深色模式
Helm 仓库与版本管理
摘要:本文面向需要把 Chart 分发给多团队、或要把 Chart 纳入企业制品库的平台工程师。覆盖经典
index.yaml仓库、OCI 注册中心(Helm 3.8+ GA)、依赖管理、GPG 签名与版本号规则,并对比两种分发模型在生产中的取舍。
适用版本与前提
- Helm:3.x(OCI 支持自 Helm 3.8 起 GA;本文以 3.14+ 为准)
- 注册中心:支持 OCI 的任意镜像仓库(如 Harbor、ECR、GAR、ACR、Docker Hub)
- 前提:已能本地
helm package出.tgz
背景与问题
写完 Chart 只是第一步。真正的工程问题是:Chart 如何安全、可追溯地分发给多个团队,并保证"生产跑的就是某个确定的版本"。这涉及三件事:
- 分发:Chart 放在哪、怎么被
helm install拉到(经典仓库 vs OCI)。 - 版本:chart 版本与 app 版本如何演进、如何保证不可变。
- 可信:如何确认拉到的 Chart 没被篡改(签名 / provenance)。
不可变性的边界
经典 Chart 仓库的 index.yaml 允许同一 version 被"覆盖"(取决于仓库服务器实现),而 OCI 注册中心的 tag 虽可覆盖但digest 不可变。生产上若要做到真正不可变,应始终用 oci://...@sha256: 或锁定 chart 的 digest,而非仅锁定 tag。
经典 Chart 仓库(index.yaml 模型)
经典仓库本质是一个静态 HTTP 服务,根目录放一个 index.yaml,列出所有 Chart 及其版本与下载 URL。客户端用 helm repo 子命令交互:
bash
# 添加仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
# 更新本地缓存的 index
helm repo update
# 搜索
helm search repo bitnami/nginx
# 拉取但不安装,查看文件
helm pull bitnami/nginx --version 17.0.0 --untar1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
经典仓库的优点是生态成熟、工具链完整(ChartMuseum、Artifactory 均支持);缺点是它是"文件服务器"语义,没有原生的不可变保证,且 index.yaml 需维护。
OCI 注册中心(推荐用于新项目)
Helm 3.8+ 把 Chart 作为 OCI artifact 推送到标准容器镜像仓库,复用镜像仓库的鉴权、不可变 tag、签名能力。命令以 oci:// 协议前缀:
bash
# 1) 先打包
helm package ./mychart # 产出 mychart-0.1.0.tgz
# 2) 登录 OCI 仓库(host 仅写域名,不带 scheme/path)
helm registry login -u $USER harbor.example.com
# 3) 推送
helm push mychart-0.1.0.tgz oci://harbor.example.com/helm-charts
# 产出示例:Pushed: harbor.example.com/helm-charts/mychart:0.1.0
# Digest: sha256:ec5f08ee...
# 4) 用 digest 安装(最安全,不可变)
helm install myapp oci://harbor.example.com/helm-charts/mychart@sha256:ec5f08ee... \
--namespace prod1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
helm pull / show / template / install / upgrade 均支持 oci://。注意:helm push 的引用不能带 basename 与 tag(由 chart 名与 version 推断),而下载类命令需要带 basename。
用 tag 还是 digest?
tag(如 :0.1.0)可读但可被覆盖;digest(:@sha256:...)不可变但不可读。生产发布用 digest 锁定,内部文档/口头沟通用 tag。OCI 同时提供两者,是最佳实践组合。
两种分发模型对比
| 维度 | 经典仓库 | OCI 仓库 |
|---|---|---|
| 协议/存储 | HTTP + index.yaml | OCI artifact,复用镜像仓库 |
| 不可变性 | 取决于服务器 | digest 天然不可变 |
| 鉴权 | 基本认证/代理 | 复用镜像仓库凭证(更统一) |
| 签名 | GPG provenance(.prov) | sigstore(helm-sigstore 插件) |
| 适用 | 既有 ChartMuseum 等存量 | 新项目、统一制品治理 |
版本管理:chart 版本 vs app 版本
version(chart 版本):SemVer 2,每次发布必须递增,是 Helm release revision 的标记。它追踪"打包方式"的变化。appVersion:被打包应用的版本,信息性,不参与 Helm 版本计算,允许非 SemVer。kubeVersion:声明兼容的 K8s 版本范围(如">= 1.25.0"),安装时强制校验。
生产危险
切勿用 latest 这类浮动 tag 作为 Chart/镜像版本。GitOps 的核心原则之一是"desired state 必须版本化且不可变",浮动 tag 会导致无法回滚到确定状态。Helm 自身 chart 版本强约束 SemVer,但应用镜像 tag 仍需你自己在 values 里写死。
依赖管理
Chart 可在 Chart.yaml 的 dependencies 中声明子 Chart,用 helm dependency update 拉取(经典仓库)或 oci:// 引用(OCI):
yaml
dependencies:
- name: redis
version: "17.0.0"
repository: "https://charts.bitnami.com/bitnami" # 或 "oci://harbor.example.com/helm-charts"
condition: redis.enabled1
2
3
4
5
2
3
4
5
bash
helm dependency update ./mychart # 拉取依赖到 charts/ 并生成 Chart.lock
helm dependency build ./mychart # 依据 lock 重建1
2
2
Chart.lock 锁定依赖的确切版本,应提交进 Git,保证可复现构建。
签名与来源可信(Provenance)
经典仓库支持 GPG 签名生成 .prov 文件;OCI 可配合 sigstore(helm-sigstore 插件)。helm install 时可加 --verify 校验 provenance:
bash
helm package --sign --key 'mykey' --keyring ~/.gnupg/secring.gpg ./mychart
helm install myapp ./mychart-0.1.0.tgz --verify1
2
2
版本相关
--verify 依赖 GPG keyring;在 Helm 3 中 keyring 路径与 GPG 2.x 的 keybox 格式需匹配,部分环境存在兼容问题,生产落地前需实测签名校验链路。
生产实践
- 新项目统一用 OCI,利用镜像仓库的鉴权/IAM 与不可变 tag,减少独立仓库运维。
- 发布锁定 digest,文档记录 tag,发布单里同时写
tag与digest。 Chart.lock进 Git,依赖可复现。- Chart 升级与 app 升级分开评审:改模板(
version递增)和改镜像(appVersion/values)是两类变更。 - CI 中
helm package后做 lint + 签名,再推送,避免把问题 Chart 入库。
故障排查
helm repo update后仍拉不到新版本:本地index.yaml缓存未刷新,或仓库服务器尚未重新生成 index;可rm ~/.cache/helm/repository/*强制刷新。- OCI 推送报 "repository/namespace must be created":部分注册中心要求先建好 project/namespace,非 Helm 问题。
- 依赖解析报版本冲突:检查
Chart.lock与dependencies是否一致,必要时删lock重建。
FAQ
Q:经典仓库会被废弃吗? A:截至 Helm 3.14,两者均官方支持。OCI 是推荐方向(与镜像治理统一),但经典仓库在存量生态中仍广泛使用,短期不会被移除。
Q:chart 版本能用 1.0.0-beta.1 这种预发版本吗? A:可以,SemVer 2 支持预发布与 build metadata,但注意 SemVer 排序下预发版本低于正式版本,自动升级策略需考虑这一点。