【问题标题】:K8s: deployment patterns for node.js apps with dbsK8s:带有 dbs 的 node.js 应用程序的部署模式
【发布时间】:2022-01-19 20:34:15
【问题描述】:

嗨!

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

 alpha | beta | gamma1 | gamma2

我有以下 node.js 应用程序服务,其中一些可以通过应用程序实例(如 gamma)进行扩展,另一些是独立的,它们都构建在带有 .Dockefile 的单个 docker 映像中并从中运行。

我也有一个非云数据库,比如 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

当前部署:

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

我想问和实现的目标:

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

例如,我在一个专用网络中连接了N VPS,每个 VPS 是一个连接在一个集群中的工作程序,(使用 Rancher,当然,其中一个是主节点)这给了我 X 个内核,Y RAM 和其他共享资源。

  1. 我是否需要另一个单独的集群(或专用网络中的 VPS 机器,但不属于集群的一部分)并在其上运行 DB?或者我可以在同一个集群中部署数据库?如果集群中的每个 VPS(worker)只有 40GB 卷,而 DB 的增长会超过这个卷呢? Worker 的共享资源是否包括共享卷空间?

  2. 拥有一个可以启动所有应用程序的映像是否正确,或者在 k8s 的情况下,我应该为每个服务拥有一个单独的 docker 映像吗?因此,如果我在一个单一存储库中有 5 个 node.js 应用程序,我应该有 5 个单独的 docker-image,而不是一个通用的?

我知道我的问题可能有一个复杂的答案,所以我很高兴看到,不仅仅是答案,还有链接或与问题相关的任何内容。如果您知道以及如何询问,则更容易找到或用 Google 搜索。

【问题讨论】:

    标签: node.js docker kubernetes deployment


    【解决方案1】:

    一个纯粹的答案:

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

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

    一个实用的答案:

    从同一个镜像上运行多个容器做不同的工作在技术上没有任何问题。如果您现在有一个存储库和一个构建系统,并且您不介意更改一项服务会导致所有这些都重新部署,那么这种方法将可以正常工作。

    无论您的存储库现在有什么构建系统,如果您采用这种方法,我会在存储库根目录中放置一个 Dockerfile,并且可能有一个 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: 覆盖 Dockerfile ENTRYPOINT,Kubernetes args: 覆盖 CMD

    无论哪种情况:

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

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

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

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

    【讨论】:

      【解决方案2】:

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

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

      关于 docker 镜像,有一个共同的镜像还是一个单独的镜像;通常,您和/或您的公司是否拥有共同的或单独的形象取决于您和/或您的公司。

      这两种方法各有利弊:

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

      或者您可以只使用包含所需库的单个基础映像,然后将代码库挂载(例如作为配置映射),并且该基础映像永远不需要更改,除非您必须在底层操作中修补某些内容系统。上面段落中提到的相同漏洞只需要在基础映像中进行修补,并且可以重新启动受影响的 pod(无需重新部署)。

      【讨论】:

      • 如果我理解正确的话,如果我为每个应用程序都有一个单独的 docker 映像,我在重新运行单独的应用程序时会有更大的灵活性? (而不是重新部署整个集群,因为重建了统一的单个 docker-image。)
      • 如果每个应用都有单独的 docker 镜像,那么每个应用都可以独立发展,是的。但是,您必须平衡这一点,因为可能需要在所有映像上完成操作系统级别或共享库级别的任何修补。所以这是你需要考虑和思考的平衡。
      • 在 Kubernetes 中绑定挂载代码库非常困难;我见过的尝试过的示例通过添加它使 YAML 文件的大小大致翻了一番,而且很难更新。我不会推荐这种方法。
      猜你喜欢
      • 1970-01-01
      • 2019-06-20
      • 2016-05-22
      • 2012-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-15
      • 1970-01-01
      相关资源
      最近更新 更多