依赖与子 Chart
这一课你将能做到
- 在
Chart.yaml 声明 dependencies,执行 helm dependency update/build/list,并在 charts/ 目录看到拉取的子包
- 用 与子 Chart 同名的顶层 values 键 覆盖子 Chart 配置,并用
condition 开关可选依赖,用 alias 安装同一 Chart 的两个实例
- 说明本站架构取舍:backend 的 Redis 在 demo 环境用子 Chart、生产外接;MySQL/平台组件为何不塞进业务 Chart
为什么要学
真实系统很少「一个 Deployment 打天下」:backend 要连 Redis 缓存、偶尔还要消息队列或证书管理。Helm 允许在父 Chart 的 Chart.yaml 里声明 dependencies,把社区维护的 Chart 组合成一个可安装单元。不会管依赖,你就会手搓重复资源、把密码与版本散落多处;反过来把一切塞进超级父 Chart,也会得到一个谁都不敢动的巨石。本课学 声明、拉取、覆盖、开关 四个动作,并建立「能组合 ≠ 应该全组合」的架构判断。
先建立图像
coderoadmap-backend/ ← 父 Chart(业务)
├── Chart.yaml ← dependencies: redis, …
├── values.yaml ← redis: { … } ← 用子 Chart 名当顶层 key 覆盖
├── charts/
│ └── redis-20.x.x.tgz ← helm dependency update 的产物
└── templates/ ← 只放业务资源(Deployment/Service)
| 概念 | 人话 |
|---|
| dependency | 父包装时需要的子 Chart 坐标(名、版本、仓库) |
| subchart | 被拉下来、随父 Chart 一起安装/渲染的 Chart |
| values 前缀 | 用「子 Chart 名」作顶层 key,把配置传给子 Chart |
| condition | values 里的布尔键,为 false 则该依赖整体跳过 |
| alias | 给依赖起别名,可同名依赖装两份、values 各自独立 |
helm dependency update → 按 Chart.yaml 解析下载到 charts/(生成 Chart.lock)
helm template/install → 父模板 + 启用的子 Chart 一并渲染/安装
跟着做
步骤 1:声明 Redis 依赖(对齐本站技术栈)
backend 需要 Redis 缓存。demo/学习环境直接把 Bitnami Redis 作为子 Chart 起一个;生产再切换为外接地址。编辑父 Chart.yaml:
apiVersion: v2
name: coderoadmap-backend
description: CodeRoadMap Spring Boot backend
type: application
version: 0.2.0 # 引入依赖属于变更,bump version
appVersion: "1.0.0"
dependencies:
- name: redis
version: "20.6.2" # 钉具体版本更可复现(以仓库实际可用版本为准)
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled # values 里 redis.enabled=false 则整个跳过
若尚未添加 Bitnami 源:helm repo add bitnami https://charts.bitnami.com/bitnami。
步骤 2:拉取依赖
helm dependency update ./coderoadmap-backend
helm dependency list ./coderoadmap-backend
charts/ 下出现 redis-20.6.2.tgz,同时生成 Chart.lock(锁精确版本)。团队约定二选一并写进 README:提交 tgz+lock(可复现),或 gitignore 后由 CI 在打包前执行 helm dependency build。
步骤 3:写 values 覆盖子 Chart
父 values.yaml 追加(键名必须与依赖 name/alias 同名):
# 业务自身
replicaCount: 2
image:
repository: registry.example/coderoadmap-backend
tag: "1.0.0"
db:
host: mysql.prod.internal # MySQL 始终外接,不走子 Chart
passwordSecretName: backend-db-secret
# 顶层 key 与依赖 name 同名 → 整块传给子 Chart
redis:
enabled: true # 对应 condition: redis.enabled
architecture: standalone
auth:
enabled: false # 学习环境免密;生产必须 true 且走 Secret
master:
persistence:
enabled: false # 学习集群关持久化,避免残留 PVC
人话:你不是去改子 Chart 的文件,而是 按子 Chart 的 values 文档(helm show values bitnami/redis)在父级同名键下覆盖。
步骤 4:渲染验证开关
helm template demo ./coderoadmap-backend -f values.yaml > with-redis.yaml
helm template demo ./coderoadmap-backend \
-f values.yaml --set redis.enabled=false > no-redis.yaml
对比两份输出:关闭后不应再出现 Redis 的 StatefulSet/Service,而业务 Deployment 仍在。这就是「同一 Chart 服务含缓存 demo 与外接缓存生产」的开关机制。
步骤 5:体验 alias(同一 Chart 两个实例)
# Chart.yaml 里改成两个依赖,第二个用 alias
dependencies:
- name: redis
version: "20.6.2"
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled
- name: redis
alias: redis-sessions # 缓存与会话分开两套
version: "20.6.2"
repository: https://charts.bitnami.com/bitnami
condition: redis-sessions.enabled
helm dependency update ./coderoadmap-backend
values 里现在要写两块:redis: 与 redis-sessions:,互不影响。入门不常用,但排障看到「顶层键和依赖名对不上」多半就是 alias。
步骤 6:对照本站架构划分边界
| 组件 | 归属 | 理由 |
|---|
| Spring Boot backend | 业务 Chart 本体 | 自研模板,参数化交付 |
| Redis(demo) | 业务 Chart 的子 Chart + condition | 学习/演示环境一键起全套 |
| Redis(生产) | 外接实例,values 只写地址 | 缓存由运维统一治理 |
| MySQL | 始终外接 | 有状态核心数据,不放业务 Chart |
| Nginx/ingress | 平台层独立 Release | 集群共享一个控制器,不随业务复制 |
笔记写死两条:业务依赖(仅本应用需要)可用子 Chart;平台组件(集群共享)必须独立 Release。
讲清楚要点
- 因为依赖坐标写在 Chart.yaml,所以版本可审、可锁——
Chart.lock 锁定精确版本,杜绝「同事机器上偶然能装」的漂移。
- 因为子 Chart 配置走同名顶层 key,所以覆盖前必须先
helm show values <子Chart>——盲猜键名不报错但完全无效,是子 Chart 第一大坑。
- 因为 condition 能整体关掉依赖,所以同一 Chart 可同时服务「内嵌 demo」与「外接生产」——用 values 开关,而不是 fork 两套 Chart。
- 因为
charts/*.tgz 是构建产物,所以要明确提交策略——提交则锁定可复现,不提交则 CI 必须执行 helm dependency build;最怕的是两边都做一半。
- 因为平台组件应集群共享,所以不要把 ingress-nginx 嵌进每个业务父 Chart——十个业务装十个入口控制器是灾难;平台层独立安装一次。
- 因为嵌套越深 values 越难推理,所以优先浅依赖 + 外部服务——超过一层的子子 Chart 会让配置审计成本指数上升。
你可能会懵的地方
-
helm dependency build 和 update 的区别?
update 按 Chart.yaml 的版本约束重新解析并刷新 tgz 与 Chart.lock;build 只按已有 Chart.lock 精确还原。CI 里用 build 保证可复现,升级依赖时手动 update 并提交新 lock。
-
子 Chart 的 values 能摊平到父根上吗?
不能。必须挂在子 Chart 名(或 alias)下面,如 redis.master.persistence.enabled;写在根上会被父 Chart 自己消费,传不进子 Chart。
-
tags: 和 condition: 有什么区别?
condition 是每个依赖可挂一个布尔值,写在依赖条目上;tags 是给依赖打标签,用 tags: 值表批量开关一组依赖。两者都支持时 condition 优先级更高。入门掌握 condition 即可。
-
依赖的子 Chart 用了已弃用 API 怎么办?
升级依赖版本或换维护活跃的 Chart;用 helm template 对照目标集群版本验证渲染结果,必要时向上游提 PR 而不是手改 charts/ 里的包。
-
子 Chart 装在哪个命名空间?
与父 Chart 的 Release 同命名空间——Helm 把父与子当作一次 Release 的整体渲染。想让 Redis 独立命名空间,就不要做子 Chart,单独 install 一个 Release。
错法对照
| 错法 | 问题 | 正解 |
|---|
手改 charts/ 里解压的内容 | 下次 update 全部冲掉 | 父 values 覆盖,或 fork 上游 |
生产 redis.enabled 恒为 true 且密码进 Git | 泄密、状态难管 | 生产外接 + Secret;demo 才开子 Chart |
| 每个微服务嵌一套 ingress-nginx | 控制器混战、资源翻倍 | 平台层独立 Release |
依赖版本写 * 或不写 | 某天构建漂移、不可复现 | 钉 SemVer + Chart.lock |
父 values 里 master.persistence 写在根上 | 传不进子 Chart | 挂在 redis: 顶层键下 |
| alias 后 values 仍写原名 | 配置错位到另一个实例 | 顶层键与 alias 同名 |
卡点急救
- 现象:
Error: can't get a valid version for ... redis——版本约束写错或索引过期;helm repo update 后用 helm search repo bitnami/redis --versions 查真实存在的版本号,填入 Chart.yaml 再 update。
- 现象:改了 values 里 redis 的配置但毫无效果——键名层级挂错了(没挂在
redis: 下)或拼写不符;helm show values bitnami/redis 核对键路径,再 helm template 验证渲染。
- 现象:
helm dependency update 后 CI 打包仍报缺依赖——CI 用了 helm package 却没先 helm dependency build,且 tgz 被 gitignore;在 CI 脚本 package 前补 build 步骤,或按团队约定提交 tgz。
面试常问
-
Helm 的依赖管理机制是怎样的?
在父 Chart.yaml 的 dependencies 里声明子 Chart 的 name/version/repository,helm dependency update 解析约束下载 tgz 到 charts/ 并生成 Chart.lock 锁定精确版本;渲染时父与子作为一个 Release 整体输出,父 values 里与子 Chart 同名的顶层键用于传配置,condition/tags 控制开关,alias 支持同 Chart 多实例。
-
如何决定哪些组件做成子 Chart、哪些独立部署?
看共享边界与生命周期:仅本应用私有、跟随应用启停的附属(如本应用的 Redis 缓存 demo)适合子 Chart;集群共享、独立升级、有自己 RBAC/网络策略的平台组件(ingress-nginx、监控栈、证书管理器)必须独立 Release。判断口诀:一个 Chart 一个 Owner、一个升级节奏。
-
同一 Chart 需要安装两份相同组件怎么办?
用 alias:dependencies 里两条同 name 不同 alias 的记录,values 分别挂在两个别名下,渲染出两套独立资源。典型场景是缓存与会话库隔离。
自测三问
- 父 values 里如何把
auth.enabled 传给名为 redis 的子 Chart?写出锅位层级。
condition: redis.enabled 解决什么问题?关闭后 helm template 输出应少什么?
- 为什么本站生产环境 MySQL 与 ingress-nginx 都不进业务 Chart 的依赖列表?
小结一句话
用 Chart.yaml dependencies + dependency update/build 组合子 Chart,用同名 values 键、condition、alias 控制传参与开关;浅组合、平台独立安装,业务 Chart 保持可审可读。
延伸