4、多环境 Values 文件设计:为开发、测试、预发布、生产、金丝雀分别创建 values-{env}.yaml,使用全局与局部变量

在 Helm Chart 的实际交付中,不同环境(开发、测试、预发布、生产、金丝雀)对资源规格、副本数、镜像标签、域名、数据库连接串等配置的需求截然不同。如果所有环境共用同一个 values.yaml,会导致配置膨胀、覆盖链混乱、误操作风险剧增。本章将系统讲解如何为每个环境创建独立的 values-{env}.yaml,并通过全局变量与局部变量的分层设计,实现配置的复用与隔离。

4.1 多环境 Values 文件结构

推荐在 Chart 根目录下按环境名称组织 values 文件,与默认的 values.yaml 形成分层覆盖关系:

my-chart/
├── Chart.yaml
├── values.yaml              # 全局默认值(所有环境共享的基础配置)
├── values-dev.yaml          # 开发环境覆盖
├── values-test.yaml         # 测试环境覆盖
├── values-staging.yaml      # 预发布环境覆盖
├── values-prod.yaml         # 生产环境覆盖
└── values-canary.yaml       # 金丝雀环境覆盖(通常继承 prod 并做少量调整)
命名规范: 使用 values-{env}.yaml 模式,便于 CI/CD 流水线通过环境变量动态选择文件。避免使用 values-dev.yaml、values-prod.yaml 之外的随意命名。

4.2 全局变量与局部变量分层设计

全局变量(Global)作用于 Chart 内所有子 Chart 和模板,适合存放跨组件共享的配置,如集群名称、公共标签、全局域名后缀。局部变量(Local)仅作用于当前 Chart 或特定组件,适合存放环境差异化的配置,如副本数、资源限制、镜像版本。

变量层级 定义位置 作用域 典型用途
全局变量 values.yaml 的 global: 字段 整个 Release 的所有子 Chart 集群名称、环境标签、公共域名、全局镜像仓库地址
局部变量 values.yaml 或 values-{env}.yaml 的顶层字段 当前 Chart 及其子模板 副本数、资源 requests/limits、镜像 tag、ingress 域名
环境覆盖变量 values-{env}.yaml 的顶层或 global: 字段 仅在该环境部署时生效 开发环境用最小资源、生产环境用高可用副本数
最佳实践: 全局变量只放“所有环境都相同”或“所有组件都需要”的配置。环境差异化的配置应放在局部变量中,通过 values-{env}.yaml 覆盖。避免在全局变量中存放环境敏感信息(如数据库密码),应使用 Kubernetes Secret 或外部密钥管理工具。

4.3 各环境 Values 文件设计要点

4.3.1 开发环境(values-dev.yaml)

  • 目标: 快速迭代、低成本、调试友好。
  • 关键配置: 副本数 1、资源 requests 极低(如 50m CPU / 128Mi 内存)、开启 debug 日志、使用 latest 或 feature 分支镜像 tag、禁用 HPA 和 PDB。
  • 示例:
# values-dev.yaml
global:
  environment: dev
  domainSuffix: dev.example.com

replicaCount: 1
image:
  tag: "latest"
  pullPolicy: Always
resources:
  requests:
    cpu: 50m
    memory: 128Mi
  limits:
    cpu: 200m
    memory: 256Mi
ingress:
  enabled: true
  host: my-app.dev.example.com
autoscaling:
  enabled: false
podDisruptionBudget:
  enabled: false

4.3.2 测试环境(values-test.yaml)

  • 目标: 模拟生产、自动化测试、稳定性验证。
  • 关键配置: 副本数 2、资源接近生产但略低、使用 CI 构建的稳定 tag、开启 HPA 但阈值放宽、启用 PDB。
  • 示例:
# values-test.yaml
global:
  environment: test
  domainSuffix: test.example.com

replicaCount: 2
image:
  tag: "ci-build-1234"
  pullPolicy: IfNotPresent
resources:
  requests:
    cpu: 200m
    memory: 512Mi
  limits:
    cpu: 500m
    memory: 1Gi
ingress:
  enabled: true
  host: my-app.test.example.com
autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 5
  targetCPUUtilizationPercentage: 80
podDisruptionBudget:
  enabled: true
  minAvailable: 1

4.3.3 预发布环境(values-staging.yaml)

  • 目标: 与生产环境配置完全一致,仅流量隔离。
  • 关键配置: 副本数、资源、镜像 tag 与生产相同;使用预发布域名;连接预发布数据库;开启完整监控和告警。
  • 示例:
# values-staging.yaml
global:
  environment: staging
  domainSuffix: staging.example.com

replicaCount: 3
image:
  tag: "v1.2.3-rc1"
  pullPolicy: IfNotPresent
resources:
  requests:
    cpu: 500m
    memory: 1Gi
  limits:
    cpu: 2
    memory: 2Gi
ingress:
  enabled: true
  host: my-app.staging.example.com
autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70
podDisruptionBudget:
  enabled: true
  minAvailable: 2

4.3.4 生产环境(values-prod.yaml)

  • 目标: 高可用、高性能、安全合规。
  • 关键配置: 多副本(至少 3)、资源充足、使用正式发布 tag、启用 HPA 和 PDB、开启 Pod 反亲和、配置就绪/存活探针、启用 TLS。
  • 示例:
# values-prod.yaml
global:
  environment: prod
  domainSuffix: example.com

replicaCount: 5
image:
  tag: "v1.2.3"
  pullPolicy: IfNotPresent
resources:
  requests:
    cpu: 1
    memory: 2Gi
  limits:
    cpu: 4
    memory: 4Gi
ingress:
  enabled: true
  host: my-app.example.com
  tls:
    enabled: true
    secretName: my-app-tls
