PAYATHON 2026

如何使用 Helm 将多个微服务部署到 AKS 的不同环境?

支付老李

结论

只用 Helm 可以完成多个微服务在 AKS 的 dev、QA 环境中的部署。不过,Helm 主要负责 Kubernetes 应用的模板化、安装、升级和回滚,不适合承担完整的跨集群编排工作。

实际项目中通常会组合使用以下工具:

  • Helm:定义和发布 payment、order 等微服务。
  • CI/CD 或 GitOps:选择目标集群、环境配置和镜像版本,并按顺序执行 Helm。
  • Terraform/Bicep:创建 AKS、网络、身份和其他 Azure 基础设施。
  • Ansible:用于操作系统配置、非 Kubernetes 资源处理或复杂的过程编排。没有这些需求时不必引入。

dev 和 QA 也不一定要使用独立的 AKS 集群。团队较小、隔离要求不高时,可以在同一集群中划分不同的 namespace;如果需要更严格的权限、网络、容量或故障隔离,则应使用独立集群。

推荐的整体结构

每个微服务维护自己的 Chart,各环境只保存差异配置:

deploy/
├── charts/
│   ├── payment/
│   │   ├── Chart.yaml
│   │   ├── values.yaml
│   │   └── templates/
│   └── order/
│       ├── Chart.yaml
│       ├── values.yaml
│       └── templates/
└── environments/
    ├── dev/
    │   ├── payment.yaml
    │   └── order.yaml
    └── qa/
        ├── payment.yaml
        └── order.yaml

各部分的职责如下:

  • charts/payment/values.yaml:保存 payment 服务的安全默认值。
  • environments/dev/payment.yaml:保存 payment 在 dev 环境中的差异。
  • environments/qa/payment.yaml:保存 payment 在 QA 环境中的差异。
  • 集群、namespace 和镜像版本:由部署流水线显式传入。

不要复制出 payment-dev、payment-qa 等多套 Chart。模板一旦分叉,后续的修复和升级很容易出现不一致。

为每个服务创建独立 Chart

以 payment 为例。

Chart.yaml:

apiVersion: v2
name: payment
description: Payment microservice
type: application
version: 0.1.0
appVersion: "1.0.0"

默认的 values.yaml:

replicaCount: 1

image:
  repository: myregistry.azurecr.io/payment
  tag: ""
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 8080

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 500m
    memory: 512Mi

config:
  logLevel: info

Deployment 模板中的镜像可以这样设置:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "payment.fullname" . }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ include "payment.name" . }}
      app.kubernetes.io/instance: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ include "payment.name" . }}
        app.kubernetes.io/instance: {{ .Release.Name }}
    spec:
      containers:
        - name: payment
          image: "{{ .Values.image.repository }}:{{ required "image.tag is required" .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: {{ .Values.service.port }}
          env:
            - name: LOG_LEVEL
              value: {{ .Values.config.logLevel | quote }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}

order 服务可以采用相同的结构,但要维护自己的模板和默认配置。如果多个服务确实共享大量稳定、重复的模板,可以进一步抽取 Helm library chart。仅为了减少少量重复就增加抽象层,通常得不偿失。

为不同环境提供覆盖值

dev 环境的 payment 配置:

replicaCount: 1

config:
  logLevel: debug

resources:
  requests:
    cpu: 50m
    memory: 64Mi
  limits:
    cpu: 250m
    memory: 256Mi

QA 环境的 payment 配置:

replicaCount: 2

config:
  logLevel: info

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 500m
    memory: 512Mi

镜像 tag 最好由流水线传入,不要长期写死在环境文件中:

helm upgrade --install payment ./charts/payment \
  --namespace dev \
  --create-namespace \
  -f ./environments/dev/payment.yaml \
  --set-string image.tag="${IMAGE_TAG}" \
  --wait \
  --atomic \
  --timeout 10m

--set-string 可以防止 1.0、Git SHA 等值因 YAML 类型推断而被意外转换。生产部署也应避免使用 latest,改用不可变的版本号或镜像 digest。

