4. Helm 包管理基础:Helm 架构、Chart 结构、模板化部署、Values 文件管理
Helm 是 Kubernetes 生态中最流行的包管理工具,被形象地称为“Kubernetes 的 apt/yum”。在发布工程自助门户中,Helm 承担着将复杂应用环境打包、版本化、参数化并一键部署到集群的核心职责。本章将深入解析 Helm 的架构设计、Chart 目录规范、模板引擎渲染机制以及 Values 文件的分层管理策略。
4.1 Helm 架构与核心组件
Helm 采用客户端-服务端架构,由 Helm CLI(客户端)和 Tiller(服务端,v3 已移除)组成。自 Helm v3 起,Tiller 被彻底移除,改为纯客户端架构,直接通过 kubeconfig 与 Kubernetes API Server 交互,大幅提升了安全性和部署效率。
架构演进要点: Helm v3 移除了服务端 Tiller,不再需要在集群中安装 tiller-deployment;每个 Release 由 Helm CLI 直接管理,不再依赖集群内的服务端组件,避免了多租户权限混乱问题。
4.2 Chart 目录结构规范
一个标准的 Helm Chart 遵循固定的目录布局。理解每个文件和目录的职责,是编写可维护 Chart 的基础。
| 路径/文件 | 必需 | 说明 |
|---|---|---|
Chart.yaml |
是 | Chart 元数据:名称、版本、apiVersion、描述、依赖声明 |
values.yaml |
是 | 默认配置值,模板渲染时的变量来源 |
templates/ |
是 | Go 模板文件目录,最终生成 Kubernetes 资源清单 |
charts/ |
否 | 子 Chart 依赖(手动或通过 helm dependency 管理) |
crds/ |
否 | 自定义资源定义(CRD),在模板渲染前安装 |
templates/NOTES.txt |
否 | 安装成功后输出的使用说明文本 |
templates/_helpers.tpl |
否 | 模板辅助函数定义,可被其他模板引用 |
最佳实践: 始终将
_helpers.tpl 中的命名模板以 chartName. 前缀命名,避免子 Chart 与父 Chart 的模板函数冲突。例如:{{- define "myapp.labels" -}}。
4.3 模板化部署与渲染机制
Helm 使用 Go 模板引擎(text/template)结合 Sprig 函数库,将 values.yaml 中的值注入到 templates/ 目录下的 YAML 模板中,生成最终的 Kubernetes 资源清单。
核心渲染流程:
- 值合并: 按照
values.yaml→ 父 Chart values →--set参数 → 外部 values 文件的优先级合并。 - 模板解析: 遍历
templates/目录,解析{{ .Values.xxx }}占位符。 - 函数执行: 执行
include、required、default、toYaml等模板函数。 - 资源生成: 输出完整的 YAML 清单,通过 Kubernetes API 创建或更新资源。
# 示例:Deployment 模板片段 (templates/deployment.yaml)
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myapp.fullname" . }}
labels:
{{- include "myapp.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "myapp.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "myapp.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: {{ .Values.service.port }}
常见陷阱: 模板中的缩进必须使用
nindent 或 indent 函数控制,否则生成的 YAML 缩进错误会导致 API 校验失败。推荐使用 nindent(换行后缩进)而非手动空格。
4.4 Values 文件管理策略
在发布工程自助门户中,环境差异(开发、测试、预发、生产)通过 Values 文件分层管理,避免硬编码和重复定义。
4.4.1 多环境 Values 文件结构
chart/
├── values.yaml # 全局默认值(所有环境共享)
├── values-dev.yaml # 开发环境覆盖
├── values-staging.yaml # 测试环境覆盖
├── values-prod.yaml # 生产环境覆盖
└── secrets/
├── dev-secrets.yaml # 开发环境敏感数据(不提交 Git)
└── prod-secrets.yaml # 生产环境敏感数据
4.4.2 部署命令示例
# 开发环境部署
helm upgrade --install myapp ./myapp \
--namespace dev \
-f values.yaml \
-f values-dev.yaml \
--set image.tag=latest
# 生产环境部署
helm upgrade --install myapp ./myapp \
--namespace prod \
-f values.yaml \
-f values-prod.yaml \
--set image.tag=v1.2.3 \
--set replicaCount=5
4.4.3 Values 文件编写规范
| 规范项 | 推荐做法 | 反例 |
|---|---|---|
| 命名风格 | 驼峰式(camelCase) | 下划线或连字符混用 |
| 默认值 | 始终在 values.yaml 中提供合理默认值 |
依赖 --set 强制传入 |
| 敏感数据 | 使用 secrets.yaml 或外部密钥管理(Vault) |
明文写在 values.yaml 中 |
| 类型约束 | 明确使用 int、bool、string 类型 |
字符串数字混用导致模板报错 |
| 注释 | 每个字段上方添加 # 注释说明用途 |
无注释或注释与字段不匹配 |
门户集成建议: 在自助门户中,将 Values 文件管理抽象为“环境配置模板”功能。用户通过 UI 选择环境(dev/staging/prod),系统自动加载对应的 values 文件,并允许用户在界面上覆盖
--set 参数,最终生成 helm upgrade 命令并执行。
4.5 依赖管理与子 Chart
复杂应用通常由多个组件组成(如前端、后端、数据库)。Helm 通过 Chart.yaml 中的 dependencies 字段管理子 Chart 依赖。
# Chart.yaml 依赖声明示例
dependencies:
- name: postgresql
version: "12.1.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
- name: redis
version: "17.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled
执行 helm dependency update 后,Helm 会将子 Chart 下载到 charts/ 目录。子 Chart 的 values 可以通过父 Chart 的 values.yaml 中的嵌套结构覆盖:
# 父 Chart values.yaml 覆盖子 Chart 配置
postgresql:
enabled: true
auth:
database: myapp
username: myapp_user
redis:
enabled: false
依赖管理技巧: 使用
condition 字段控制子 Chart 是否启用,避免在不需要时安装额外组件。使用 tags 字段可以批量启用/禁用一组子 Chart。
4.6 本章小结
- Helm 架构: v3 纯客户端模式,直接与 K8s API 交互,安全高效。
- Chart 结构: 遵循标准目录布局,
Chart.yaml、values.yaml、templates/是核心三要素。 - 模板化部署: Go 模板 + Sprig 函数实现参数化渲染,
nindent控制缩进。 - Values 管理: 多环境文件分层 +
--set覆盖,敏感数据独立管理。 - 依赖管理: 通过
dependencies声明子 Chart,支持条件启用和值覆盖。