作为 10 年运维专家,先把核心逻辑捋清楚,再给落地步骤和可直接跑的案例 —— 全程说人话,不堆砌术语,适配 K8s 1.33 的特性(比如废弃的 API 都规避掉)。
一、核心技术逻辑:先搞懂 Helm 到底在干嘛
1. Helm 的本质
Helm 是 K8s 的包管理器,把 K8s 的 YAML 配置(Deployment、Service、Ingress 等)打包成一个「Chart」(相当于 Linux 的 rpm/deb 包),解决:
- 零散 YAML 不好管理的问题;
- 环境差异化配置(开发 / 测试 / 生产);
- 版本追溯、回滚、升级的管控;
- 一键部署 / 卸载,不用手动改 YAML。
2. Chart 的核心逻辑
一个 Chart 就是一个目录结构,核心是「模板 + 配置」:
- 模板(templates):带变量的 K8s YAML 文件(比如镜像版本、副本数用变量 {{.Values.xxx}} 代替);
- 配置(values.yaml):模板变量的默认值,部署时可通过
-f或--set覆盖; - 元数据(Chart.yaml):Chart 的版本、名称、依赖、适配 K8s 版本等核心信息(关键:要适配 1.33)。
3. 版本管控的核心逻辑
Helm 的版本管控分两层:
- Chart 版本:Chart.yaml 里的
version(语义化版本,比如 1.0.0、1.0.1),对应 Chart 包的迭代; - Release 版本:Helm 部署 Chart 后生成的 Release(比如部署 myapp-1.0.0 生成 release myapp-v1),Helm 会记录每个 Release 的配置,支持回滚(
helm rollback); - 配合仓库(Chart Repository):把打好的 Chart 包推到仓库(比如 Harbor、ChartMuseum),实现版本归档和团队共享。
4. K8s 1.33 适配要点
1.33 版本主要废弃 / 变更的 API 要规避:
- Ingress:必须用
networking.k8s.io/v1(v1beta1 早已废弃); - StatefulSet/Deployment:用
apps/v1(没问题,1.33 仍支持); - PodSecurityPolicy(PSP)已完全移除,改用 Pod Security Standards(PSS)+ Pod Security Admission(PSA);
- 其他核心 API(Service、ConfigMap、Secret)无变更,正常用
v1。
二、自定义 Chart 开发:详细操作步骤
步骤 1:环境准备(适配 1.33)
先确认 Helm 版本(建议 3.14+,适配 1.33):
# 安装Helm 3.14+(Linux示例) curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash # 验证版本 helm version # 输出v3.14.x即可 # 验证K8s集群(1.33) kubectl version --short # 确保Server Version是v1.33.x步骤 2:初始化 Chart 骨架
Helm 提供create命令生成标准目录结构,不用手动建:
# 创建名为myapp的Chart(自定义Chart的核心目录) helm create myapp生成的目录结构(重点标★):
myapp/ ├── Chart.yaml ★ Chart元数据(版本、名称、K8s适配) ├── values.yaml ★ 模板默认配置(镜像、副本数、端口等) ├── charts/ ★ 依赖的其他Chart(比如redis、mysql) ├── templates/ ★ 核心模板目录(K8s资源YAML) │ ├── deployment.yaml ★ 部署模板 │ ├── service.yaml ★ 服务模板 │ ├── ingress.yaml ★ 入口模板(适配1.33) │ ├── _helpers.tpl ★ 辅助函数(变量复用) │ ├── NOTES.txt ★ 部署后提示信息 └── .helmignore ★ 忽略文件(类似.gitignore)步骤 3:定制 Chart 元数据(Chart.yaml)
核心是适配 K8s 1.33,示例如下(注释讲清楚每一项):
apiVersion: v2 # Helm Chart的API版本(v2是通用版,v1是旧版) name: myapp # Chart名称(全局唯一) description: A simple web app Chart for K8s 1.33 # 描述 type: application # 类型(application/库chart) # Chart版本(语义化:主版本.次版本.补丁,比如1.0.0) # 迭代规则:主版本(大改)、次版本(新增功能)、补丁(bug修复) version: 1.0.0 # App版本(对应业务应用的版本,比如v1.0.0) appVersion: "v1.0.0" # 适配的K8s版本(1.33.x),避免部署到不兼容的集群 kubeVersion: ">=1.33.0 <1.34.0" # 可选:依赖(比如需要redis) dependencies: - name: redis version: 17.3.1 repository: https://charts.bitnami.com/bitnami condition: redis.enabled # 条件启用步骤 4:定制默认配置(values.yaml)
核心是「默认值 + 可覆盖」,适配 1.33 的 Ingress,示例如下:
# 全局配置(可被依赖Chart继承) global: namespace: myapp # 默认命名空间 # 部署配置 deployment: replicas: 2 # 默认副本数 strategy: type: RollingUpdate # 滚动更新(1.33支持) rollingUpdate: maxSurge: 1 maxUnavailable: 0 pod: # 容器配置 containers: name: myapp-web image: nginx:1.25-alpine # 基础镜像(1.33兼容) imagePullPolicy: IfNotPresent ports: - containerPort: 80 name: http # 资源限制(避免资源抢占) resources: limits: cpu: 500m memory: 512Mi requests: cpu: 100m memory: 256Mi # 健康检查(1.33推荐配置) livenessProbe: httpGet: path: / port: http initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: / port: http initialDelaySeconds: 5 periodSeconds: 5 # PSS适配(替代PSP,1.33必用) securityContext: runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 # Service配置 service: type: ClusterIP # 类型(ClusterIP/NodePort/LoadBalancer) port: 80 targetPort: http # Ingress配置(适配1.33的networking.k8s.io/v1) ingress: enabled: true className: nginx # Ingress Controller类名(需提前部署nginx-ingress) annotations: nginx.ingress.kubernetes.io/rewrite-target: / hosts: - host: myapp.example.com paths: - path: / pathType: Prefix # 1.33必填(Prefix/Exact/ImplementationSpecific) tls: false # 暂时关闭TLS,生产可开启 # 依赖配置(redis) redis: enabled: false # 默认不启用 auth: enabled: true步骤 5:定制模板(templates/)
模板是「带变量的 K8s YAML」,核心是复用 values.yaml 的配置,适配 1.33:
5.1 Deployment 模板(deployment.yaml)
apiVersion: apps/v1 # 1.33支持 kind: Deployment metadata: name: {{ .Release.Name }}-myapp # Release名称+固定后缀(避免冲突) namespace: {{ .Values.global.namespace }} labels: app: {{ .Chart.Name }} version: {{ .Chart.AppVersion }} spec: replicas: {{ .Values.deployment.replicas }} strategy: {{- toYaml .Values.deployment.strategy | nindent 4 }} # 复用values的更新策略 selector: matchLabels: app: {{ .Chart.Name }} template: metadata: labels: app: {{ .Chart.Name }} spec: securityContext: {{- toYaml .Values.deployment.pod.securityContext | nindent 8 }} containers: - name: {{ .Values.deployment.pod.containers.name }} image: {{ .Values.deployment.pod.containers.image }} imagePullPolicy: {{ .Values.deployment.pod.containers.imagePullPolicy }} ports: {{- toYaml .Values.deployment.pod.containers.ports | nindent 12 }} resources: {{- toYaml .Values.deployment.pod.containers.resources | nindent 12 }} livenessProbe: {{- toYaml .Values.deployment.pod.containers.livenessProbe | nindent 12 }} readinessProbe: {{- toYaml .Values.deployment.pod.containers.readinessProbe | nindent 12 }}5.2 Service 模板(service.yaml)
apiVersion: v1 # 1.33支持 kind: Service metadata: name: {{ .Release.Name }}-myapp-service namespace: {{ .Values.global.namespace }} labels: app: {{ .Chart.Name }} spec: type: {{ .Values.service.type }} selector: app: {{ .Chart.Name }} ports: - port: {{ .Values.service.port }} targetPort: {{ .Values.service.targetPort }} protocol: TCP name: http5.3 Ingress 模板(ingress.yaml,适配 1.33)
重点:必须用networking.k8s.io/v1,pathType 必填:
{{- if .Values.ingress.enabled }} # 条件渲染(enabled为true才生成) apiVersion: networking.k8s.io/v1 # 1.33唯一支持的版本 kind: Ingress metadata: name: {{ .Release.Name }}-myapp-ingress namespace: {{ .Values.global.namespace }} annotations: {{- toYaml .Values.ingress.annotations | nindent 4 }} spec: ingressClassName: {{ .Values.ingress.className }} rules: {{- range .Values.ingress.hosts }} # 循环渲染多个host - host: {{ .host }} http: paths: {{- range .paths }} - path: {{ .path }} pathType: {{ .pathType }} # 1.33必填 backend: service: name: {{ $.Release.Name }}-myapp-service # 引用Service名称 port: number: {{ $.Values.service.port }} {{- end }} {{- end }} {{- if .Values.ingress.tls }} # TLS配置 tls: {{- toYaml .Values.ingress.tls | nindent 4 }} {{- end }} {{- end }}步骤 6:模板校验(避免语法错误)
开发完模板后,先校验语法和适配性:
# 1. 检查Chart语法(核心) helm lint myapp/ # 2. 渲染模板(看最终生成的YAML,不部署) helm template myapp/ --namespace myapp # 3. 模拟部署(dry-run,检查K8s 1.33兼容性) helm install myapp-test myapp/ --namespace myapp --create-namespace --dry-run如果报错,优先看:
- API 版本是否正确(比如 Ingress 用 networking.k8s.io/v1);
- 变量是否存在(比如 {{.Values.xxx}} 有没有在 values.yaml 定义);
- K8s 1.33 的特性是否兼容(比如 pathType 必填)。
三、版本管控:从打包到仓库全流程
步骤 1:Chart 打包(版本固化)
把 Chart 目录打成 tgz 包,版本对应 Chart.yaml 里的 version:
# 打包(生成myapp-1.0.0.tgz) helm package myapp/ # 查看包信息 helm show chart myapp-1.0.0.tgz步骤 2:搭建 Chart 仓库(团队共享)
推荐用 Harbor(自带 Chart 仓库)或 ChartMuseum,这里用 ChartMuseum 快速搭建(适配 1.33):
# 1. 部署ChartMuseum(用Helm本身部署) helm repo add chartmuseum https://chartmuseum.github.io/charts helm install chartmuseum chartmuseum/chartmuseum \ --namespace chartmuseum \ --create-namespace \ --set env.open.DISABLE_API=false # 开启API(允许推送) # 2. 获取ChartMuseum地址 kubectl get svc -n chartmuseum chartmuseum-chartmuseum -o jsonpath='{.spec.clusterIP}' # 假设地址是10.96.0.100:8080步骤 3:推送 Chart 到仓库(版本归档)
用cm-push插件推送(需先安装):
# 安装cm-push插件 helm plugin install https://github.com/chartmuseum/helm-push.git # 添加仓库到Helm helm repo add myrepo http://10.96.0.100:8080 # 推送包到仓库(版本1.0.0) helm cm-push myapp-1.0.0.tgz myrepo # 刷新仓库 helm repo update myrepo # 查看仓库里的Chart版本 helm search repo myrepo/myapp步骤 4:部署指定版本(版本管控核心)
部署时指定版本,避免随意升级:
# 部署1.0.0版本 helm install myapp vmyrepo/myapp --version 1.0.0 \ --namespace myapp \ --create-namespace \ # 覆盖默认配置(比如生产环境副本数3) --set deployment.replicas=3 \ --set ingress.hosts[0].host=myapp.prod.example.com # 查看Release版本 helm list -n myapp # 输出示例:NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION # myapp myapp 1 2025-12-15 10:00:00 deployed myapp-1.0.0 v1.0.0步骤 5:版本升级 / 回滚(运维核心操作)
5.1 版本升级(比如迭代到 1.0.1)
- 修改 Chart.yaml 的 version 为 1.0.1,更新功能(比如增加资源限制);
- 重新打包:
helm package myapp/; - 推送新版本:
helm cm-push myapp-1.0.1.tgz myrepo; - 升级 Release:
helm upgrade myapp myrepo/myapp --version 1.0.1 -n myapp \ --set deployment.replicas=4 # 同时覆盖配置5.2 版本回滚(升级出问题时)
Helm 会记录每个 Release 的版本(REVISION),回滚到上一版本:
# 查看Release历史 helm history myapp -n myapp # 输出示例:REVISION UPDATED STATUS CHART DESCRIPTION # 1 2025-12-15 10:00:00 superseded myapp-1.0.0 Install complete # 2 2025-12-15 10:10:00 deployed myapp-1.0.1 Upgrade complete # 回滚到REVISION 1(1.0.0版本) helm rollback myapp 1 -n myapp # 验证回滚结果 helm status myapp -n myapp步骤 6:版本清理(避免冗余)
# 卸载Release(保留Chart版本) helm uninstall myapp -n myapp # 从仓库删除指定Chart版本(1.0.0) curl -X DELETE http://10.96.0.100:8080/api/charts/myapp/1.0.0 # 清理本地Chart缓存 helm repo remove myrepo rm -rf myapp-1.0.0.tgz myapp-1.0.1.tgz四、完整案例:部署一个 Nginx Web 应用(适配 1.33)
案例目标
开发一个 myapp Chart,部署 Nginx 应用,支持:
- 自定义副本数、镜像版本;
- Ingress 访问(myapp.example.com);
- 版本升级(1.0.0→1.0.1);
- 版本回滚。
前置条件
- K8s 1.33 集群已部署 nginx-ingress Controller(Ingress 需要);
- Helm 3.14 + 已安装;
- 本地 hosts 配置:
集群节点IP myapp.example.com。
步骤 1:创建并定制 Chart
# 1. 创建Chart helm create myapp # 2. 修改Chart.yaml(按前面的示例,version=1.0.0,kubeVersion=>=1.33.0) # 3. 修改values.yaml(按前面的示例,镜像用nginx:1.25-alpine,副本数2) # 4. 校验模板 helm lint myapp/ helm template myapp/ --namespace myapp步骤 2:部署 1.0.0 版本
# 1. 创建命名空间 kubectl create namespace myapp # 2. 部署Release helm install myapp myapp/ -n myapp \ --set ingress.hosts[0].host=myapp.example.com \ --set deployment.replicas=2 # 3. 验证部署 helm status myapp -n myapp kubectl get pods -n myapp # 应该有2个nginx pod kubectl get ingress -n myapp # Ingress已创建 curl myapp.example.com # 应该返回Nginx默认页面步骤 3:升级到 1.0.1 版本
# 1. 修改Chart.yaml,version改为1.0.1,appVersion改为v1.0.1 # 2. 修改values.yaml,镜像改为nginx:1.26-alpine,副本数3 # 3. 打包并推送(这里用本地测试,不用仓库) helm package myapp/ # 4. 升级Release helm upgrade myapp myapp-1.0.1.tgz -n myapp \ --set deployment.replicas=3 # 5. 验证升级 helm status myapp -n myapp # 显示REVISION=2,CHART=myapp-1.0.1 kubectl get pods -n myapp # 3个pod,镜像为1.26-alpine curl myapp.example.com # 仍返回Nginx页面步骤 4:回滚到 1.0.0 版本
# 1. 查看Release历史 helm history myapp -n myapp # 2. 回滚到REVISION=1 helm rollback myapp 1 -n myapp # 3. 验证回滚 helm status myapp -n myapp # 显示REVISION=3,CHART=myapp-1.0.0 kubectl get pods -n myapp # 2个pod,镜像为1.25-alpine步骤 5:卸载 Release
helm uninstall myapp -n myapp kubectl delete namespace myapp五、核心总结(运维视角)
- Chart 开发核心:模板 + 配置分离,适配 K8s 1.33 的 API 版本(尤其是 Ingress);
- 版本管控核心:Chart 版本(包迭代)+ Release 版本(部署迭代),通过仓库归档,支持升级 / 回滚;
- 避坑点:
- 不要硬编码 K8s 资源名称,用 {{.Release.Name}} 避免冲突;
- 必须校验模板(helm lint/helm template),避免部署时出错;
- K8s 1.33 的 Ingress 必须用 networking.k8s.io/v1,pathType 必填;
- 版本号严格遵循语义化,便于团队协作和追溯。
可以基于这个框架,扩展到更复杂的场景(比如 StatefulSet、ConfigMap/Secret、多环境配置),核心逻辑不变 —— 模板复用、配置可覆盖、版本可管控。