如何使用 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 流水线就可以完成这些步骤:
- 登录 Azure。
- 获取目标 AKS 凭据。
- 选择并验证 kube context。
- 创建 namespace。
- 运行 lint 和模板检查。
- 部署多个 Helm release。
- 等待 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 集群。
备注:内容仅供参考。
