{
"title": "使用 Helm 在 Kubernetes 上扩展 Node.js 应用",
"content": "使用 Helm 在 Kubernetes 上扩展 Node.js 应用\n\n引言\nKubernetes 是一个用于大规模运行现代化容器化应用程序的系统。借助它,开发者可以在机器集群上部署和管理应用。尽管 Kubernetes 可以用于提升单实例应用设置的效率和可靠性,但其设计初衷是在多组机器上运行应用的多个实例。\n\n在使用 Kubernetes 创建多服务部署时,许多开发者选择使用 Helm 包管理器。Helm 通过提供协调这些对象交互的图表和模板,简化了创建多个 Kubernetes 资源的过程。它还为主流的开源项目提供了预打包的图表。\n\n在本教程中,您将使用 Helm 图表将一个 Node.js 应用与 MongoDB 数据库部署到 Kubernetes 集群上。您将使用官方的 Helm MongoDB 副本集图表来创建一个由三个 Pod、一个 Headless Service 和三个 PersistentVolumeClaim 组成的 StatefulSet 对象。您还将创建一个图表,使用自定义的应用镜像来部署一个多副本的 Node.js 应用。\n\n如果您是初次连接 Node.js 和 MongoDB,《如何将 MongoDB 与您的 Node 应用集成》涵盖了基础知识;《从容器到 Kubernetes 与 Node.js》电子书扩展了此工作流。\n\n您将在本教程中构建的设置将镜像《使用 Docker Compose 容器化 Node.js 应用》中描述的代码功能,并将成为构建一个具有 MongoDB 数据存储、可根据需求扩展的弹性 Node.js 应用的绝佳起点。\n\n关键要点\n\n- 您将使用 Helm 图表在 Kubernetes 集群上部署 Node.js 应用和 MongoDB 数据库,以实现声明式、可重复的配置。\n
- MongoDB 将作为一个由三个 Pod(StatefulSet)组成的副本集运行,具有持久存储和一个用于稳定网络身份的无头服务。\n
- Node.js 应用将作为多副本 Deployment 运行,数据库连接详情通过 ConfigMaps 和 Secrets 提供的环境变量传递。\n
- 扩展分为无状态应用副本(由 Kubernetes Deployments 处理)和有状态的 MongoDB(由副本集和 Helm 图表值处理)。\n
- 此模式是生产就绪设置的基础;要自动扩展应用层,您可以在完成本教程后添加 Horizontal Pod Autoscaler。\n
- 在生产环境中增加副本数量之前,可观测性、资源请求和安全的 MongoDB 扩展实践至关重要。\n
\n\n架构概述\n本教程采用 Helm 优先的方法来定义一个可重复、声明式的堆栈,将无状态应用扩展与有状态数据库扩展分离。核心组件包括:\n\n- Node.js Deployment:应用的多个副本,用于水平扩展和高可用性。\n
- MongoDB StatefulSet:三个副本集成员,带有持久卷用于持久存储。\n
- ConfigMap 和 Secret:连接设置(主机名、端口、副本集名称)和凭据。\n
- Services:一个用于 MongoDB Pod DNS 解析的无头服务,以及一个用于 Node.js 应用的 LoadBalancer 服务。\n
\n数据流如下:外部流量到达 Node.js Service,应用从环境变量读取 MongoDB 连接设置,驱动程序通过 DNS 连接到 MongoDB 副本集成员。这种分离是 Kubernetes 扩展 Node.js 应用同时保持 MongoDB 在 Kubernetes 上可靠的基础。\n\n先决条件\n要完成本教程,您需要:\n\n\n第 1 步 — 克隆并打包应用\n为了在 Kubernetes 中使用我们的应用,我们需要将其打包,以便 kubelet 代理可以拉取镜像。然而,在打包应用之前,我们需要修改应用代码中的 MongoDB 连接 URI,以确保我们的应用能够连接到我们将使用 Helm mongodb-replicaset 图表创建的副本集成员。\n\n我们的第一步是从 DigitalOcean Community GitHub 账户克隆 node-mongo-docker-dev 仓库。此仓库包含《使用 Docker Compose 为开发容器化 Node.js 应用》中描述的设置代码,该设置使用一个带有 MongoDB 数据库的演示 Node.js 应用来展示如何使用 Docker Compose 设置开发环境。您可以在《从容器到 Kubernetes 与 Node.js》系列中找到关于应用本身的更多信息。\n\n将仓库克隆到名为 node_project 的目录中:\n- git clone https://github.com/do-community/node-mongo-docker-dev.git node_project
复制代码 \n\n导航到 node_project 目录:\n\n\nnode_project 目录包含一个与用户输入交互的鲨鱼信息应用的文件和目录。它已现代化以适用于容器:敏感和特定的配置信息已从应用代码中移除,并重构为在运行时注入,应用的状态已卸载到 MongoDB 数据库。\n\n有关设计现代化容器化应用的更多信息,请参阅《为 Kubernetes 架构应用》和《为 Kubernetes 现代化应用》。\n\n当我们部署 Helm mongodb-replicaset 图表时,它将创建:\n\n- 一个包含三个 Pod 的 StatefulSet 对象:MongoDB 副本集的成员。每个 Pod 将有一个关联的 PersistentVolumeClaim,并在重新调度时保持固定的身份。\n
- 一个由 StatefulSet 中的 Pod 组成的 MongoDB 副本集。该集合将包括一个主节点和两个从节点。数据将从主节点复制到从节点,确保我们的应用数据保持高可用性。\n
\n\n为了让我们的应用与数据库副本交互,我们代码中的 MongoDB 连接 URI 需要包含副本集成员的主机名以及副本集本身的名称。因此,我们需要在 URI 中包含这些值。\n\n我们克隆的仓库中指定数据库连接信息的文件名为 db.js。现在使用 nano 或您喜欢的编辑器打开该文件:\n\n\n目前,该文件包含在运行时在数据库连接 URI 中引用的常量。这些常量的值使用 Node 的 process.env 属性注入,该属性在运行时返回一个包含用户环境信息的对象。在我们的应用代码中动态设置值允许我们将代码与底层基础设施解耦,这在动态、无状态的环境中至关重要。有关以这种方式重构应用代码的更多信息,请参阅《使用 Docker Compose 为开发容器化 Node.js 应用》的第 2 步以及《12-Factor App》中的相关讨论。\n\n连接 URI 的常量和 URI 字符串本身目前如下所示:\n- ~/node_project/db.js\n...\nconst { MONGO_USERNAME, MONGO_PASSWORD, MONGO_HOSTNAME, MONGO_PORT, MONGO_DB } = process.env;\n...\nconst url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;\n...
复制代码 \n\n遵循 12FA 方法,我们不希望将副本实例的主机名或副本集名称硬编码到此 URI 字符串中。现有的 MONGO_HOSTNAME 常量可以扩展以包含多个主机名(我们的副本集成员),因此我们将保留它。但是,我们需要在 URI 字符串的选项部分添加一个副本集常量。\n\n将 MONGO_REPLICASET 添加到 URI 常量对象和连接字符串中:\n- ~/node_project/db.js\n...\nconst { MONGO_USERNAME, MONGO_PASSWORD, MONGO_HOSTNAME, MONGO_PORT, MONGO_DB, MONGO_REPLICASET } = process.env;\n...\nconst url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?replicaSet=${MONGO_REPLICASET}&authSource=admin`;\n...
复制代码 \n\n在 URI 的选项部分使用 replicaSet 选项允许我们传入副本集的名称,这与 MONGO_HOSTNAME 常量中定义的主机名一起,将允许我们连接到集合成员。\n\n编辑完成后保存并关闭文件。\n\n修改了数据库连接信息以适用于副本集后,您现在可以打包您的应用,使用 docker build 命令构建镜像,并将其推送到 Docker Hub。\n\n使用 docker build 和 -t 标志构建镜像,该标志允许您用易记的名称标记镜像。在本例中,用您的 Docker Hub 用户名标记镜像,并将其命名为 node-replicas 或您选择的名称:\n- docker build -t your_dockerhub_username/node-replicas .
复制代码 \n\n命令中的 . 指定构建上下文为当前目录。构建镜像需要一两分钟。完成后,检查您的镜像:\n\n\n您将看到以下输出:\n- Output\nREPOSITORY TAG IMAGE ID CREATED SIZE\nyour_dockerhub_username/node-replicas latest 56a69b4bc882 7 seconds ago 90.1MB\nnode 10-alpine aa57b0242b33 6 days ago 71MB
复制代码 \n\n接下来,登录到您在先决条件中创建的 Docker Hub 账户:\n- docker login -u your_dockerhub_username
复制代码 \n\n出现提示时,输入您的 Docker Hub 账户密码。以这种方式登录将在您的非 root 用户的主目录中创建一个包含您的 Docker Hub 凭据的 ~/.docker/config.json 文件。\n\n使用 docker push 命令将应用镜像推送到 Docker Hub。请记住将 your_dockerhub_username 替换为您自己的 Docker Hub 用户名:\n- docker push your_dockerhub_username/node-replicas
复制代码 \n\n您现在拥有一个可以拉取以在 Kubernetes 上运行复制应用的应用镜像。下一步将是配置与 MongoDB Helm 图表一起使用的特定参数。\n\n第 2 步 — 为 MongoDB 副本集创建 Secrets\nstable/mongodb-replicaset 图表在使用 Secrets 方面提供了不同的选项,我们将创建两个用于我们的图表部署:\n\n- 一个用于我们的副本集密钥文件的 Secret,它将作为副本集成员之间的共享密码,允许它们相互认证。\n
- 一个用于我们的 MongoDB 管理员用户的 Secret,该用户将在 admin 数据库上创建为 root 用户。此角色将允许您在将应用部署到生产环境时创建具有有限权限的后续用户。\n
\n\n有了这些 Secrets,我们将能够在专用的值文件中设置我们首选的参数值,并使用 Helm 图表创建 StatefulSet 对象和 MongoDB 副本集。\n\n首先,让我们创建密钥文件。我们将使用 openssl 命令和 rand 选项生成一个 756 字节的随机字符串作为密钥文件:\n- openssl rand -base64 756 > key.txt
复制代码 \n\n该命令生成的输出将进行 base64 编码,确保数据传输的一致性,并重定向到名为 key.txt 的文件,遵循 mongodb-replicaset 图表认证文档中所述的指南。密钥本身必须介于 6 到 1024 个字符之间,仅由 base64 集中的字符组成。\n\n现在,您可以使用此文件通过 kubectl create 创建一个名为 keyfilesecret 的 Secret:\n- kubectl create secret generic keyfilesecret --from-file=key.txt
复制代码 \n\n这将在默认命名空间中创建一个 Secret 对象,因为我们没有为我们的设置创建特定的命名空间。您将看到以下输出,表明您的 Secret 已创建:\n- Output\nsecret/keyfilesecret created
复制代码 \n\n删除 key.txt:\n\n\n或者,如果您想保存该文件,请确保限制其权限并将其添加到您的 .gitignore 文件中,以使其远离版本控制。\n\n接下来,为您的 MongoDB 管理员用户创建 Secret。第一步是将您所需的用户名和密码转换为 base64。\n\n转换您的数据库用户名:\n- echo -n 'your_database_username' | base64
复制代码 \n\n记下您在输出中看到的值。\n\n接下来,转换您的密码:\n- echo -n 'your_database_password' | base64
复制代码 \n\n同样记下此处的输出值。\n\n打开一个文件用于 Secret:\n\n\n注意:Kubernetes 对象通常使用 YAML 定义,YAML 严格禁止使用制表符,并要求使用两个空格进行缩进。如果您想检查任何 YAML 文件的格式,可以使用 linter 或使用 kubectl create 和 --dry-run 及 --validate 标志测试语法的有效性:\n- kubectl create -f your_yaml_file.yaml --dry-run --validate=true
复制代码 \n\n通常,在使用 kubectl 创建资源之前验证语法是一个好主意。\n\n将以下代码添加到文件中,以创建一个 Secret,该 Secret 将使用您刚刚创建的编码值定义用户和密码。请务必将此处的虚拟值替换为您自己的编码用户名和密码:\n- ~/node_project/secret.yaml\napiVersion: v1\nkind: Secret\nmetadata:\n name: mongo-secret\ndata:\n user: your_encoded_username\n password: your_encoded_password
复制代码 \n\n在这里,我们使用了 mongodb-replicaset 图表期望的键名:user 和 password。我们将 Secret 对象命名为 mongo-secret,但您可以自由命名。\n\n编辑完成后保存并关闭文件。\n\n使用以下命令创建 Secret 对象:\n- kubectl create -f secret.yaml
复制代码 \n\n您将看到以下输出:\n- Output\nsecret/mongo-secret created
复制代码 \n\n同样,您可以删除 secret.yaml 或限制其权限并将其添加到您的 .gitignore 文件中。\n\n创建了 Secret 对象后,您可以继续指定将与 mongodb-replicaset 图表一起使用的参数值并创建 MongoDB 部署。\n\n第 3 步 — 配置 MongoDB Helm 图表并创建部署\n注意:stable Helm 仓库已于 2022 年归档,stable/mongodb-replicaset 图表不再维护。以下步骤仍适用于学习目的。对于新部署,请考虑使用支持副本集的 Bitnami MongoDB 图表。\n\nHelm 带有一个名为 stable 的活跃维护仓库,其中包含我们将使用的图表:mongodb-replicaset。为了将此图表与我们刚刚创建的 Secrets 一起使用,我们将创建一个名为 mongodb-values.yaml 的配置文件,其中包含配置参数值,然后使用此文件安装图表。\n\n我们的 mongodb-values.yaml 文件将很大程度上镜像 mongodb-replicaset 图表仓库中的默认 values.yaml 文件。但是,我们将对文件进行以下更改:\n\n- 我们将把 auth 参数设置为 true,以确保我们的数据库实例在启用授权的情况下启动。这意味着所有客户端都需要进行身份验证才能访问数据库资源和操作。\n
- 我们将添加有关我们在上一步中创建的 Secrets 的信息,以便图表可以使用这些值来创建副本集密钥文件和管理员用户。\n
- 我们将减小与 StatefulSet 中每个 Pod 关联的 PersistentVolumes 的大小,以使用最小的可行 DigitalOcean Block Storage 单元 1GB,但您可以自由修改以满足您的存储需求。\n
\n\n然而,在编写 mongodb-values.yaml 文件之前,您应该首先检查是否已创建并配置了 StorageClass 以提供存储资源。您的数据库 StatefulSet 中的每个 Pod 都将具有粘性身份和关联的 PersistentVolumeClaim,这将为 Pod 动态提供 PersistentVolume。如果 Pod 被重新调度,PersistentVolume 将被挂载到 Pod 被调度到的任何节点(尽管如果其关联的 Pod 或 StatefulSet 被永久删除,每个卷必须手动删除)。\n\n因为我们使用的是 DigitalOcean Kubernetes,所以我们的默认 StorageClass 提供程序设置为 dobs.csi.digitalocean.com(DigitalOcean Block Storage),我们可以通过输入以下内容来检查:\n\n\n如果您使用的是 DigitalOcean 集群,您将看到以下输出:\n- Output\nNAME PROVISIONER AGE\ndo-block-storage (default) dobs.csi.digitalocean.com 21m
复制代码 \n\n如果您使用的不是 DigitalOcean 集群,您需要创建一个 StorageClass 并配置您选择的提供程序。有关如何执行此操作的详细信息,请参阅官方文档。\n\n现在您已确保配置了 StorageClass,请打开 mongodb-values.yaml 进行编辑:\n\n\n您将在此文件中设置值,这些值将执行以下操作:\n\n- 启用授权。\n
- 引用您的 keyfilesecret 和 mongo-secret 对象。\n
- 为您的 PersistentVolumes 指定 1Gi。\n
- 将您的副本集名称设置为 db。\n
- 为集合指定 3 个副本。\n
- 将 mongo 镜像固定到撰写时的最新版本:4.1.9。\n
\n\n将以下代码粘贴到文件中:\n- ~/node_project/mongodb-values.yaml\nreplicas: 3\nport: 27017\nreplicaSetName: db\npodDisruptionBudget: {}\nauth:\n enabled: true\n existingKeySecret: keyfilesecret\n existingAdminSecret: mongo-secret\nimagePullSecrets: []\ninstallImage:\n repository: unguiculus/mongodb-install\n tag: 0.7\n pullPolicy: Always\ncopyConfigImage:\n repository: busybox\n tag: 1.29.3\n pullPolicy: Always\nimage:\n repository: mongo\n tag: 4.1.9\n pullPolicy: Always\nextraVars: {}\nmetrics:\n enabled: false\n image:\n repository: ssalaues/mongodb-exporter\n tag: 0.6.1\n pullPolicy: IfNotPresent\n port: 9216\n path: /metrics\n socketTimeout: 3s\n syncTimeout: 1m\n prometheusServiceDiscovery: true\nresources: {}\npodAnnotations: {}\nsecurityContext:\n enabled: true\n runAsUser: 999\n fsGroup: 999\n runAsNonRoot: true\ninit:\n resources: {}\n timeout: 900\nresources: {}\nnodeSelector: {}\naffinity: {}\ntolerations: []\nextraLabels: {}\npersistentVolume:\n enabled: true\n #storageClass: "-"\n accessModes:\n - ReadWriteOnce\n size: 1Gi\n annotations: {}\nserviceAnnotations: {}\nterminationGracePeriodSeconds: 30\ntls:\n enabled: false\nconfigmap: {}\nreadinessProbe:\n initialDelaySeconds: 5\n timeoutSeconds: 1\n failureThreshold: 3\n periodSeconds: 10\n successThreshold: 1\nlivenessProbe:\n initialDelaySeconds: 30\n timeoutSeconds: 5\n failureThreshold: 3\n periodSeconds: 10\n successThreshold: 1
复制代码 \n\npersistentVolume.storageClass 参数在此处被注释掉:移除注释并将其值设置为 \"-\" 将禁用动态提供。在我们的例子中,由于我们未定义此值,图表将选择默认提供程序(在我们的例子中为 dobs.csi.digitalocean.com)。\n\n另请注意与 persistentVolume 键关联的 accessMode:ReadWriteOnce 意味着提供的卷只能由单个节点读写。有关不同访问模式的更多信息,请参阅文档。\n\n要了解文件中包含的其他参数,请参阅仓库中的配置表。\n\n编辑完成后保存并关闭文件。\n\n在部署 mongodb-replicaset 图表之前,您需要使用 helm repo update 命令更新 stable 仓库:\n\n\n这将从 stable 仓库获取最新的图表信息。\n\n最后,使用以下命令安装图表:\n- helm install --name mongo -f mongodb-values.yaml stable/mongodb-replicaset
复制代码 \n\n注意:在安装图表之前,您可以使用 --dry-run 和 --debug 选项运行 helm install 来检查生成的发布清单:\n- helm install --name your_release_name -f your_values_file.yaml --dry-run --debug your_chart
复制代码 \n\n请注意,我们将 Helm 发布命名为 mongo。此名称将指代我们使用指定配置选项的图表的此特定部署。我们通过包含 -f 标志和我们的 mongodb-values.yaml 文件来指向这些选项。\n\n另请注意,由于我们在 helm install 中未包含 --namespace 标志,我们的图表对象将在默认命名空间中创建。\n\n创建发布后,您将看到有关其状态的输出,以及有关创建的对象和与之交互的说明:\n- Output\nNAME: mongo\nLAST DEPLOYED: Tue Apr 16 21:51:05 2019\nNAMESPACE: default\nSTATUS: DEPLOYED\n\nRESOURCES:\n==> v1/ConfigMap\nNAME DATA AGE\nmongo-mongodb-replicaset-init 1 1s\nmongo-mongodb-replicaset-mongodb 1 1s\nmongo-mongodb-replicaset-tests 1 0s\n...
复制代码 \n\n您现在可以使用以下命令检查 Pod 的创建情况:\n\n\n您将看到类似以下的输出,因为 Pod 正在创建中:\n- Output\nNAME READY STATUS RESTARTS AGE\nmongo-mongodb-replicaset-0 1/1 Running 0 67s\nmongo-mongodb-replicaset-1 0/1 Init:0/3 0 8s
复制代码 \n\n此处的 READY 和 STATUS 输出表明我们 StatefulSet 中的 Pod 尚未完全就绪:与 Pod 容器关联的 Init 容器仍在运行。由于 StatefulSet 成员是按顺序创建的,因此 StatefulSet 中的每个 Pod 必须处于 Running 和 Ready 状态,然后才会创建下一个 Pod。\n\n一旦 Pod 被创建并且所有关联的容器都在运行,您将看到此输出:\n- Output\nNAME READY STATUS RESTARTS AGE\nmongo-mongodb-replicaset-0 1/1 Running 0 2m33s\nmongo-mongodb-replicaset-1 1/1 Running 0 94s\nmongo-mongodb-replicaset-2 1/1 Running 0 36s
复制代码 \n\nRunning STATUS 表示您的 Pod 已绑定到节点,并且与这些 Pod 关联的容器正在运行。READY 表示 Pod 中有多少个容器正在运行。有关更多信息,请参阅Pod 生命周期文档。\n\n注意:如果您在 STATUS 列中看到意外的阶段,请记住您可以使用以下命令对 Pod 进行故障排除:\n- kubectl describe pods your_pod\nkubectl logs your_pod
复制代码 \n\n您的 StatefulSet 中的每个 Pod 都有一个名称,该名称结合了 StatefulSet 的名称和 Pod 的序号索引。因为我们创建了三个副本,所以我们的 StatefulSet 成员编号为 0-2,每个成员都有一个稳定的 DNS 条目,由以下元素组成:$(statefulset-name)-$(ordinal).$(service name).$(namespace).svc.cluster.local。\n\n在我们的例子中,由 mongodb-replicaset 图表创建的 StatefulSet 和 Headless Service 具有相同的名称:\n- kubectl get statefulset\nOutput\nNAME READY AGE\nmongo-mongodb-replicaset 3/3 4m2s
复制代码 \n\n- kubectl get svc\nOutput\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\nkubernetes ClusterIP 10.245.0.1 <none> 443/TCP 42m\nmongo-mongodb-replicaset ClusterIP None <none> 27017/TCP 4m35s\nmongo-mongodb-replicaset-client ClusterIP None <none> 27017/TCP 4m35s
复制代码 \n\n这意味着我们 StatefulSet 的第一个成员将具有以下 DNS 条目:\nmongo-mongodb-replicaset-0.mongo-mongodb-replicaset.default.svc.cluster.local\n\n因为我们的应用需要连接到每个 MongoDB 实例,所以拥有此信息至关重要,这样我们就可以直接与 Pod 通信,而不是与服务通信。当我们创建自定义应用 Helm 图表时,我们将使用环境变量将每个 Pod 的 DNS 条目传递给我们的应用。\n\n您的数据库实例启动并运行后,您就可以为您的 Node 应用创建图表了。\n\n安全扩展 MongoDB\n在 Kubernetes 上扩展 MongoDB 与扩展无状态应用不同。在更改副本数量之前,请查看以下安全措施:\n\n- 副本集健康状态:在添加或删除成员之前,确认所有成员都是 PRIMARY 或 SECONDARY 并且完全同步。\n
- 存储大小调整:PersistentVolumeClaims 必须为增长而调整大小。不支持以后减小大小。\n
- 写入关注:在生产环境中,使用多数写入关注以确保跨副本的持久性。\n
- Pod 中断:保持 PodDisruptionBudget,以便日常维护不会一次驱逐太多 MongoDB Pod。\n
- 连接字符串准确性:每当副本集名称或成员更改时,更新 MONGO_HOSTNAME 和 MONGO_REPLICASET。\n
\n这可以保持 MongoDB StatefulSets 的稳定,并避免在扩展事件期间出现脑裂或数据丢失。\n\n第 4 步 — 创建自定义应用图表并配置参数\n我们将为我们的 Node 应用创建一个自定义 Helm 图表,并修改标准图表目录中的默认文件,以便我们的应用可以与刚刚创建的副本集一起工作。我们还将创建文件来为我们的应用定义 ConfigMap 和 Secret 对象。\n\n首先,使用以下命令创建一个名为 nodeapp 的新图表目录:\n\n\n这将在您的 ~/node_project 文件夹中创建一个名为 nodeapp 的目录,其中包含以下资源:\n\n- 一个 Chart.yaml 文件,包含有关您的图表的基本信息。\n
- 一个 values.yaml 文件,允许您设置特定的参数值,就像您对 MongoDB 部署所做的那样。\n
- 一个 .helmignore 文件,包含在打包图表时将忽略的文件和目录模式。\n
- 一个 templates/ 目录,包含将生成 Kubernetes 清单的模板文件。\n
- 一个 templates/tests/ 目录用于测试文件。\n
- 一个 charts/ 目录用于此图表依赖的任何图表。\n
\n\n我们将修改的这些默认文件中的第一个是 values.yaml。现在打开该文件:\n\n\n我们将在此处设置的值包括:\n\n- 副本数量。\n
- 我们想要使用的应用镜像。在我们的例子中,这将是我们在第 1 步中创建的 node-replicas 镜像。\n
- ServiceType。在本例中,我们将指定 LoadBalancer 以为我们的应用创建一个测试访问点。因为我们使用的是 DigitalOcean Kubernetes 集群,所以在部署图表时,这将创建一个 DigitalOcean Load Balancer。在生产环境中,您可以配置图表以使用 Ingress Resources 和 Ingress Controllers 将流量路由到您的服务。\n
- targetPort 以指定 Pod 上暴露我们应用的端口。\n
\n\n我们不会将环境变量输入到此文件中。相反,我们将为 ConfigMap 和 Secret 对象创建模板,并将这些值添加到我们的应用 Deployment 清单中,该清单位于 ~/node_project/nodeapp/templates/deployment.yaml。\n\n在 values.yaml 文件中配置以下值:\n- ~/node_project/nodeapp/values.yaml\n# Default values for nodeapp.\n# This is a YAML-formatted file.\n# Declare variables to be passed into your templates.\n\nreplicaCount: 3\n\nimage:\n repository: your_dockerhub_username/node-replicas\n tag: latest\n pullPolicy: IfNotPresent\n\nnameOverride: ""\nfullnameOverride: ""\n\nservice:\n type: LoadBalancer\n port: 80\n targetPort: 8080\n...
复制代码 \n\n编辑完成后保存并关闭文件。\n\n接下来,在 nodeapp/templates 目录中打开一个 secret.yaml 文件:\n- nano nodeapp/templates/secret.yaml
复制代码 \n\n在此文件中,为您的 MONGO_USERNAME 和 MONGO_PASSWORD 应用常量添加值。这些是您的应用在运行时期望访问的常量,如您的数据库连接文件 db.js 中所指定。在添加这些常量的值时,请记住使用您在第 2 步中创建 mongo-secret 对象时使用的 base64 编码值。如果您需要重新创建这些值,可以返回第 2 步并再次运行相关命令。\n\n将以下代码添加到文件中:\n- ~/node_project/nodeapp/templates/secret.yaml\napiVersion: v1\nkind: Secret\nmetadata:\n name: {{ .Release.Name }}-auth\ndata:\n MONGO_USERNAME: your_encoded_username\n MONGO_PASSWORD: your_encoded_password
复制代码 \n\n此 Secret 对象的名称将取决于您的 Helm 发布的名称,您将在部署应用图表时指定该名称。\n\n编辑完成后保存并关闭文件。\n\n接下来,打开一个文件为您的应用创建 ConfigMap:\n- nano nodeapp/templates/configmap.yaml
复制代码 \n\n在此文件中,我们将定义我们的应用期望的其余变量:MONGO_HOSTNAME、MONGO_PORT、MONGO_DB 和 MONGO_REPLICASET。我们的 MONGO_HOSTNAME 变量将包括我们副本集中每个实例的 DNS 条目,因为这是 MongoDB 连接 URI 所要求的。根据 Kubernetes 文档,当应用实现活跃度和就绪度检查时,连接到 Pod 时应使用 SRV 记录。\n\n如第 3 步所述,我们的 Pod SRV 记录遵循以下模式:$(statefulset-name)-$(ordinal).$(service name).$(namespace).svc.cluster.local。由于我们的 MongoDB StatefulSet 实现了活跃度和就绪度检查,因此在定义 MONGO_HOSTNAME 变量的值时应使用这些稳定的标识符。\n\n将以下代码添加到文件中以定义 MONGO_HOSTNAME、MONGO_PORT、MONGO_DB 和 MONGO_REPLICASET 变量。您可以自由地为您的 MONGO_DB 数据库使用另一个名称,但您的 MONGO_HOSTNAME 和 MONGO_REPLICASET 值必须按此处所示编写:\n- ~/node_project/nodeapp/templates/configmap.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n name: {{ .Release.Name }}-config\ndata:\n MONGO_HOSTNAME: "mongo-mongodb-replicaset-0.mongo-mongodb-replicaset.default.svc.cluster.local,mongo-mongodb-replicaset-1.mongo-mongodb-replicaset.default.svc.cluster.local,mongo-mongodb-replicaset-2.mongo-mongodb-replicaset.default.svc.cluster.local"\n MONGO_PORT: "27017"\n MONGO_DB: "sharkinfo"\n MONGO_REPLICASET: "db"
复制代码 \n\n因为我们已经创建了 StatefulSet 对象和副本集,所以此处列出的主机名必须完全按照此示例中的样子列在您的文件中。如果您销毁这些对象并重命名您的 MongoDB Helm 发布,那么您将需要修改此 ConfigMap 中包含的值。MONGO_REPLICASET 也是如此,因为我们使用 MongoDB 发布指定了副本集名称。\n\n另请注意,此处列出的值被引用,这是 Helm 中环境变量的期望。\n\n编辑完成后保存并关闭文件。\
原文链接:Scale Node.js Apps on Kubernetes with Helm |