K8s:node.js 应用程序与 dbs 的部署模式

K8s: deployment patterns for node.js apps with dbs

嗨!

我的问题与通过 k8s、架构模式部署 node.js 应用程序并将它们与数据库连接有关。

 alpha | beta | gamma1 | gamma2

我有以下 node.js 应用程序服务,其中一些可通过应用程序实例进行扩展(如 gamma),其他是独立的,所有这些都构建在单个 docker 图像中.Dockefile 和 运行 来自它。

我也有一个非云数据库,比如 elastic & mongo 运行 来自他们的容器 .env: mongo | elastic

至于现在,我的 docker-compose.yml 就像一个典型的 node.js 示例应用程序,但具有通用的音量和桥接网络(除了我有一个以上的 node.js 应用程序):

version: '3'
services:
  node:
    restart: always
    build: .
    ports:
      - 80:3000
    volumes:
      - ./:/code
  mongo:
    image: mongo
    ports:
      - 27017:27017
    volumes:
      - mongodb:/data/db
volumes:
 mongodb:

networks:
  test-network:
    driver: bridge

当前部署:

所有这些东西都是 运行 在单个重型 VPS 上(X CPU 内核,Y RAM,Z SSD,所有东西都加载了 70%)来自单个 docker-compose.yml 文件。

我想问的和实现的:

因为一个VPS已经不够了,我想开始使用k8s和rancher。所以问题是关于正确部署:

例如,我有 N VPSs 连接在一个私有网络中,每个 VPS 是连接在一个集群中的一个 worker,(当然,对于 Rancher,其中一个它们是一个主节点),它给我 X 个核心、Y 个 RAM 和其他共享资源。

  1. 我是否需要另一个带有数据库 运行 的独立集群(或私有网络中的 VPS 机器,但不是集群的一部分)?或者我可以在同一个集群中部署数据库?如果集群中的每个 VPS (worker) 只有 40GB 卷,而 DB 会增长超过这个卷怎么办?来自工作人员的共享资源是否包括共享卷 space?

  2. 我可以从一张图片开始我所有的应用程序是否正确,或者在 k8s 的情况下,我应该为每个服务有一个单独的 docker 图像吗?因此,如果我在一个单一存储库中有 5 个 node.js 应用程序,我应该有 5 个单独的 docker-图像,而不是一个常见的?

I'll understand that my question can have a complex answer, so I will be glad to see, not just answer but links or anything that is connected with a problem. It's much more easy to find or google for something, if you know and how to ask.

我无法回答你关于 VPS 机器设置的部分问题,但我可以就图像设置提出一些建议。

实际上,虽然您问过这个关于节点应用程序的问题,但它实际上不仅适用于节点。

关于docker图片,有共同的图片还是单独的图片;通常,由您 and/or 您的公司决定是否拥有公共图像或单独图像。

这两种方法各有利弊:

您可以将代码“嵌入”到映像中,并且每个应用程序具有不同的映像,但是如果您 运行 进入任何安全漏洞,您必须修补、重建和重新部署所有映像.如果您有 5 个应用程序都使用同一个库,但该库不在基础映像中,那么您将不得不对其进行 5 次修补,在每个映像中一次,重建映像并重新部署。

或者您可以只使用一个包含所需库的基础映像,并将代码库安装在其中(例如作为配置映射),并且该基础映像永远不需要更改,除非您必须在底层操作系统。上一段中提到的相同漏洞,只需要在基础映像中进行修补,受影响的 pods 可以重新运行(无需重新部署)。

一个纯粹的答案:

您的五个服务中的每一个都应该有自己的图像和自己的数据库。只要您有办法备份它们、运行 迁移和做其他与数据库有关的事情,数据库就可以位于同一个集群中。如果您的云提供商提供这些数据库的托管版本,那么将数据存储在集群之外也很好,并且可以帮助解决您提到的一些磁盘问题。space。

我倾向于将 Helm 用于实际的部署机制,作为在部署时注入主机名和其他设置等内容的一种方式。每个服务都有自己的 Docker 文件、自己的 Helm 图表、自己的 package.json 等等。您的 CI 系统将单独构建和部署每个服务。

一个实用的答案:

运行从同一图像中分离多个容器执行不同的工作在技术上没有任何问题。如果您现在只有一个存储库和一个构建系统,并且您不介意一项服务的更改会导致所有这些服务重新部署,那么这种方法会很好用。

无论您的存储库现在有什么构建系统,如果您采用这种方法,我会在存储库根目录中放置一个 Docker 文件,并且可能有一个 Helm 图表来部署它。在 Helm 图表部署规范中,您可以使用

之类的内容将命令覆盖到 运行
# This fragment appears under containers: in a Deployment's Pod spec
# (this is Helm chart, Go text/template templated, YAML syntax)
image: {{ .Values.repository }}/{{ .Values.image }}:{{ .Values.tag }}
command: node service3/index.js

此处 Kubernetes 的术语与 Docker 的术语略有不同,尤其是当您使用入口点包装器脚本时。 Kubernetes command: 覆盖 Docker 文件 ENTRYPOINT,Kubernetes args: 覆盖 CMD.

无论哪种情况:

Kubernetes 中的许多东西都是动态分配基础设施的。例如,您可以设置一个 horizo​​ntal pod autoscaler 来设置基于负载的 Deployment 的副本数,或者一个 cluster autoscaler 来设置如果需要,更多(云)实例到 运行 Pods。如果您有一个 持久卷供应器 那么 Kubernetes PersistentVolumeClaim 对象可以由动态分配的存储支持(例如,在 AWS 上,它创建一个 EBS 卷),并且您不会受到限制到单个节点的存储space。您通常可以找到为数据库预建的 Helm 图表;如果没有,请使用 StatefulSet 让 Kubernetes 为您创建 PVC。

确保您的 CI 系统生成带有唯一标签的图像,可能基于时间戳或源代码控制提交 ID。不要使用 ...:latest 或其他固定字符串:Kubernetes 不会在更新时重新部署,除非 image: 字符串的文本发生变化。

多个集群在很多方面都很棘手。在我的日常工作中,我们每个环境(开发、预生产、生产)都有单独的集群,但应用程序本身 运行 在单个集群中,集群之间没有通信。如果您可以管理存储,那么 运行将数据库集中在同一个集群中就可以了。

几个 Compose 选项不能很好地转换为 Kubernetes。我特别建议在执行任何特定于 Kubernetes 的操作之前,删除将代码绑定挂载到容器中并正确验证图像 运行 的 volumes:。如果您要替换图像中的整个源代码树,那么您实际上并没有 运行 宁图像,并且在本地调试会容易得多。在 Kubernetes 中,您也几乎无法控制 networks:,但在 Compose 中也不需要它们。