news 2026/10/9 11:07:51

Helm 3.10实战:从手工YAML到模板化部署与回滚

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Helm 3.10实战:从手工YAML到模板化部署与回滚

1. 为什么最终选择Helm管理应用:手工YAML到模板化的不归路

先说一个很常见的场景:团队里最开始部署 Kubernetes 应用,基本靠 git 仓库里堆一大堆 YAML。大家心照不宣地把deployment.yaml、service.yaml、configmap.yaml一个个kubectl apply -f丢上去,一个应用也就是三五份文件,看着没什么问题。但等应用多起来,你就会发现这套做法开始不对劲了。

首先是环境差异。同一个应用要部署到 dev、staging、prod,唯一的区别可能就是镜像 tag、副本数、资源配置,但这样就要复制三份 YAML。一旦改了一次环境变量或者加了一个探针,你就要同步改三个文件,漏一个就是事故。其次是升级和回滚。手工kubectl apply没有版本之间的概念,改错了只能靠眼睛找问题,再想办法改回去。再往后,如果要做应用的多实例部署,比如每个租户一套独立环境,手写 YAML 的做法基本等于宣告结束。

Helm 解决的就是这个问题。它把你那一堆 Kubernetes 清单文件打包成一个整体——也就是 Chart,机制上叫模板化渲染:把可变的部分变成变量(Values),不变的部分写成模板。部署的时候,Helm 根据你提供的 values 动态生成一份完整的 YAML,再提交给 Kubernetes。这相当于从"每次手工改文件"进化到"把文件变成可配置的工程"。

除此之外,Helm 自带release 版本追踪。每次helm install、helm upgrade都会生成一个 revision 记录,你可以随时回滚到任意历史版本。这一点我在后面专门讲,因为它是整个工具最值得依赖的特性。

所以这篇文章我打算从零开始,用 Helm 3.10 跑一遍完整的流程:安装、部署 Nginx、改配置、升级、回滚,再到排查常见问题。整篇内容偏实战,都是我自己在项目里用过的命令和踩过的坑,适合正在从纯 kubectl 转向 Helm 的运维和开发同学参考。

2. 环境准备:Helm 3.10安装、集群权限和chart仓库配置

2.1 安装Helm 3.10:别再用旧版本的习惯操作

先强调一个前提:现在的 Helm 3 和 Helm 2 是完全不同的形态。Helm 2 需要在集群里安装 Tiller,这玩意有严重的权限问题,所以 Helm 3 直接去掉了 Tiller。你现在搜"helm 3.10下载",建议直接去 GitHub releases 页面找对应的二进制包,或者用包管理器装。下面是我在 Linux 服务器上的安装方式:

# 下载 Helm 3.10.x 二进制包,假设是 amd64 Linux wget https://get.helm.sh/helm-v3.10.3-linux-amd64.tar.gz tar -zxvf helm-v3.10.3-linux-amd64.tar.gz mv linux-amd64/helm /usr/local/bin/helm helm version

如果你在 Mac 上开发,那直接brew install helm就行。Windows 用户用 chocolatey 或者 scoop 也可以。装完验证一下:

helm version

输出类似version.BuildInfo{Version:"v3.10.3", ...}就说明装好了。这个版本比较稳定,兼容 Kubernetes 1.25 以下的集群没什么太大问题。如果你集群版本比较高,建议用更新的 Helm 3.x。

安装本身没什么难度,真正容易踩坑的是权限。Helm 3 里所有的操作都靠你在~/.kube/config里提供的 kubeconfig 凭证。也就是说,你在 kubectl 里能做什么,Helm 就能做什么。所以装完以后先检查集群连通性:

kubectl cluster-info

如果能正常输出集群地址和版本信息,再执行helm env看看 Helm 的配置目录。这里我遇到过一个尴尬的情况:用户明明有集群权限,但kubectl能读到的 context 不对,导致 Helm 找不到集群。排查方法是检查当前 context:

kubectl config current-context

确认这个 context 指向的是你想操作的环境。不要在混乱的 kubeconfig 里同时开着多个 context,否则你很容易把应用装到错误的集群上。

