3. Helm 依赖管理:子 Chart 与全局值、条件依赖、hooks 机制
在生产级 Helm 应用中,一个 Chart 往往需要依赖多个子 Chart(如 MySQL、Redis、Prometheus)来组成完整的服务栈。Helm 的依赖管理机制允许你声明式地定义这些子 Chart,并通过 全局值、条件依赖 和 Hooks 实现精细化的交付控制。本章将深入剖析这三项核心能力,并结合 SRE 场景说明其应用。
3.1 子 Chart 与全局值传递
子 Chart 通过 Chart.yaml 中的 dependencies 字段声明。Helm 会从仓库下载或本地路径引用子 Chart,并在渲染时将其模板合并到父 Chart 中。
3.1.1 依赖声明与值覆盖
以下是一个典型的 Chart.yaml 依赖声明:
# Chart.yaml
apiVersion: v2
name: myapp
version: 1.0.0
dependencies:
- name: redis
version: "~17.0.0"
repository: "https://charts.bitnami.com/bitnami"
alias: cache
- name: mysql
version: "~9.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: mysql.enabled
子 Chart 的值默认从父 Chart 的 values.yaml 中同名键读取。例如,父 Chart 中 redis.xxx 会传递给子 Chart redis。但更推荐使用 全局值 实现跨 Chart 共享配置。
3.1.2 全局值(Global Values)
全局值通过父 Chart values.yaml 中的 global 字段定义,所有子 Chart 均可直接引用。这在设置公共环境标签、镜像仓库地址、全局开关时非常有用。
# 父 Chart values.yaml
global:
registry: "registry.internal.company.com"
environment: "production"
labels:
team: "sre"
app: "myapp"
redis:
image:
registry: "{{ .Values.global.registry }}"
fullnameOverride: "myapp-cache"
mysql:
enabled: true
image:
registry: "{{ .Values.global.registry }}"
3.2 条件依赖(Conditional Dependencies)
条件依赖允许根据父 Chart 的值动态启用或禁用子 Chart。这在多环境部署(如开发环境不启用 MySQL 集群,生产环境启用)中至关重要。
3.2.1 条件声明与使用
在 Chart.yaml 的依赖项中,使用 condition 字段指定一个布尔值路径:
# Chart.yaml
dependencies:
- name: mysql
condition: mysql.enabled # 当 .Values.mysql.enabled 为 true 时安装
- name: redis
condition: redis.enabled # 当 .Values.redis.enabled 为 true 时安装
在 values.yaml 中控制开关:
# values.yaml
mysql:
enabled: true
redis:
enabled: false
执行 helm dependency update 后,Helm 会根据条件生成锁文件 Chart.lock,并在安装时只渲染启用的子 Chart。
3.2.2 条件依赖与全局值联动
条件依赖可以与全局值结合,实现更复杂的策略:
# values.yaml
global:
highAvailability: true
mysql:
enabled: "{{ .Values.global.highAvailability }}"
replicaCount: 3
values.yaml 中显式定义,否则 Helm 会将其视为 false 并跳过子 Chart。在 SLO 违约后的快速恢复场景中,错误的条件配置可能导致关键依赖缺失。
3.3 Hooks 机制:Pre/Post Install、Upgrade、Delete
Helm Hooks 允许在 Release 生命周期的特定节点执行自定义 Job。这对于数据库迁移、预热缓存、DNS 记录更新、SLO 违约后的延迟处置等场景至关重要。
3.3.1 Hook 类型与执行顺序
| Hook 名称 | 触发时机 | 典型用途 |
|---|---|---|
pre-install |
在 Release 资源被创建之前 | 创建数据库、初始化配置、验证依赖 |
post-install |
在 Release 所有资源创建成功后 | 数据填充、缓存预热、健康检查 |
pre-upgrade |
在 Upgrade 操作执行之前 | 备份数据、暂停流量、DNS 预切换 |
post-upgrade |
在 Upgrade 操作执行成功后 | 验证新版本、清理旧资源、更新 DNS 记录 |
pre-delete |
在 Release 删除操作执行之前 | 优雅关闭、数据导出、通知下游 |
post-delete |
在 Release 删除操作执行成功后 | 清理外部资源、发送告警 |
3.3.2 Hook 资源定义示例
以下是一个 pre-upgrade Hook,用于在升级前备份 MySQL 数据:
# templates/pre-upgrade-backup.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ .Release.Name }}-pre-upgrade-backup"
annotations:
"helm.sh/hook": pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation
spec:
template:
spec:
restartPolicy: Never
containers:
- name: backup
image: "{{ .Values.global.registry }}/mysql-backup:latest"
env:
- name: DB_HOST
value: "{{ .Release.Name }}-mysql"
- name: BACKUP_PATH
value: "/backup/{{ .Release.Name }}-pre-upgrade.sql"
command: ["/bin/sh", "-c", "mysqldump -h $DB_HOST -u root -p$DB_PASSWORD --all-databases > $BACKUP_PATH"]
3.3.3 Hook 权重与删除策略
- 权重(hook-weight): 控制同一 Hook 类型下多个 Job 的执行顺序。权重越小,越先执行。默认权重为 0。
- 删除策略(hook-delete-policy): 控制 Hook Job 在完成后是否自动删除。常用值:
before-hook-creation(创建新 Hook 前删除旧 Job)、hook-succeeded(成功后删除)、hook-failed(失败后保留以便排查)。
当检测到 SLO 违约(如 DNS 解析延迟 > 500ms)时,可通过
pre-upgrade Hook 执行 DNS 预切换脚本,将流量指向备用 DNS 服务器;post-upgrade Hook 验证新 DNS 记录的生效时间,确保延迟恢复到 SLO 阈值内。
3.4 依赖管理与 Hooks 的协同流程
下图展示了 Helm 在安装/升级过程中,依赖解析与 Hooks 的执行顺序:
3.5 常见陷阱与 SRE 建议
| 陷阱 | 现象 | SRE 建议 |
|---|---|---|
| 子 Chart 版本未锁定 | 不同环境安装的版本不一致 | 始终提交 Chart.lock 到 Git,使用 helm dependency build |
| 全局值命名冲突 | 子 Chart 意外覆盖全局值 | 使用 global. 前缀,避免与子 Chart 内部键名重复 |
| Hook Job 残留 | 大量已完成 Job 占用集群资源 | 设置 hook-delete-policy: hook-succeeded,并配置 TTL 控制器 |
| 条件依赖未生效 | 子 Chart 始终被安装或跳过 | 检查 condition 路径是否与 values.yaml 层级一致,使用 helm template --debug 验证 |
| Hook 执行超时 | Release 安装/升级卡住 | 为 Hook Job 设置 activeDeadlineSeconds,并在 helm install 时使用 --timeout 参数 |
pre-upgrade Hook 中执行 DNS 预切换(权重 -10),在 post-upgrade Hook 中执行 DNS 延迟验证(权重 +10),确保切换过程可观测、可回滚。