3. Helm 基础回顾:Chart 结构、模板引擎、Values 文件、Release 管理
在集成 OPA 策略引擎之前,必须牢固掌握 Helm 的核心概念。Helm 是 Kubernetes 的包管理器,它将应用及其依赖打包为 Chart,通过 模板引擎 动态生成 Kubernetes 资源清单,利用 Values 文件 实现配置分离,并通过 Release 管理部署的生命周期。本节将逐一拆解这些基础组件,为后续的合规治理奠定技术基础。
3.1 Chart 目录结构
一个标准的 Helm Chart 是一个遵循特定布局的目录集合。理解其结构是创建和修改 Chart 的前提。
my-app/
├── Chart.yaml # Chart 元数据(名称、版本、描述等)
├── values.yaml # 默认配置值
├── values.schema.json # (可选)Values 的 JSON Schema 校验文件
├── charts/ # 子 Chart 依赖(手动或通过 helm dependency 管理)
├── templates/ # Go 模板文件,生成 Kubernetes 资源清单
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── _helpers.tpl # 可复用的模板片段(命名模板)
│ └── tests/ # 测试连接的文件
│ └── test-connection.yaml
├── templates/NOTES.txt # 安装后显示的提示信息
├── README.md # Chart 使用说明
└── .helmignore # 打包时忽略的文件模式
| 文件/目录 | 作用 | 合规治理关注点 |
|---|---|---|
Chart.yaml |
定义 Chart 名称、版本、API 版本、应用版本等 | 版本号策略、annotations 可携带合规标签 |
values.yaml |
提供所有可配置参数的默认值 | 默认值必须符合基线安全策略 |
templates/ |
存放 Go 模板,渲染后生成 YAML | 模板中禁止硬编码敏感信息,必须引用 Values |
charts/ |
存放子 Chart 或依赖的 Chart 包 | 依赖的 Chart 也需要通过合规扫描 |
values.schema.json |
对 values.yaml 进行结构校验 | 可强制要求某些字段必须存在且合规 |
Chart.yaml 的 annotations 字段中,可以添加自定义合规元数据,例如 compliance/standard: "pci-dss",便于 OPA 策略在发布时进行匹配和审计。
3.2 模板引擎与模板函数
Helm 使用 Go 的 text/template 引擎,并扩展了 60+ 个模板函数(来自 Sprig 库和内置函数)。模板引擎将 templates/ 目录下的文件与 values.yaml 及命令行传入的值结合,渲染出最终的 Kubernetes YAML。
3.2.1 核心模板语法
| 语法 | 说明 | 示例 |
|---|---|---|
{{ .Values.key }} |
引用 Values 中的值 | image: {{ .Values.image.repository }}:{{ .Values.image.tag }} |
{{- if condition -}} ... {{- end -}} |
条件判断(- 用于消除空白) |
{{- if .Values.ingress.enabled }} ... {{- end }} |
{{- range $i, $v := .Values.list -}} ... {{- end }} |
遍历列表或字典 | {{- range .Values.ports }} - port: {{ . }} {{- end }} |
{{ include "chart.name" . }} |
引用 _helpers.tpl 中定义的命名模板 |
name: {{ include "my-app.fullname" . }} |
{{ .Chart.Name }} |
内置对象,访问 Chart.yaml 中的字段 | app.kubernetes.io/name: {{ .Chart.Name }} |
{{ .Release.Name }} |
内置对象,访问 Release 名称 | app.kubernetes.io/instance: {{ .Release.Name }} |
{{ .Values.rawYaml | nindent 4 }} 这类将用户输入直接注入 YAML 的写法,这可能导致 YAML 注入攻击。OPA 策略应检查模板中是否存在 toYaml、fromYaml 等危险函数的不当使用。
3.2.2 管道与函数链
Helm 模板支持 Unix 风格的管道操作,将前一个函数的输出作为后一个函数的输入,实现数据转换。
# 将 Values 中的字符串转为大写并添加引号
{{ .Values.environment | upper | quote }}
# 默认值处理:如果 .Values.replicas 未定义,则使用 3
replicas: {{ .Values.replicas | default 3 }}
# 缩进控制:将多行字符串缩进 4 个空格
{{ .Values.annotations | toYaml | nindent 4 }}
3.3 Values 文件与配置分层
Values 文件是 Helm 实现配置与模板分离的关键机制。Helm 支持多级 Values 合并,优先级从低到高为:Chart 内置的 values.yaml → 父 Chart 的 Values → helm install -f 指定的文件 → --set 命令行参数。
# values.yaml(Chart 默认值)
replicaCount: 1
image:
repository: nginx
tag: latest
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
# production-values.yaml(生产环境覆盖)
replicaCount: 3
image:
tag: 1.25.0
service:
type: LoadBalancer
# 部署命令:helm install my-release ./my-app -f production-values.yaml --set image.tag=1.25.1
最终渲染时,image.tag 的值为 1.25.1(--set 优先级最高),replicaCount 为 3,service.type 为 LoadBalancer。
3.4 Release 管理
Release 是 Helm 中一个 Chart 实例的部署运行态。每次 helm install 都会创建一个新的 Release,每次 helm upgrade 都会生成一个新的 Revision(修订版本)。
| Helm 命令 | 作用 | Release 状态变化 |
|---|---|---|
helm install |
首次部署 Chart,创建 Release | 从 pending-install → deployed |
helm upgrade |
升级 Release 到新版本 | 旧 Revision 变为 superseded,新 Revision 变为 deployed |
helm rollback |
回滚到之前的 Revision | 目标 Revision 变为 deployed,当前变为 superseded |
helm uninstall |
删除 Release 及其所有资源 | 变为 uninstalled(默认保留历史记录) |
helm list |
列出所有 Release | 显示名称、命名空间、Chart、状态、Revision 等 |
helm install 和 helm upgrade 的 Webhook 中拦截请求,检查 Release 的 values 是否满足安全基线(如禁止 privileged: true、必须设置 resources.limits 等),从而在部署前阻断不合规的 Release。
3.5 内置对象与作用域
Helm 模板中预置了多个内置对象,用于访问 Chart 元数据、Release 信息、Values 和文件内容。理解这些对象的作用域是编写复杂模板的基础。
| 内置对象 | 类型 | 常用字段 |
|---|---|---|
.Chart |
Chart.yaml 内容 | .Name, .Version, .AppVersion, .Annotations |
.Release |
当前 Release 信息 | .Name, .Namespace, .IsInstall, .IsUpgrade, .Revision |
.Values |
合并后的 Values | 所有用户配置和默认值 |
.Files |
Chart 内文件访问 | .Get "filename", .Glob "pattern" |
.Capabilities |
Kubernetes 集群能力 | .APIVersions.Has "apps/v1", .KubeVersion |
.Template |
当前模板信息 | .Name, .BasePath |
$ 变量: 在 range 或 with 块内,当前上下文(.)会改变。要访问根作用域,使用 $.Values、$.Release.Name 等。例如:
{{- range .Values.containers }}
- name: {{ .name }} # 这里的 . 是容器对象
image: {{ $.Values.global.registry }}/{{ .image }} # $.Values 访问根 Values
{{- end }}
3.6 依赖管理与子 Chart
大型应用通常拆分为多个子 Chart。Helm 通过 charts/ 目录或 Chart.yaml 中的 dependencies 字段管理依赖。
# Chart.yaml 中的依赖声明
dependencies:
- name: postgresql
version: "12.1.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled # 条件控制是否安装
tags:
- database
子 Chart 的 Values 可以通过全局值(global 字段)共享配置,也可以被父 Chart 的 Values 覆盖。OPA 策略需要递归检查所有子 Chart 的合规性,因为子 Chart 中的不安全配置同样会引入风险。
helm dependency update 时,会从远程仓库下载 Chart 包。OPA 策略应要求所有依赖的 Chart 来源必须是经过审批的受信任仓库,并检查其 Chart.yaml 中的签名或摘要信息。