2.2 添加并搜索Chart仓库:找到需要的Nginx Chart

Helm 的应用包目录叫Chart 仓库,类似 apt 或 yum 的软件源。你可以用官方维护的 Artifact HUB 搜索,也可以直接添加常见的 chart 仓库。先从 Bitnami 仓库开始,它维护了一堆常用应用的 Chart,质量比较高:

helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update

更新之后,可以搜索一下 nginx 相关的 Chart:

helm search repo nginx

这个命令会列出仓库里所有名字包含 nginx 的图表。你可以注意到,光是 Bitnami 仓库里就有nginx和nginx-ingress-controller,它们完全是不同的角色。前者是一个常规的 Nginx Web Server,后者是 Ingress Controller,千万别选错。我一开始为了测试,就直接装了一个nginx普通应用,用来验证安装流程。

这里也顺便说一句:生产环境建议先确认 chart 的版本和你的 Kubernetes 版本兼容性。你可以在搜索结果的APP VERSION列看到对应应用版本,在CHART VERSION看到 Helm Chart 自身版本。始终有个习惯,安装前先查阅它的 values.yaml,了解默认配置和可调参数,后面我们升级的时候才能不出错。

2.3 理解 Helm 的 Releases 和命名空间绑定

在安装之前,建议把 Helm 的几个核心概念理顺,不然直接上手会迷路:

  • Chart:一个打包好的应用描述,里面包含了模板、默认 values 和元信息。
  • Release:Chart 的一次实际部署实例。同一个 Chart 可以装上多个 Release,比如nginx-web和nginx-api,它们是独立管理的。
  • 版本(Revision):Release 的每一次升级都会生成新的版本号,用来回滚和追踪变更。

Helm 3 默认把 release 的状态信息存储在一个同名的 Secret 对象里。所以你会发现,用helm list -A时,命名空间下会有额外的 Secret,这是正常的。这也解释了一个限制:release 和它的命名空间是绑定的。你安装时用-n指定命名空间,后续的升级、回滚、查询都必须带上同样的命名空间,否则 Helm 会找不到 release。

helm list -n dev

如果你忘了 release 装在哪里,可以用helm list -A查看所有命名空间的 release。我以前在测试机装了好几个 demo,最后全忘了,就是靠-A才找回来的。

3. 部署一个真实应用:Nginx从零开始的完整流程

3.1 安装Nginx:一行命令背后的实际改动

现在开始实战。我们用 Bitnami 的 nginx chart 部署一个简单的 Web 服务:

helm install nginx-demo bitnami/nginx -n default

如果一切正常,它会输出说明,包括 release 名字、命名空间,以及如何访问应用。这时候你可能会好奇:这一行命令到底做了什么?

过程拆解下来大概是这样的:

  1. Helm 从本地缓存中读取 chart 包(刚才repo update已经把缓存下载到~/.cache/helm/repository/)。
  2. 将 chart 里的模板文件结合默认的 values.yaml 渲染成最终的 Kubernetes 资源清单。
  3. 调用 Kubernetes API 创建对应的 Deployment、Service、ConfigMap 等对象。
  4. 在 default 命名空间创建 release 相关的 Secret 信息,记录当前 release 的状态和配置。

你可以验证一下资源是否都创建出来了:

kubectl get pods -n default kubectl get svc nginx-demo -n default

你会发现生成的 Deployment 名称带了随机后缀,这是 Bitnami chart 的命名规则。如果用helm list看到 release 状态是deployed,说明安装成功。

3.2 查看Nginx对外访问地址:修改Service类型和暴露端口

默认的 Bitnami nginx chart 创建的是 ClusterIP 类型的 Service,只能在集群内部访问。如果你要测试外部访问,可以把它改成 NodePort:

kubectl edit svc nginx-demo

把type: ClusterIP改成type: NodePort,然后看节点端口:

kubectl get svc nginx-demo

实际上,更合理的做法是安装的时候直接传参。Helm 支持通过--set参数生效,例如:

helm upgrade nginx-demo bitnami/nginx --set service.type=NodePort