autoscaling:
  enabled: true
  minReplicas: 5
  maxReplicas: 20
  targetCPUUtilizationPercentage: 65
podDisruptionBudget:
  enabled: true
  minAvailable: 3
affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
              - key: app
                operator: In
                values:
                  - my-app
          topologyKey: kubernetes.io/hostname

4.3.5 金丝雀环境(values-canary.yaml)

  • 目标: 基于生产环境做小范围灰度验证,快速回滚。
  • 关键配置: 继承生产配置,仅修改镜像 tag 为金丝雀版本、副本数减少(如 1~2)、添加金丝雀标签、配置流量权重(通过 Service Mesh 或 Ingress 实现)。
  • 示例:
# values-canary.yaml
global:
  environment: canary
  domainSuffix: example.com

# 继承生产配置,仅覆盖以下字段
replicaCount: 2
image:
  tag: "v1.3.0-canary.1"
  pullPolicy: Always
canary:
  enabled: true
  weight: 5  # 5% 流量进入金丝雀版本
  stableService: my-app-prod
注意: 金丝雀环境通常不独立部署完整集群,而是通过 Service Mesh(如 Istio)或 Ingress Controller 的流量分割能力,在生产集群中创建金丝雀版本的 Deployment,并与稳定版本共享 Service。此时 values-canary.yaml 需要配合 canary.weight 等字段使用,而非独立部署。

4.4 全局变量与局部变量的协同工作流

以下 SVG 图展示了 Helm 在部署时如何合并全局变量、默认局部变量与环境覆盖变量,最终生成渲染模板所用的完整 values 对象。

多环境 Values 合并流程 多环境 Values 合并流程 values.yaml 全局默认值 values-{env}.yaml 环境覆盖值 --set / --set-file 命令行覆盖 Helm Values 合并引擎 优先级:--set > values-{env}.yaml > values.yaml 最终渲染用 Values 对象 全局变量(global.*)+ 局部变量(顶层字段) 所有环境覆盖已合并,模板通过 .Values 访问 Go 模板渲染({{ .Values }})

4.5 部署时选择环境 Values 文件

在 CI/CD 流水线或命令行中,通过 -f 参数指定环境对应的 values 文件,Helm 会自动按优先级合并:

# 开发环境部署
helm upgrade --install my-app ./my-chart \
  -f values.yaml \
  -f values-dev.yaml \
  --namespace dev

# 生产环境部署
helm upgrade --install my-app ./my-chart \
  -f values.yaml \
  -f values-prod.yaml \
  --namespace prod

# 金丝雀部署(基于生产,额外覆盖)
helm upgrade --install my-app-canary ./my-chart \
  -f values.yaml \
  -f values-prod.yaml \
  -f values-canary.yaml \
  --namespace prod \
  --set canary.weight=5
关键原则: 始终先加载 values.yaml 作为基础,再加载 values-{env}.yaml 进行环境覆盖。金丝雀部署时,先加载生产配置,再加载金丝雀覆盖,确保只修改必要的差异字段。

4.6 全局变量在子 Chart 中的传递

当 Chart 包含子 Chart(依赖)时,全局变量通过 global 字段自动向下传递。子 Chart 的模板中通过 {{ .Values.global.environment }} 访问。局部变量不会自动传递,需要在父 Chart 的 requirements.yaml 或 Chart.yaml 的 dependencies 中显式传递。

# 父 Chart values.yaml
global:
  environment: prod
  clusterName: prod-cluster-01

# 子 Chart 模板(如 subchart/templates/deployment.yaml)
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    environment: {{ .Values.global.environment }}
    cluster: {{ .Values.global.clusterName }}

4.7 常见避坑指南

  • 不要将敏感信息硬编码在 values 文件中: 数据库密码、 等应使用 Kubernetes Secret 或外部密钥管理工具(如 Vault、Sealed Secrets),values 中只引用 Secret 名称。
  • 避免全局变量过度膨胀: 全局变量应保持精简,只放跨组件共享的配置。每个子 Chart 的独有配置应放在局部变量中,通过 dependencies 的 import-values 或显式传递。
  • 环境覆盖文件不要重复定义全局变量: 如果 values-dev.yaml 中定义了 global.environment: dev,则 values.yaml 中的 global.environment 会被覆盖,无需重复定义其他全局字段。
  • 金丝雀环境不要独立部署完整集群: 金丝雀应基于生产环境做增量覆盖,避免维护两套独立的基础设施配置。
  • 使用 helm get values 验证合并结果: 部署后执行 helm get values my-app --namespace prod 查看最终生效的 values 对象,确保覆盖链正确。

4.8 多环境 Values 文件对比总览

配置项 开发 (dev) 测试 (test) 预发布 (staging) 生产 (prod) 金丝雀 (canary)
副本数 1 2 3 5 2(基于 prod)
CPU requests 50m 200m 500m 1 1(继承 prod)
内存 requests 128Mi 512Mi 1Gi 2Gi 2Gi(继承 prod)
镜像 tag latest ci-build-1234 v1.2.3-rc1 v1.2.3 v1.3.0-canary.1
HPA 启用 否 是(阈值 80%) 是(阈值 70%) 是(阈值 65%) 是(继承 prod)
PDB 启用 否 是(minAvailable:1) 是(minAvailable:2) 是(minAvailable:3) 否(金丝雀可容忍中断)
域名后缀 dev.example.com test.example.com staging.example.com example.com example.com(继承 prod)
金丝雀流量权重 — — — — 5%

通过以上分层设计,每个环境只需维护自己差异化的配置,全局变量确保跨环境的一致性,局部变量提供环境级别的灵活性。这种模式在大型微服务项目中尤其重要,能够显著降低配置管理的复杂度,减少人为失误。