Helm 基础回顾:Chart 结构、模板引擎、Values 与 Release 概念
在云原生供应链中,Helm 是 Kubernetes 应用打包与部署的事实标准。理解 Helm 的核心抽象——Chart、模板引擎、Values 与 Release——是后续进行镜像签名注入、冷启动削峰配置的基础。本节从供应链视角重新梳理这些概念,并聚焦于它们如何影响部署时的镜像拉取与签名验证流程。
1. Chart 目录结构与供应链元数据
一个标准的 Helm Chart 是一个遵循特定布局的目录集合。除了传统的 Kubernetes 资源模板外,供应链安全要求我们在 Chart 中携带签名、摘要和策略元数据。
| 文件/目录 | 用途 | 供应链安全关注点 |
|---|---|---|
Chart.yaml |
Chart 元数据(名称、版本、依赖) | 声明 annotations 字段记录签名算法与策略版本 |
values.yaml |
默认配置值 | 定义镜像仓库地址、摘要(digest)、签名公钥引用 |
templates/ |
Go 模板文件,渲染后生成 Kubernetes 清单 | 注入 Cosign 验证注解、镜像摘要替换逻辑 |
charts/ |
子 Chart 依赖(如适用) | 递归验证子 Chart 的签名完整性 |
.helmignore |
打包时排除的文件模式 | 确保不排除 .sig 或 .att 签名文件 |
供应链实践:在
Chart.yaml 的 annotations 中增加 cosign.signature.algorithm: sha256 和 cosign.policy.required: true,使 Chart 自身成为可验证的签名载体。
2. 模板引擎与镜像引用注入
Helm 使用 Go 模板引擎将 Values 中的参数动态注入到 Kubernetes 资源中。在镜像供应链场景下,模板引擎的核心职责是:将抽象的镜像名称解析为包含摘要(digest)的不可变引用,并附加签名验证注解。
# values.yaml 中的镜像定义
image:
repository: registry.example.com/app
tag: v1.2.3
digest: sha256:a1b2c3d4e5f6...
cosign:
enabled: true
keyRef: k8s://namespace/cosign-public-key
# templates/deployment.yaml 中的模板片段
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}@{{ .Values.image.digest }}"
{{- if .Values.image.cosign.enabled }}
env:
- name: COSIGN_KEY_REF
value: "{{ .Values.image.cosign.keyRef }}"
{{- end }}
冷启动陷阱:避免在模板中使用
latest 标签或动态 tag(如 {{ .Values.image.tag }})。标签可变性会导致签名验证失败,且无法利用镜像层缓存进行削峰。始终优先使用 @digest 格式。
3. Values 分层与签名策略注入
Values 支持多层覆盖:默认值(values.yaml)→ 父 Chart 值 → 用户提供的 --set 或 -f 文件。这种分层机制允许我们在不同环境(开发、预发、生产)注入不同的签名策略。
| Values 层级 | 覆盖优先级 | 典型签名策略配置 |
|---|---|---|
values.yaml(Chart 内建) |
最低 | 默认关闭签名验证,或指向开发签名密钥 |
values-production.yaml |
中 | 强制开启 Cosign 验证,指定生产公钥 |
--set 命令行参数 |
最高 | 临时覆盖镜像摘要或密钥引用(用于应急回滚) |
4. Release 生命周期与签名状态绑定
Release 是 Chart 的一次部署实例。每个 Release 都有唯一的名称和修订版本(revision)。在供应链上下文中,Release 的修订历史应当与镜像签名的版本一一对应。
- 安装(install):首次部署时,Helm 记录 Release 的签名策略快照。
- 升级(upgrade):更新镜像摘要或签名密钥时,Helm 创建新 revision,旧 revision 保留签名历史。
- 回滚(rollback):回滚到旧 revision 时,自动恢复对应的签名策略和镜像摘要。
- 卸载(uninstall):清理 Release 时,可选择保留签名审计日志。
削峰关联:通过 Helm 的
--atomic 和 --wait 参数,可以在部署失败时自动回滚,避免因签名验证失败导致 Pod 反复 CrashLoopBackOff,从而减少镜像仓库的无效拉取请求(冷启动削峰的关键手段之一)。
5. 核心概念对比:Chart、Values、Release 与模板
下表从定义、生命周期、供应链角色三个维度对比 Helm 的四大核心概念,帮助建立清晰的认知边界。
| 概念 | 定义 | 生命周期 | 供应链角色 |
|---|---|---|---|
| Chart | Kubernetes 资源的打包模板集合 | 开发期 → 打包 → 分发(Chart Museum / OCI 仓库) | 签名元数据载体,镜像摘要的声明来源 |
| Values | Chart 的配置参数,支持分层覆盖 | 随 Chart 分发,部署时由用户覆盖 | 注入镜像仓库地址、摘要、签名公钥引用 |
| Release | Chart 的一次部署实例,包含修订历史 | 安装 → 升级 → 回滚 → 卸载 | 绑定签名策略快照,提供可审计的部署链 |
| 模板引擎 | Go 模板系统,将 Values 渲染为 Kubernetes 清单 | 每次 helm install/upgrade 时执行 | 将镜像名称解析为不可变摘要,注入验证注解 |
6. 模板函数与镜像摘要解析
Helm 内置了丰富的模板函数,在供应链场景中,digest 解析和 quote 处理是最常用的。以下是一个生产级模板片段,展示如何安全地构造镜像引用并注入 Cosign 注解:
{{- /* 安全构造镜像引用:优先使用 digest,回退到 tag */ -}}
{{- $imageRepo := .Values.image.repository -}}
{{- $imageDigest := .Values.image.digest | default "" -}}
{{- $imageTag := .Values.image.tag | default "latest" -}}
{{- if $imageDigest }}
{{- $imageRef := printf "%s@%s" $imageRepo $imageDigest -}}
{{- else }}
{{- $imageRef := printf "%s:%s" $imageRepo $imageTag -}}
{{- /* 生产环境警告:缺少 digest 可能导致签名验证失败 */ -}}
{{- end }}
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
cosign.sigstore.dev/image-ref: {{ $imageRef | quote }}
cosign.sigstore.dev/verified: "true"
spec:
template:
spec:
containers:
- name: {{ .Chart.Name }}
image: {{ $imageRef }}
削峰技巧:在模板中使用
digest 而非 tag 可以确保 kubelet 在拉取镜像时直接命中镜像层缓存(因为 digest 唯一且不可变),避免因 tag 更新导致的全量层重新拉取,从而降低镜像仓库的并发压力。
7. 常见陷阱与供应链最佳实践
- 陷阱:在模板中使用
.Values.image.tag而不指定 digest —— 导致镜像引用可变,签名验证失败,且无法利用层缓存。 - 陷阱:忽略
.helmignore文件 —— 打包时可能排除.sig或.att签名文件,导致 Chart 分发后签名丢失。 - 最佳实践:在
values.yaml中为每个环境定义独立的digest和cosign.keyRef—— 实现环境隔离的签名策略。 - 最佳实践:使用
helm lint --strict和helm template --validate—— 在部署前验证模板渲染结果和签名注解的正确性。 - 最佳实践:将 Chart 打包为 OCI 制品并签名 —— 使用
helm push配合 Cosign 对 Chart 本身进行签名,形成完整的供应链信任链。
本节小结:Helm 的 Chart 结构、模板引擎、Values 分层和 Release 生命周期共同构成了镜像供应链的部署基础。通过将镜像摘要(digest)和 Cosign 签名策略注入到模板和 Values 中,我们可以在部署阶段实现不可变引用和自动签名验证,这是后续章节实现冷启动削峰的前提条件。