Helm
一个 HTTP 服务通常需要 Deployment、Service、ConfigMap,生产环境还会增加 Secret 引用、入口路由和资源限制。Helm 把这些资源模板、默认参数与依赖打包成 Chart,安装后形成命名的 Release。同一个 Chart 可以使用不同参数部署多份应用,各自保留升级历史。
Chart 怎样变成一份运行中的应用
Chart、Release 与三种版本
web/ Chart 源码
├─ Chart.yaml 名称、Chart 版本、应用版本、依赖
├─ values.yaml 默认参数
├─ values.schema.json 参数类型与约束
├─ templates/
│ ├─ _helpers.tpl 共享命名和标签函数
│ ├─ deployment.yaml 应用 Pod 模板
│ ├─ service.yaml 稳定服务入口
│ └─ configmap.yaml 应用配置
├─ charts/ 打包的依赖 Chart(按需)
└─ crds/ 独立安装的 CRD(按需)Chart.yaml.version 决定 Chart 包版本,例如 web-0.1.0.tgz;appVersion 是应用版本说明,只有模板显式读取它时才影响生成内容。镜像的 tag 或 digest 则决定容器运行什么程序。三者应分别保存,不能以为修改 appVersion 就自动更新所有镜像。Charts 规范定义了目录、依赖和版本字段。
Release 由名称与 namespace 定位,如 helm-lab/demo。同一次发布通常产生多个 Kubernetes 对象,Helm 保存其清单和参数,Kubernetes 控制器继续负责 Pod 调度和运行。Helm 适合重复交付同一类应用;只有少量固定 YAML 时,直接使用 kubectl 或 Kustomize也很自然。
Helm 是客户端,使用 kubeconfig 中的身份请求 API,不需要安装 Tiller。拥有安装权限也意味着可能创建 Chart 中的 Job、RBAC 或其他对象;获取 Chart 后应先查看资源内容再运行。
安装固定客户端并确认测试集群
Linux x86-64 普通用户在新的实验目录操作。下载 Helm HTTP 实验包,解压后应看到 web/、values-v2.yaml 和 bad-readiness.yaml。安装二进制到当前目录:
mkdir -p bin
curl -q --fail-with-body -L \
https://get.helm.sh/helm-v4.2.4-linux-amd64.tar.gz -o helm.tar.gz
curl -q --fail-with-body -L \
https://get.helm.sh/helm-v4.2.4-linux-amd64.tar.gz.sha256sum -o helm.sha256sum
printf '%s helm.tar.gz\n' "$(awk '{print $1}' helm.sha256sum)" | sha256sum -c -
tar -xzf helm.tar.gz
install -m 0755 linux-amd64/helm bin/helm
export PATH="$PWD/bin:$PATH"
helm version --short
helm env预期校验 OK、版本 v4.2.4;失败就停止。不同 CPU 架构从官方 Release选择对应包,不混用 amd64 与 arm64。包管理器安装也可用,但 CI 应固定可回找的版本、来源与校验值。
Helm 4.2.x 的 Kubernetes 支持窗口为 1.33—1.36,实验使用 Kubernetes 1.36.4。升级集群或 Helm 前检查版本支持策略,不要默认客户端支持比编译基线更新的集群。
已有测试集群可使用平台发放的受限 kubeconfig;本地操作可按 Kubernetes创建 ops7 并加载 Nginx 镜像。下面让所有写入明确指向该实验集群,KUBECONFIG 改成该实验创建的绝对文件路径:
export KUBECONFIG="/绝对路径/k8s-lab/kubeconfig"
export CTX=kind-ops7
export NS=helm-lab
k() { kubectl --kubeconfig "$KUBECONFIG" --context "$CTX" "$@"; }
h() { helm --kubeconfig "$KUBECONFIG" --kube-context "$CTX" -n "$NS" "$@"; }
k config current-context
k get nodes
k auth can-i create deployments -n "$NS"
k auth can-i create secrets -n "$NS"
k create namespace "$NS"这些变量在新终端需要重新设置。namespace 创建若返回 AlreadyExists,先确认它确为自己的测试空间;若 Forbidden,申请相应授权,不换管理员凭据绕过。Helm 默认将 Release 记录存为目标 namespace 的 Secret,部署账号需要相应能力。
完整 Chart 的首次安装
web/Chart.yaml 使用稳定的 v2 Chart 格式,Helm 4 的实验性 v3 Chart 格式不是本实验依赖:
apiVersion: v2
name: web
type: application
version: 0.1.0
appVersion: "1.30.4"
kubeVersion: ">=1.33.0-0 <1.37.0-0"默认参数:
replicaCount: 2
image:
repository: nginx
tag: "1.30.4-alpine"
message: helm-v1
readinessPath: /readyChart 启动两个 UID 101 的 Nginx 副本,使用只读根与可写临时卷,HTTP 监听 8080;Service 映射 80 到 8080。探针、资源和安全配置与 Kubernetes 实验保持一致。这里的 message 进入受 schema 约束的 Nginx 配置,readinessPath 进入 Pod 探针。
先做本地检查:
helm lint ./web
helm template demo ./web --namespace "$NS" --kube-version 1.36.4预期渲染出 ConfigMap、Service、Deployment。安装时再进行服务端 dry-run,然后执行真实安装:
h install demo ./web --dry-run=server --hide-secret
h install demo ./web --wait=watcher --timeout=2m
h status demo
k -n "$NS" get deployment demo-web
k -n "$NS" exec deployment/demo-web -- wget -qO- http://demo-web/预期 Release 为 deployed,Deployment Ready 为 2/2,请求得到 helm-v1。--wait=watcher 要求 Helm 等待资源状态,--timeout 给等待设置上限;仍须发送请求检查具体应用结果。参数行为见 helm install。
对本地 HTTP 客户端,在单独终端保持:
k -n "$NS" port-forward --address 127.0.0.1 service/demo-web 18081:80本机执行:
curl -q --noproxy '*' --fail-with-body http://127.0.0.1:18081/输出同样为 helm-v1。转发终止或所选 Pod 重建后需要重新建立连接;它是临时调试通路,集群内请求才覆盖 Service/DNS 路径。
模板和参数怎样接入项目
values 合并与类型约束
参数从 Chart 默认值开始,多个 -f 从左向右覆盖,同一类命令行参数重复出现时右侧取胜。映射逐键合并,数组通常整体替换。将默认键设为 null 可在合并时移除它,但模板和 schema 也要接受缺失。
helm template demo ./web --kube-version 1.36.4 \
-f values-v2.yaml --set-string message=command-valuevalues-v2.yaml 设置 message: helm-v2,最后的 --set-string 又覆盖它,所以渲染内容为 command-value。端口、副本等数字用正确类型,版本号、带前导零的标识等用字符串,不能用 YAML 外观猜实际类型。合并与删除规则见 Values Files。
本实验的 values.schema.json 对副本数、消息字符和路径施加约束;以下是副本数部分:
{
"type": "object",
"properties": {
"replicaCount": {
"type": "integer",
"minimum": 1,
"maximum": 5
}
}
}验证错误类型:
helm template demo ./web --kube-version 1.36.4 \
--set-string replicaCount=two应非零退出并指出 replicaCount 类型不符。这个错误发生在创建 Release 前,history 不会因此出现一个新失败 revision。schema 无法验证镜像是否存在或数据库是否能连接,后者需要实际环境检查。
共享命名、作用域与生成的 YAML
模板通过 .Values 读取参数,.Release.Name 获取安装名称,.Chart 获取元数据。with、range 会改变当前点号作用域,需要外层根对象时保存或使用 $。
templates/_helpers.tpl 定义资源名:
{{- define "web.fullname" -}}
{{- printf "%s-web" .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}Deployment、Service selector 和配置引用共同使用它:
metadata:
name: {{ include "web.fullname" . }}
spec:
selector:
matchLabels:
app: {{ include "web.fullname" . }}include 返回字符串,可以继续进入管道;toYaml 序列化映射,nindent 负责 YAML 缩进,quote 输出带引号字符串。例如资源预算可在模板中写:
resources:
{{- toYaml .Values.resources | nindent 2 }}这是说明 resources 块内部缩进的片段,嵌入完整 Deployment 时缩进必须随所在层级调整。模板函数与作用域查 Chart Template Guide,不要仅看模板源码的缩进,还要检查最终渲染 YAML。
普通应用可在 Chart 中接入 ServiceAccount、入口和 Secret 引用;平台 CRD 或集群级权限应单独审查。命名函数使用稳定字段,避免把版本写入 Deployment selector,否则正常升级会遇到不可变字段错误。
配置变化怎样触发新 Pod
ConfigMap 对象更新与应用重新加载配置是不同步骤。实验用 subPath 挂载 Nginx 配置,因此必须重建 Pod。Deployment 模板在 annotation 中记录配置模板的摘要:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}message 改变后,渲染出的 ConfigMap 文本改变,摘要也改变;Pod 模板不同,Deployment 便进行滚动更新。若只改变独立 ConfigMap 而没有修改 Pod 模板,Helm 可能成功结束,但旧进程仍使用旧配置。该方法适合 Chart 自己生成的配置;外部 Secret 轮换需要自己的重启或应用刷新机制。Helm 配置更新技巧提供了 checksum 示例。
生产应用的 values 通常保存资源预算、镜像 digest、入口主机名、非敏感配置与已有 Secret 名称。不要把数据库密码直接写进 Git 中的 values;Secret 的值可能出现在 Release 存储、debug、CI artifact 和失败日志。--hide-secret 只隐藏 dry-run 中的 Secret 对象,不能隐藏误放在 ConfigMap、annotation 或 NOTES 中的秘密。
依赖、仓库和离线交付
Chart.yaml.dependencies 描述子 Chart 的名称、版本约束、仓库以及启用条件。维护者主动更新依赖时运行 helm dependency update 并审阅 Chart.lock;CI 用 helm dependency build 按锁文件恢复。没有依赖的实验 Chart 不需要为了“完整”添加一个数据库子 Chart。
传统 Chart repository 使用 index.yaml 指向包;OCI registry 保存 Chart artifact,二者入口不同:
# 团队提供的可信 HTTP Chart 仓库
helm repo add internal "$CHART_REPO_URL"
helm repo update internal
helm search repo internal/web --versions
helm pull internal/web --version "$CHART_VERSION"
# 本地实验 Chart 打包,无外部依赖
helm package ./web --destination packages
helm show chart packages/web-0.1.0.tgzCHART_REPO_URL、CHART_VERSION 必须从团队仓库配置中取得。查索引有结果后继续检查包是否能下载、依赖是否完整、镜像是否仍可取得。helm package 预期生成 web-0.1.0.tgz,不会同时打包 Nginx 镜像。
采用 OCI 时,管理员提供 REGISTRY 域名、账户和短期令牌;只有明确授权的项目路径可上传:
printf '%s' "$REGISTRY_TOKEN" | helm registry login "$REGISTRY" \
--username "$REGISTRY_USER" --password-stdin
helm push packages/web-0.1.0.tgz "oci://$REGISTRY/charts"
helm pull "oci://$REGISTRY/charts/web" --version 0.1.0
helm registry logout "$REGISTRY"登录用域名而不是带 https:// 的 URL;push 目标不带 Chart 名和版本,Helm 从包元数据获得它们。OCI 行为见官方 registry 说明。已有 Harbor 环境的仓库与身份配置见 Harbor。
内网部署先在受控联网环境准备 CLI、Chart、锁定的依赖、全部容器镜像以及校验文件,再传入内网。管理机拉 Chart 成功与 worker 拉镜像成功要分别检查;helm registry login 的凭据不会自动变成 Pod 的 imagePullSecrets。完全离线可直接安装本地 .tgz,镜像则预装到所有可能调度的节点,或存入可访问的内网镜像仓库。
传统 Chart 的 .prov 可以结合可信公钥执行 helm verify;验证方必须事先确认公钥来源,而不是连包带公钥一起无条件信任。OCI 发布可记录 digest 并采用组织的签名方案。Provenance解释了完整性与签名验证。
升级失败后恢复哪一份状态
显式选择 values 继承方式
应用更新使用 values-v2.yaml,其中只有一项差异:
message: helm-v2升级命令明确重置到新 Chart 默认值,再合并本次文件:
h upgrade demo ./web --reset-values -f values-v2.yaml \
--wait=watcher --timeout=2m --history-max 10
h history demo
h get values demo --all
k -n "$NS" rollout status deployment/demo-web --timeout=120s
k -n "$NS" exec deployment/demo-web -- wget -qO- http://demo-web/新请求应返回 helm-v2。新配置摘要触发了 Pod 更新,history 出现新的 revision。停止旧 port-forward 后重建再检查,避免把仍连着旧 Pod 的转发结果误判为发布状态。
Ready 状态更新与节点转发规则更新存在传播时间。若更新后首次请求超时,先用 wget -T 5 -qO- http://demo-web/ 限定单次等待,并检查 EndpointSlice 中的地址、端口与 ready。可在 30 秒内重新请求;持续失败则比较 Pod 本地端口与 Service 访问,继续排查节点转发和网络策略,不能仅凭 Helm 的 deployed 忽略访问失败。
默认 upgrade 的 values 继承取决于是否传入新值等条件,不适合靠记忆猜测。--reset-values 使用新默认值与本次输入;--reuse-values 继承上次值再叠加输入,可能保留已从 Git 删除的临时修改;--reset-then-reuse-values 先重置再合并旧值和新输入。自动化应明确选择,并把完整环境参数纳入版本控制。helm upgrade列出了优先关系。
一个会进入失败历史的坏探针
bad-readiness.yaml 把 readiness 指到不存在的路径:
message: helm-bad
readinessPath: /missing这次参数类型合法,YAML 也合法,API 可以接收;失败发生在应用就绪阶段。为了观察失败对象,实验先不启用自动回滚:
h upgrade demo ./web --reset-values -f bad-readiness.yaml \
--wait=watcher --timeout=90s
h history demo
k -n "$NS" get rs,pods -l app=demo-web
k -n "$NS" describe deployment demo-web
k -n "$NS" get endpointslice -l kubernetes.io/service-name=demo-web -o yaml预期 upgrade 非零退出,history 留下失败 revision。新 Pod Running 但未就绪,readiness 404;旧的两个可用副本仍被保留。ConfigMap 对象可能已经变为 helm-bad,旧 Pod 因 subPath 继续使用启动时的旧文件。这正是“部分资源已改变,发布尚未完成”的状态。
先在 history 中找到内容为 helm-v2 的成功编号。全新按上述顺序执行时是 revision 2;实际环境必须查询,不直接照抄编号:
h get values demo --revision 2 --all
h rollback demo 2 --wait=watcher --timeout=2m
h history demo
k -n "$NS" exec deployment/demo-web -- wget -qO- http://demo-web/预期再次返回 helm-v2。rollback 创建一个新的 revision,内容来自选择的历史记录,不会把历史编号倒退。具体参数见 helm rollback。
revision 1:安装 helm-v1
revision 2:升级 helm-v2
revision 3:坏探针,failed
revision 4:回滚到 revision 2 的内容,deployed上述状态序列要求从空 Release 开始且没有插入其他 upgrade。渲染前失败、API 请求失败和就绪等待失败不一定留下相同历史,诊断要结合发生阶段。
自动恢复、Hook 和数据库变化
普通流水线可以启用:
h upgrade demo ./web --reset-values -f values-v2.yaml \
--wait=watcher --timeout=2m --rollback-on-failure --history-max 10Helm 4 的 --rollback-on-failure 在 upgrade 失败时尝试恢复先前成功版本;首次 install 失败则清理安装。Helm 3 的对应选项是 --atomic。超时控制单项操作的等待,不是整个发布及恢复的绝对总耗时。恢复后仍应保留原发布失败结果,检查 history、资源与实际请求。Helm 4 变更说明还列出了 SSA 和插件机制变化。
Hook 可在 pre/post install、upgrade、rollback、delete 等阶段运行 Job。对于 Job/Pod Hook,Helm 等待任务完成;其他 Hook 资源按相应创建处理,并非等待所有对象具有同一种 Ready。迁移 Job 应幂等,有超时和清理策略,例如:
metadata:
annotations:
helm.sh/hook: pre-upgrade
helm.sh/hook-weight: "-10"
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
spec:
ttlSecondsAfterFinished: 300Hook 不按普通 Release 资源跟踪,卸载应用后可能留下 Job 或其他对象;失败日志也可能被 TTL 清理,需要提前收集。Chart Hooks说明了排序和删除策略。需要发布后请求测试时可使用 helm test 的测试 Hook,但 Helm install/upgrade 不会自动代替你执行这组业务测试。
数据库 DDL、已消费的消息和外部 API 写入发生在 Kubernetes 对象之外。应用回滚后仍要能读取新旧数据结构,因此先做兼容性迁移,再发布读取新结构的版本,最后在确认回退窗口结束后清除旧结构。把迁移脚本塞进 pre-upgrade Job 不会让它自动获得可逆性。
CRD 与普通资源的不同生命周期
crds/ 中的 CRD 不做模板渲染,安装时先于依赖它的资源创建;Helm 不负责自动升级或删除这些 CRD。控制器、CRD schema、已有 Custom Resource 和 conversion webhook 应有独立的兼容检查。CRD 最佳实践解释了这个保守策略。
CRD 缺失会导致 no matches for kind。先查看 helm show crds 与 kubectl api-resources,确认平台已经提供所需 API,再安装应用。不要在普通 namespace 发布账号中随意授予创建集群 CRD 的权限。删除 CRD 还会影响该类型的自定义资源,不能作为清理失败 Release 的常规方法。
从渲染、API 到运行状态排查
模板正确但集群拒绝
本地 lint/template 主要检查 Chart 和渲染;--dry-run=server 可以连接集群执行 discovery/lookup 等流程,但不要把 Helm 的 dry-run 直接等同于完整的 Kubernetes admission 验证。对已经存在相关 CRD 的目标集群,可另做:
umask 077
helm template demo ./web --namespace "$NS" --kube-version 1.36.4 > rendered.yaml
k -n "$NS" apply --server-side --dry-run=server -f rendered.yaml这会让 API Server 校验资源而不持久化。使用 kubectl 的字段管理者仍可能与实际 Helm 不同,Webhook、配额和并发变化也要求真实安装再检查。渲染文件可能包含秘密,不公开上传;用完删除这个明确文件。
遇到 YAML 错误先查看报错模板与 nindent;Forbidden 查当前身份和资源动词;no matches for kind 查 API/CRD;不可变字段错误比较 selector、Service 类型和存储关联。不要直接加 --force-replace,它可能删除重建资源并引起中断。
所有权冲突与重复发布
同名对象可能属于另一 Release,也可能由 GitOps 或 kubectl 管理。先检查:
k -n "$NS" get deployment demo-web -o yaml --show-managed-fields
h get manifest demo
h get values demo --allHelm 的 Release 归属与 SSA 的字段归属是不同层次。Helm 4 新安装默认使用 Server-Side Apply;升级或回滚默认沿用该 Release 之前的 apply 方法,因此旧 Helm 3 Release 不会仅因换客户端立即转为 SSA。
--take-ownership 跳过 Helm 的归属校验,不会停止旧控制器;--force-conflicts 处理字段冲突也可能覆盖其他写入者。迁移前先确定谁以后维护对象,暂停旧调和,比较不可变字段并保留恢复方案。GitOps 管理的资源通过其声明库修复,避免临时 Helm 命令与自动同步持续争抢。
同一 Release 应串行发布。出现 pending-upgrade 时先确认是否还有真实 Helm 进程或流水线执行,检查 Hook、事件和网络中断,不直接删除 Release Secret“解锁”。
等待超时后的定位顺序
h status demo
h history demo
h get hooks demo
k -n "$NS" get pods,jobs
k -n "$NS" get events --sort-by=.metadata.creationTimestamp
k -n "$NS" logs deployment/demo-web --tail=100| 观察 | 优先检查与恢复 |
|---|---|
| Hook Job 未结束 | Job Pod 日志、依赖、重试与幂等;先判断外部操作是否已经完成 |
| Pod Pending | requests、亲和性、taint、PVC;为新副本留容量 |
| ImagePullBackOff | 镜像、节点 CA/网络与 imagePullSecrets;Chart 仓库凭据不管这一层 |
| Pod Running 不 Ready | 探针路径、端口、实际响应和应用配置 |
| 回滚失败 | 目标历史是否存在、旧镜像能否拉取、API 是否仍支持、Hook 是否阻塞 |
| Release deployed 但应用异常 | Service/入口、应用日志、数据库兼容与业务指标 |
故障版本的 values 与 manifest 可用 --revision 查询,但可能含秘密,保存到受控目录。只保留 Release 历史仍不足以重建应用:旧镜像、Chart、依赖、配置引用和必要的数据恢复材料也必须可取得。
历史太多会增加 Secret/etcd 存储,--history-max 应覆盖团队实际回退窗口。不能为清理空间直接删掉所有 Helm Secret;发布记录消失后,Helm 将失去相应历史和管理信息。各存储驱动与权限见 Helm RBAC。
卸载与交还资源
实验结束先停止 port-forward,再查看本 Release 的对象与 Hook:
h get hooks demo
h uninstall demo --wait --timeout=2m
h list --all
k -n "$NS" get deployment,service,configmap,secret,job,pvc该示例无 Hook、CRD 或 PVC,应用资源应消失,namespace 中可能仍有 Kubernetes 自己维护的对象。默认 uninstall 删除 Release 历史;--keep-history 会保留历史,不能与保留业务资源混淆。helm uninstall说明了删除选项。
一般 Chart 的 Hook、resource-policy: keep 对象、CRD、某些由控制器产生的 PVC 或外部副作用可能保留。是否删除 PVC 要检查 Chart 资源与存储回收策略,不应一概声称“Helm 永远保留 PVC”。
确认 helm-lab 仅含自己的实验对象后:
k delete namespace "$NS"namespace 长期 Terminating 时查仍存对象和 finalizer 对应控制器,先恢复其清理能力。不要直接移除 finalizer,让后端存储或外部资源失去管理。
权威资料与规范地址
安装、兼容与参数化
- Helm 4.2.4:https://github.com/helm/helm/releases/tag/v4.2.4
- 版本支持:https://helm.sh/docs/topics/version_skew/
- Chart 目录与 schema:https://helm.sh/docs/topics/charts/
- Values 合并:https://helm.sh/docs/chart_template_guide/values_files/
- 模板语言:https://helm.sh/docs/chart_template_guide/
- 配置更新技巧:https://helm.sh/docs/howto/charts_tips_and_tricks/
发布与恢复
- install:https://helm.sh/docs/helm/helm_install/
- upgrade:https://helm.sh/docs/helm/helm_upgrade/
- rollback:https://helm.sh/docs/helm/helm_rollback/
- uninstall:https://helm.sh/docs/helm/helm_uninstall/
- Helm 4 变化:https://helm.sh/docs/overview/
- Hook:https://helm.sh/docs/topics/charts_hooks/
- CRD:https://helm.sh/docs/chart_best_practices/custom_resource_definitions/
分发与权限
- OCI registry:https://helm.sh/docs/topics/registries/
- Provenance:https://helm.sh/docs/topics/provenance/
- RBAC:https://helm.sh/docs/topics/rbac/