看到没?这里我直接用了upgrade而不是install。Helm 里update也可以用于修改现有 release 的配置。其实安装一个已经存在的 release,install会报错,upgrade可以复用这个名字。后面升级还会详细讲。

如果你只是临时想看看 Nginx 的模样,使用kubectl port-forward更简单:

kubectl port-forward svc/nginx-demo 8080:80

然后在浏览器打开http://localhost:8080。这个方式不修改任何 Service 类型,最适合本地调试。

3.3 把配置写成values.yaml:比--set更好维护的方式

刚开始你可能会图省事,想把所有参数都用--set传,比如:

helm install nginx-demo bitnami/nginx --set replicaCount=3 --set service.type=NodePort

但这样做的问题是:配置项一多,命令行根本没法看历史,也没法 review。我更推荐维护一个自定义的 values 文件,例如在项目目录下建一个my-values.yaml:

replicaCount: 3 service: type: NodePort port: 80 resources: limits: cpu: 250m memory: 256Mi requests: cpu: 100m memory: 128Mi

然后执行:

helm install nginx-demo bitnami/nginx -f my-values.yaml -n default

这样变更记录全都在 Git 里,代码评审的时候可以清晰地看到改了哪些配置。后来我把这套实践扩展成"每个环境一个 values 文件":dev-values.yaml、prod-values.yaml,它们之间有少量覆盖,再配合 Helm 的层级特性,就能满足多环境部署。

4. 升级、回滚和版本管理:Helm的revision机制

4.1 升级的本质:修改Values后的重新渲染

部署完一个应用不等于结束,后续一定会改镜像 tag、改副本数、改环境变量。这时候 Helm 的核心优势就体现出来了。我仍然用刚才的 nginx-demo 示例,现在想把副本数从默认值改成 3,同时更新镜像版本(假设该 chart 的 appVersion 支持,你可以通过--set image.tag调整),执行:

helm upgrade nginx-demo bitnami/nginx -f my-values.yaml --set replicaCount=3

这里我用了--set覆盖 values 文件里的值。注意执行完 upgrade 后,Helm 会把这次变更记录为新的 revision。你可以查看 release 的所有版本记录:

helm history nginx-demo

输出会列出 REVISION、UPDATE TIME、STATUS、CHART、APP VERSION、DESCRIPTION。你会看到1和2两条状态,第二条的 STATUS 是deployed,第一条则变为superseded,表示已经被新版本取代。这个机制特别强大,它意味着你可以回到应用历史上任意一个状态。

升级之前,建议先用helm diff upgrade(需要安装 helm-diff 插件)或者helm template来预览将要渲染出来的 YAML。我常用的是:

helm template nginx-demo bitnami/nginx -f my-values.yaml > preview.yaml

渲染后 diff 一下,看看会不会引入意外的资源变化。不过helm template不会真的提交到集群,只输出到文件,所以很安全。也可以先 dry-run:

helm upgrade nginx-demo bitnami/nginx -f my-values.yaml --dry-run --debug

这个命令会比helm template多提供一个信息:Helm 会告诉你"这个 release 将执行哪些操作"。实测下来,生产环境的升级前我至少会跑一次--dry-run,不然改坏了只能重新回滚,容易产生中间抖动。

4.2 回滚:从revision 2回到revision 1的完整操作

回滚是 Helm 最值得用的功能之一。比如刚才那次升级把配置改错了,导致 Pod 启动不了。你会先确认新版确实有问题:

kubectl get pods -n default

如果 Pod 状态不是Running,那赶紧回滚:

helm rollback nginx-demo 1

这个命令的含义是:把 releasenginx-demo回滚到revision 1。执行完再helm history nginx-demo,你会发现多了一个 revision 3,状态是deployed,它的内容等同于 revision 1。注意:Helm 的回滚不是真的删除当前版本,而是基于历史版本重新渲染并提交一个新版本。所以历史记录仍然存在,这才是正确的设计思路。

回滚唯一需要注意的点是:如果你升级之后跑了一段时间,集群里有些资源被人工kubectl edit改过,回滚可能把这些人工改动覆盖掉。所以团队协作时要明确:release 命名空间内的 Kubernetes 资源,不要用 kubectl 直接篡改,一切通过 Helm 管理。一旦绕过 Helm 直接改资源,Helm 根本不知道,下次升级会把你的手工改动全部冲掉。