选择目标 AKS 集群

Helm 不会根据 “cluster name” 自动寻找 AKS。它依赖 kubeconfig 中的当前 context,也可以通过 --kube-context 显式选择 context。

先获取集群凭据:

az aks get-credentials \
  --resource-group rg-platform-dev \
  --name aks-dev

然后部署:

helm upgrade --install payment ./charts/payment \
  --kube-context aks-dev \
  --namespace payment-dev \
  --create-namespace \
  -f ./environments/dev/payment.yaml \
  --set-string image.tag="${IMAGE_TAG}" \
  --wait \
  --atomic

kubeconfig 中的 context 名称不一定始终等于 AKS cluster name。自动化脚本应先确认实际的 context,或者在获取凭据时明确设置 context 名称,以免误部署到当前默认集群。

如果 dev 和 QA 共用一个 AKS,可以分别创建 namespace:

kubectl create namespace dev
kubectl create namespace qa

部署时指定对应的 namespace:

helm upgrade --install payment ./charts/payment \
  --namespace dev \
  -f ./environments/dev/payment.yaml \
  --set-string image.tag="${IMAGE_TAG}"
helm upgrade --install payment ./charts/payment \
  --namespace qa \
  -f ./environments/qa/payment.yaml \
  --set-string image.tag="${IMAGE_TAG}"

Helm release 由 release name 和 namespace 共同标识。因此,同一个 Chart 部署到不同 namespace 时,都可以使用 payment 作为 release name。

一次部署多个微服务

Helm 原生命令通常一次只管理一个 release。最直接的做法是在 CI/CD 中分别部署:

helm upgrade --install payment ./charts/payment \
  --namespace dev \
  --create-namespace \
  -f ./environments/dev/payment.yaml \
  --set-string image.tag="${PAYMENT_IMAGE_TAG}" \
  --wait \
  --atomic

helm upgrade --install order ./charts/order \
  --namespace dev \
  --create-namespace \
  -f ./environments/dev/order.yaml \
  --set-string image.tag="${ORDER_IMAGE_TAG}" \
  --wait \
  --atomic

相比把所有服务塞进一个巨型 Chart,这种方式更便于独立升级、回滚和控制发布节奏。

如果这些服务必须作为一个整体发布,也可以创建 umbrella chart,将各微服务声明为 dependencies:

apiVersion: v2
name: commerce-platform
type: application
version: 0.1.0

dependencies:
  - name: payment
    version: 0.1.0
    repository: "file://../payment"
  - name: order
    version: 0.1.0
    repository: "file://../order"

然后更新依赖并部署:

helm dependency update ./charts/commerce-platform

helm upgrade --install commerce ./charts/commerce-platform \
  --namespace dev \
  --create-namespace \
  -f ./environments/dev/platform.yaml \
  --wait \
  --atomic

umbrella chart 会让服务的生命周期产生耦合。只要 payment 和 order 需要独立发布,使用独立 release 通常更合适。

服务数量较多时,可以用流水线矩阵、GitOps 控制器或 Helmfile 等声明式工具统一调用多个 Helm release。这些工具负责 orchestration,Helm 继续管理各个 release。

是否需要 Ansible

如果只是根据环境选择 values 文件并执行 helm upgrade --install,一般不必增加 Ansible。CI/CD 流水线就可以完成这些步骤:

  1. 登录 Azure。
  2. 获取目标 AKS 凭据。
  3. 选择并验证 kube context。
  4. 创建 namespace。
  5. 运行 lint 和模板检查。
  6. 部署多个 Helm release。
  7. 等待 rollout 并执行冒烟测试。

以下情况更适合使用 Ansible:

  • 需要同时配置虚拟机、操作系统或中间件。
  • 部署流程包含大量非 Kubernetes 操作。
  • 团队已有成熟的 Ansible 资产、角色和运维规范。
  • 需要跨多个异构系统执行有状态的步骤。

