Chart 目录结构
这一课你将能做到
- 用
helm create 生成标准骨架,并指认 Chart.yaml、values.yaml、templates/、_helpers.tpl 各自的职责
- 把脚手架删减为「Deployment + Service」的最小 backend Chart,说清为何删除 HPA/Ingress 等可选模板是合理取舍
- 对照本站裸 YAML 清单,列出应抽进 values 的环境差异字段(至少镜像 tag、副本数、DB 地址、探针路径)
为什么要学
仓库约定是 Helm 的「合同」:Helm 按固定目录找元数据、默认配置与模板,渲染器按固定规则处理下划线开头的文件。目录乱、把密钥写进 values、把环境常量硬编码进模板,后面 helm template、helm lint 和 GitOps 同步都会痛。本课目标是搭出 可 lint、可渲染 的 backend Chart 骨架——下一课才填 Go template 的语法细节。你已会 K8s 资源语义,这里学的是「把它们装进包」的标准形状。
先建立图像
coderoadmap-backend/ ← Chart 根目录(目录名通常=Chart 名)
├── Chart.yaml ← 包身份证:name、version、依赖声明
├── values.yaml ← 默认配置(可被 -f / --set 覆盖)
├── charts/ ← 子 Chart(dependency update 后出现)
├── templates/ ← 待渲染的 YAML 模板
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── _helpers.tpl ← 可复用的命名/标签片段(下划线开头不直接渲染)
│ ├── NOTES.txt ← install 成功后打印的使用提示
│ └── NOTES 之外的文件按资源类型命名
└── .helmignore ← 打包时忽略的文件(类似 .gitignore)
| 文件/目录 | 人话 | 什么时候改它 |
|---|
| Chart.yaml | 包名、版本、描述、依赖 | 发版 bump version、加依赖 |
| values.yaml | 出厂默认旋钮 | 定默认值;环境差异另建 values-*.yaml |
| templates/*.yaml | 资源形状 | 增删资源种类(Deployment/Service…) |
| _helpers.tpl | 命名与标签函数 | 统一资源名前缀、统一标签 |
| charts/ | 解压后的依赖包 | 不手改,由 dependency 命令管理 |
| .helmignore | 打包黑名单 | 排除文档、测试脚本等 |
人话:Chart.yaml 是包装盒上的标签;values.yaml 是出厂预设的旋钮;templates/ 是「按旋钮填空」的说明书;_helpers.tpl 是说明书里反复引用的填空公式。
跟着做
步骤 1:生成骨架
helm create coderoadmap-backend
cd coderoadmap-backend
# Linux/macOS: ls -R 或 tree
# Windows PowerShell: tree /F
你会看到上面图里的标准结构。官方脚手架自带示例 Deployment、Service、Ingress、HPA、ServiceAccount 和测试——对学习用的 backend 来说偏重,下一步裁剪。
步骤 2:读懂并改写 Chart.yaml
# Chart 包元数据(apiVersion: v2 表示 Helm 3 格式)
apiVersion: v2
name: coderoadmap-backend
description: CodeRoadMap Spring Boot backend (MySQL + Redis via config, Nginx at edge)
type: application # application=可安装应用;library=供依赖复用的库 Chart
version: 0.1.0 # Chart 自身版本(SemVer,每次发布必须递增)
appVersion: "1.0.0" # 应用版本提示,与镜像 tag 策略对齐
# dependencies: [] # 依赖在 helm-deps 课再引入
笔记写:「version 变了才算发了新包;只改 templates 不 bump version,仓库消费者无从感知变更。」appVersion 习惯加引号——K8s 注解值必须是字符串。
步骤 3:裁剪 templates 到最小集
学习目标:保留并渲染以下文件,其余(Ingress、HPA、ServiceAccount、tests、serviceaccount 相关 helper)删除或移走:
templates/deployment.yaml
templates/service.yaml
templates/_helpers.tpl(保留 fullname/labels 相关 define,删掉用不到的)
templates/NOTES.txt(可简化为一行访问提示)
helm template demo . --debug
应输出合法 YAML,只含 Deployment + Service。若报错,通常是删文件时把 helper 引用弄断了——对照报错行修掉。
步骤 4:约定 values.yaml 放什么
# 只放「环境会变」或「安装时可调」的项;默认值应安全、可本地跑
replicaCount: 1
image:
repository: registry.example/coderoadmap-backend
tag: "1.0.0" # 最常见覆盖点
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 8080
# 探针(本站 Spring Boot actuator)
probes:
readinessPath: /actuator/health/readiness
livenessPath: /actuator/health/liveness
# 数据库:只写地址与 Secret 名,绝不写密码明文
db:
host: mysql.coderoadmap-dev.svc
port: 3306
passwordSecretName: backend-db-secret
passwordSecretKey: password
# 空对象 = 模板里条件渲染,dev 不配资源限额也能跑
resources: {}
对照 k8s-practice 的裸清单:凡是「环境差异字段」都应出现在这里成为键。本课先列键,下一课在模板里用 .Values.xxx 消费它们。
步骤 5:确认 _helpers.tpl 的职责
打开 _helpers.tpl,看到形如下面的 define(语法细节下一课讲,本课只认职责):
{{/* 统一全名:Release 名 + Chart 名,全集群唯一且可预测 */}}
{{- define "coderoadmap-backend.fullname" -}}
{{- printf "%s-backend" .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
要点:Deployment 的 metadata.name、Service 的 metadata.name、Service 的 selector 都引用同一批 helper——改一处全员生效,且不会拼错。这正是 Service selector 与 Pod 标签必须严格一致的保障。
步骤 6:验收骨架可用性
helm lint . # 语法与最佳实践检查
helm template myrel . > out.yaml # 渲染产物
# 检查 out.yaml:Deployment 与 Service 名称带 release 前缀、selector 与标签一致
helm package . # 打出 coderoadmap-backend-0.1.0.tgz,验证可打包
helm lint 无 Error、helm template 产物可读、helm package 能出包——骨架合格。把「本 Chart 最小文件清单」写进笔记,这就是你后面所有课的工作目录。
讲清楚要点
- 因为 Helm 按约定目录工作,所以不要自创「随便一个 yaml 文件夹」当 Chart——缺 Chart.yaml 就不是合法 Chart,
helm lint/install 都会拒绝。
- 因为默认脚手架偏完整,所以业务 Chart 应按需删减——少一个用不到的 Ingress 模板,就少一处「误开公网入口」的风险面;HPA 同理,先稳再扩。
- 因为 values 是覆盖点,所以默认 values 应安全、可在学习集群直接跑——环境差异放 values-*.yaml 覆盖,而不是改模板或改默认 values。
- 因为密钥进 Git 会永久泄漏,所以 values 只引用 Secret 名——
passwordSecretName 这类键 + 集群侧 Secret/外部注入,是贯穿本 track 的铁律。
- 因为资源命名要稳定可预期,所以用
_helpers.tpl 统一 fullname 与 labels——Service selector 与 Pod 标签来自同一 helper,杜绝「选不中 Pod」这类事故。
- 因为
charts/ 里的内容是构建产物,所以要约定提交策略——要么提交锁定包(可复现),要么 gitignore + CI 每次 helm dependency update(helm-deps 课详述),团队二选一并写进 README。
你可能会懵的地方
-
type: application 和 library 有什么区别?
application 可直接 helm install;library 不产生资源,只通过 define 给其他 Chart 提供 helpers。backend 这种业务 Chart 永远是 application。
-
为什么有的文件以下划线开头?
_helpers.tpl 这类下划线开头的文件不会被单独渲染成集群对象,只作为「片段库」被 include/template 引用。这是 Helm 的约定:下划线 = 不直接输出。
-
.helmignore 有什么用?
helm package 时不打进包里的文件列表,类似 .gitignore。文档、本地脚本、IDE 配置放这里,避免包体积与信息泄漏。
-
Ingress 模板要不要保留?
本站架构里入口由集群级 ingress-nginx 统一管理,业务 Chart 只暴露 ClusterIP Service,Ingress 规则由平台层声明——所以业务 Chart 删掉 Ingress 是正确取舍。若你的服务需要独立域名规则,再以 values 开关加回。
-
NOTES.txt 算资源吗?
不算。它不渲染成集群对象,只在 install/upgrade 成功后打印到终端,作用是告诉使用者「接下来怎么访问、密码从哪取」。写好 NOTES 是 Chart 用户体验的加分项。
错法对照
| 错法 | 问题 | 正解 |
|---|
| 三环境复制三份 Chart 目录 | 模板分叉,修 bug 要改三处 | 一份 Chart + 多份 values |
| 明文 DB 密码写进 values.yaml | 密钥随 Git 永久泄漏 | Secret 名 + 集群侧注入 |
| 保留 create 生成的全部模板 | 误开 Ingress、HPA 抢资源 | 删到最小可运行集 |
手改 charts/ 里解压的内容 | 下次 dependency update 全部冲掉 | 用父 values 覆盖或换上游版本 |
| 资源名写死不带 Release 名 | 同命名空间多实例冲突 | helpers fullname 引用 .Release.Name |
| 忘记 bump version 就发包 | 消费者拉到旧包且无感知 | 发版流程强制递增 version |
卡点急救
- 现象:
helm lint 报 [ERROR] templates/: template not found——某个模板 include/template 引用了不存在的 define 名(常见于删文件后忘改引用);全文搜索报错里的 helper 名,补回 define 或删掉引用。
- 现象:
helm template 输出里 Service selector 和 Pod 标签对不上——两处没有用同一个 selectorLabels helper;把 Deployment 的 template.metadata.labels 与 Service 的 selector 统一改为引用同一 define。
- 现象:
helm package 把临时文件也打进了包——把忽略项加进 .helmignore(如 *.md、.idea/、out.yaml),重新打包并 helm template 抽查。
面试常问
-
一个 Helm Chart 的最小合法结构是什么?
至少包含 Chart.yaml(含 name 与 version)和 templates/ 目录;实践中必有 values.yaml 提供默认配置。apiVersion: v2 表示 Helm 3 格式。额外常见:templates/_helpers.tpl(复用片段)、NOTES.txt(安装提示)、charts/(依赖)、.helmignore。
-
_helpers.tpl 为什么要存在?模板文件不是都可以写在 yaml 里吗?
为了 DRY 与一致性。 fullname、labels、selectorLabels 这类逻辑在多个资源间必须完全一致,集中到 define 后改一处生效全局;下划线前缀保证它们不被当作独立资源渲染。这也是「Service 选不中 Pod」这类经典事故的标准预防手段。
-
Chart 的 version 和 appVersion 分别控制什么?
version 是 Chart 包自身的 SemVer,决定仓库里包的版本与升级解析,每次模板/values 变更发布都必须递增;appVersion 是所打包应用的版本提示,供人与工具识别「这个包对应哪代应用」,常与镜像 tag 对齐但不会自动生效。
自测三问
- Chart.yaml 的
version 与 appVersion 分别给谁看?何时必须 bump version?
- 最小 backend Chart 建议保留哪些模板文件?为什么删除 Ingress 可能是合理取舍?
- values 里适合放什么、绝对不该放什么?各举一个本站 backend 的键名例子。
小结一句话
标准 Chart = Chart.yaml + values.yaml + templates(含 helpers);先用 helm create 起步、裁剪出可 lint 可渲染的最小骨架,把环境差异字段列进 values——下一课填模板语法。
延伸