4.3 自定义values文件的版本迁移策略

等到 chart 版本升级时,values 文件的字段可能发生变化。比如旧的自定义 values 里写了service.nodePort,新 chart 可能改成了service.extraFields。升级 chart 版本时,如果直接执行helm upgrade -f old-values.yaml,很可能因为字段不匹配报错或者被忽略。

这时候一定要看升级前后的 release manifest。常用的做法是先helm get values nginx-demo看看当前的用户自定义值,再对比新 chart 的默认 values:

helm show values bitnami/nginx --version <新的chart版本>

把项目 values 文件同步成新结构,再执行升级。另一个技巧是:升级比较大的版本前,通常 chart 作者会提供 migration guide,多看 release notes。Bitnami 的 chart 一般在升级说明里列出 breaking changes,这可能包括存储路径变化、Service 端口变化等。

5. 排查实战:我最常遇到的五个Helm问题

5.1 错误的release已经存在:install变成upgrade

一个常见的报错:

Error: release: nginx-demo already exists

原因很简单:之前安装过同名 release,但你忘了。解决方案有两个:如果你想彻底删掉重装,先卸载:

helm uninstall nginx-demo

如果只是想重新覆盖配置,那用helm upgrade而不是install。对于 CI/CD 流水线,我会写成一个幂等逻辑:先判断是否存在 release,存在就 upgrade,不存在就 install。具体可以这样:

helm upgrade nginx-demo bitnami/nginx -f my-values.yaml --install --force

--install参数会让upgrade在 release 不存在时自动执行安装,很便捷。--force会在集群版本变化导致仅代码变化时强制替换资源,但要注意--force实际上通过删除并重建资源的方式实现,可能引起短暂不可用,慎用。

5.2 找不到chart仓库或仓库未更新

报错manifest not found或者chart download failed时,绝大多数是仓库索引过期了。先执行:

helm repo update

如果还是找不到,检查 repo 是否添加:

helm repo list

有时候你手动改了本地/etc/hosts或者公司网络限速,会导致仓库下载超时。可以把仓库里的 chart 先拉到本地:

helm pull bitnami/nginx --version <chart version> --untar

pull 到本地后,后续使用helm install nginx-demo ./nginx安装本地目录,就不依赖仓库网络了。

5.3 升级卡死或hang住:查看pending状态

有时你执行helm upgrade后,它卡在半路,或者最终状态显示:

STATUS: pending-upgrade

这通常意味着上一次 upgrade 还没有完成,可能是集群资源创建超时、webhook 卡住、或者你执行命令的客户端断开了。此时不能继续upgrade,因为会报另一个错误。先检查集群实际资源状态:

kubectl get deploy,pods -n default

如果资源正常,可以尝试强制完成这次升级:

helm upgrade nginx-demo bitnami/nginx -f my-values.yaml --history-max 10

但这可能因为当前 release 状态 locked 而失败。更稳妥的办法是直接查询 release 的秘密对象,了解里面记录的状态:

kubectl get secret -n default -l owner=helm kubectl describe secret sh.helm.release.v1.nginx-demo.v2 -n default

如果确定没有实际资源变更,或者集群资源已存在,可以直接修复状态。有一种相对干净的手段是把 release 的 status 字段改回failed或deployed,但我不建议在生产上乱改 secret。多数情况下,问题出在 chart 中的资源创建卡在某处,排查对应资源即可。

5.4 values文件里的值是正常类型,但渲染报错

有个很自然的错误:在 values.yaml 里写了端口数字,但模板里期望的是字符串。比如:

service: port: 80

而模板中使用了{{ .Values.service.port | quote }},Helm 会尝试把整数 80 转换成字符串 "80";如果不加quote,就可能在某些字段(如容器端口)渲染成不带引号的数字,Kubernetes API 通常可以接受数字,但遇到 template 里拼接字符串的场景就出问题。