如果大部分资源都在 Kubernetes 和 Azure 中,使用 Terraform/Bicep 加 CI/CD 或 GitOps,通常比 Helm 加 Ansible 更清晰。

dev 和 QA 是否应拆分集群

是否拆分取决于隔离需求,与 Helm 本身无关。

共用集群并划分 namespace 的成本较低,管理也更简单,但至少应配置:

  • namespace 级 RBAC。
  • ResourceQuota 和 LimitRange。
  • NetworkPolicy。
  • 独立的 ServiceAccount。
  • 清晰的 Ingress 域名和证书。
  • 节点容量及环境间的资源争抢策略。

以下场景更适合使用独立集群:

  • QA 需要接近生产环境的集群级配置。
  • 环境之间必须严格隔离身份、网络或数据。
  • 不允许一个环境耗尽另一个环境的集群资源。
  • 需要独立升级 Kubernetes、Ingress Controller 或 CRD。
  • 合规要求禁止共享控制面或节点。

即使使用独立集群,通常也应该划分不同的 namespace,不要把所有资源都部署到 default。

Secret 与环境配置

不要将密码、连接字符串或证书以明文形式提交到普通 values 文件。Helm 的渲染结果、release 历史和 CI 日志都可能暴露这些内容。

在 AKS 上可以考虑:

  • Azure Key Vault。
  • Secrets Store CSI Driver。
  • External Secrets Operator。
  • 通过受保护的 CI/CD secret 临时注入。

Chart 中只引用 Secret:

env:
  - name: DATABASE_PASSWORD
    valueFrom:
      secretKeyRef:
        name: payment-database
        key: password

普通的环境差异放在 values 中,敏感信息交给专门的 Secret 管理方案,不要把两者混在一起。

部署前后的检查

提交 Chart 时至少执行:

helm lint ./charts/payment

查看最终的渲染结果:

helm template payment ./charts/payment \
  --namespace dev \
  -f ./environments/dev/payment.yaml \
  --set-string image.tag="test-version"

部署前查看变更也很有用。Helm 本身没有内置完整的 diff 体验。如果使用 Helm Diff 插件,应在团队环境和 CI 环境中统一安装,并管理好插件版本。

部署后执行检查:

helm status payment --namespace dev
kubectl rollout status deployment/payment --namespace dev
helm history payment --namespace dev

需要人工回滚时:

helm rollback payment 1 --namespace dev

--atomic 会在升级失败时自动回滚,但不能替代应用级健康检查。Deployment 仍需正确配置 readinessProbe、livenessProbe,必要时再增加 startupProbe。

实践建议

  • 每个可以独立发布的微服务使用独立的 Chart 和 release。
  • Chart 保存通用模板,环境文件只记录差异,不要复制整套配置。
  • 明确指定 --kube-context 和 --namespace,降低误部署风险。
  • 部署脚本应通过白名单映射环境名和集群,不要直接信任任意输入。
  • 对 QA 等受控环境设置审批门禁,并采用 Azure/Kubernetes 最小权限。
  • 镜像使用不可变的 tag 或 digest,同时记录 Chart 版本和应用版本。
  • 使用 helm lint、helm template 以及 Kubernetes schema/policy 校验。
  • 配置资源 requests/limits、健康检查、PodDisruptionBudget 和 autoscaling。
  • 将 CRD、Ingress Controller、证书组件等集群级资源与业务服务分开发布。
  • 避免多个流水线同时修改同一个 release,并设置环境级并发锁。
  • 如果采用 GitOps,应让 Git 中声明的目标状态成为唯一来源,避免流水线和人工命令同时管理同一个 release。

可以先让 dev 与 QA 使用独立的 namespace,每个微服务各有一个 Chart 和 release,各环境维护一个覆盖文件,再由 CI/CD 明确选择 AKS context 并执行 helm upgrade --install。只有隔离、安全或集群级配置确实有要求时,再将 dev 和 QA 拆分到独立的 AKS 集群。

备注:内容仅供参考。