Helm 自定义 Chart 开发与版本管控(适配 K8s 1.33)
作为 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: http
5.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、多环境配置),核心逻辑不变 —— 模板复用、配置可覆盖、版本可管控。
更多推荐
所有评论(0)