解决办法是遵循模板里对值类型的期望。如果你不确定,打开 chart 的templates目录看看相关模板,或者用helm template看渲染结果。多跑几次渲染,对比输出,很快就能定位。

5.5 升级后Pod没有真正更新

你升级了镜像 tag,但是 Pod 仍然使用旧镜像。常见原因是:Helm 只更新你提供的 values 里的值,如果 deployment 模板中的镜像 tag 是根据某个固定值渲染的,默认值可能没变。很多 chart 的 image.tag 默认使用AppVersion,你需要显式指定:

helm upgrade nginx-demo bitnami/nginx --set image.tag=latest

还有一种是 Deployment 的strategy是Recreate或滚动策略设置过大,导致 Pod 长时间不重建。确认是否更新可以看:

kubectl rollout status deploy/nginx-demo -n default

如果显示等待,等它完成即可。另一个原因是你在helm get manifest nginx-demo里看到了镜像更新,但kubectl get deployment -o yaml没有变化,那八成是 chart 的模板里有条件判断,你设的值没走通那个分支。这种时候就老老实实去读 chart 的模板代码。

6. 进阶思路:自写chart模板和应用发布流程

6.1 从零开始写一个最小Chart

当你要发布自己的应用时,使用公共 chart 可能并不合适。自己写一个 Chart 其实没那么复杂。首先创建骨架:

helm create myapp

这个命令会生成一个标准结构的 Chart:

myapp/ ├── Chart.yaml ├── charts/ # 存放依赖的子 chart ├── templates/ # 所有 Kubernetes 资源模板 │ ├── deployment.yaml │ ├── service.yaml │ ├── serviceaccount.yaml │ ├── _helpers.tpl │ └── ... └── values.yaml # 默认配置

Chart.yaml是元信息文件,至少填写apiVersion,name,version,appVersion。对于 Helm 3,apiVersion 为v2。下面是一个最简单的示例:

apiVersion: v2 name: myapp description: A simple Helm chart for my app type: application version: 0.1.0 appVersion: "1.16.0"

删除helm create生成的过多示例文件,保留一个 deployment.yaml 和一个 service.yaml,然后自定义。在templates/deployment.yaml里,你可以用{{ .Values.replicaCount }}的方式替换副本数,用{{ .Values.image.repository }}:{{ .Values.image.tag }}组合镜像。

6.2 理解模板渲染:_helpers.tpl和include的作用

写 Chart 的入门难点之一是_helpers.tpl。很多初学者不理解为什么 Helm 要把 name 和 labels 抽成一个 define 块,而不是直接在模板里写死变量。

原因有两个:一是 K8s 资源名称要求字母、数字等有限字符,如果 release name 或 chart name 包含.或者长度超限,直接用会报错;二是组件直接要共享一致的标签,用于 Service 选择器和 Deployment 匹配。_helpers.tpl里的 define 块相当于一个通用函数,比如:

{{- define "mychart.fullname" -}} {{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }} {{- end -}}

这样你在 deployment.yaml 和 service.yaml 里都可以通过:

name: {{ include "mychart.fullname" . }}

引用同一个名称,避免两处手写不一致。刚开始你可能觉得多此一举,但一旦你在多个文件里用到同样的标签,就会明白这个抽象的价值。

6.3 编写values阶层的多环境配置

为了让一套 chart 适配 dev/prod 环境,除了每个环境独立 values 文件,还可以使用 Chart 的values.yaml中的层级结构和global字段。比如全局配置里定义:

global: imageRegistry: "registry.example.com" image: repository: ""

然后模板里引用:

image: {{ .Values.global.imageRegistry }}/{{ .Values.image.repository }}:{{ .Values.image.tag }}

每个环境的 values 文件只需覆盖image.repository和image.tag,仓库域名统一由global控制。这个设计在多个子 chart 或微服务场景下特别有用,避免重复写仓库地址。

6.4 使用CI流水线做发布实战:Chart版本号与自动回滚

当你开始用 Helm 做应用发布,必须解决好两个问题:Chart 版本号怎么管理?失败时怎么自动回滚?

我目前的做法是在 CI 流程里,每次更改代码后构建新的镜像 tag,然后用这个 tag 作为 Chart 的 appVersion 或 image.tag 传入 Helm 升级命令。同时让 CI 在升级前把当前 release 的 revision 记录下来,如果升级后健康检查失败,就执行回滚:

PREVIOUS_REVISION=$(helm history myapp -n production | awk 'NR==2{print $1}') helm upgrade myapp ./chart -n production --atomic --set image.tag=$CI_PIPELINE_IID

--atomic是个关键参数,它会在升级失败时自动回滚到上一个 revision,但要注意--atomic依赖超时设置,默认 5 分钟。它只会在超时及失败时回滚,所以通常配合--timeout 2m使用:

helm upgrade myapp ./chart -n production --atomic --timeout 2m --set image.tag=$CI_PIPELINE_IID

我实测遇到过一次问题:--atomic回滚时因为某资源删除卡住,最终 rollback 也失败。所以更保险的做法是升级脚本里先记录 revision,失败后手动回滚,并提前检查是否有 incoming webhook 等卡点。后来我在流水线里把回滚步骤放到了专门的异常处理阶段,不再依赖--atomic到底执行到哪一步。

总的来说,Helm 这套体系,核心价值不是帮你省写 YAML 的几行字,而是把 Kubernetes 应用交付变成了"可配置、可记录、可回滚、可自动化"的工程化管理。你越早把应用交给 Helm 管理,后面版本升级和发布时越省力。我从刚开始的helm install nginx-demo到管理几十个微服务 chart,只花了两周时间适应,但从此再也不想回到纯 kubectl 时代了。建议你现在就装一个 Helm,拉一个公共 chart 试试安装和升级,亲自感受一次回滚的快乐,比读再多的教程都管用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 11:07:45

Coding Agent 生产级调优:Harness 工程实战与效果提升

1. 从 Vibe Coding 到生产可用&#xff1a;一个 Coding Agent 调优项目的真实起点Vibe Coding 这个词这两年被聊得很多&#xff0c;大意就是“凭感觉写代码”——你给 AI 一个模糊的意图&#xff0c;它帮你把代码补全、把功能搭起来&#xff0c;你只需要在关键节点上做判断。听…

作者头像 李华
网站建设 2026/10/9 11:05:33

OpenWorkMate:开源企业级AI工作伙伴框架,让AI真正能干活

1. 从"只会聊天"到"能干活"&#xff1a;企业AI工作伙伴到底缺了什么公司里那套AI工具&#xff0c;我用了快两年&#xff0c;最大的感受就一个字&#xff1a;虚。你问它"帮我写个周报"&#xff0c;它能给你整出八百字排比句&#xff1b;你问它&qu…

作者头像 李华
网站建设 2026/10/9 11:05:28

2026软件测试面试MySQL核心考点与避坑指南

MySQL 在软件测试面试里&#xff0c;权重一直不低。不管你是面功能测试还是测开&#xff0c;SQL 基础、索引原理、事务隔离级别、甚至死锁排查&#xff0c;都可能是面试官手里的“常规牌”。尤其这两年行业里卷得厉害&#xff0c;光会 select * from table 已经糊弄不过去了&am…

作者头像 李华
网站建设 2026/10/9 11:05:27

MySQL时间函数匹配实战:从格式化到索引优化避坑指南

做后端开发这些年&#xff0c;凡是涉及统计报表、定时任务、数据对账的话&#xff0c;十有八九都要跟 SQL 时间函数匹配打交道。MySQL 里的日期时间函数不算少&#xff0c;但真正用得上的、也最容易出幺蛾子的&#xff0c;基本上就是那套“格式化、转换、加减、求差、比较”的组…

作者头像 李华
网站建设 2026/10/9 11:04:34

数据透视图实操:从数据规范到切片器联动全指南

做数据分析的人都知道&#xff0c;透视表是查数看数的神器。不过今天我想聊的是它的孪生兄弟——数据透视图。很多人学会了透视表&#xff0c;但做透视图时还是用最土的办法&#xff1a;选中原始数据直接插入图表&#xff0c;结果一刷新新增的数据根本不显示&#xff0c;要么就…

作者头像 李华