0%

Helm Chart 开发指南:从入门到生产就绪

Helm Chart 开发指南:从入门到生产就绪

写在前面:这篇文章源于今晚(2026-03-10)的 Helm Chart 开发实战。我们为 OpenClaw 创建了完整的 Helm Chart,支持多环境配置、 Harbor 发布和一键部署。


一、为什么选择 Helm?

1.1 真实痛点

没有 Helm 时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 部署 OpenClaw 需要执行 10+ 条命令
kubectl create configmap openclaw-config --from-file=openclaw.json
kubectl create secret generic openclaw-secrets --from-literal=...
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml
kubectl apply -f rbac.yaml
...

# 升级时更痛苦
# 1. 手动修改每个 YAML 文件
# 2. 逐个 apply
# 3. 验证是否成功
# 4. 回滚?手动改回去

有了 Helm 后

1
2
3
4
5
6
7
8
9
10
11
# 一键部署
helm install openclaw ./openclaw-chart -n openclaw

# 一键升级
helm upgrade openclaw ./openclaw-chart -n openclaw --set image.tag=1.0.4

# 一键回滚
helm rollback openclaw 1 -n openclaw

# 查看状态
helm status openclaw -n openclaw

1.2 Helm 的核心价值

模板化

  • 一套 Chart,多环境复用
  • 参数化配置,避免硬编码

版本管理

  • Chart 有版本号(SemVer)
  • Release 有修订历史
  • 支持回滚到任意版本

依赖管理

  • Chart 可以依赖其他 Chart
  • 自动安装依赖
  • 版本锁定

生态丰富

  • Artifact Hub 有海量 Chart
  • 企业可以搭建私有仓库(Harbor)

二、Chart 结构详解

2.1 标准目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
openclaw/
├── Chart.yaml # Chart 元数据(必需)
├── values.yaml # 默认配置值(必需)
├── values-prod.yaml # 生产环境配置(可选)
├── values-staging.yaml # 测试环境配置(可选)
├── .helmignore # 忽略文件(可选)
├── charts/ # 依赖的 Charts(可选)
└── templates/ # Kubernetes 模板(必需)
├── _helpers.tpl # 模板辅助函数
├── deployment.yaml
├── service.yaml
├── configmap.yaml
├── secret.yaml
├── serviceaccount.yaml
├── rbac.yaml
└── ingress.yaml

2.2 Chart.yaml 详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: v2  # Helm v3 使用 v2
name: openclaw # Chart 名称
description: OpenClaw AI Agent - K8s 部署 Chart
type: application # 应用类型
version: 1.0.0 # Chart 版本(SemVer)
appVersion: "1.0.3-feishu" # 应用版本
keywords:
- ai
- agent
- openclaw
- kubernetes
maintainers:
- name: John
email: john@example.com
url: https://blog.sharezone.cn
dependencies: # 依赖其他 Chart
- name: postgresql
version: "10.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
- name: redis
version: "17.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled

关键字段说明

  • apiVersion: Helm v3 必须是 v2
  • version: Chart 版本号,遵循 SemVer
  • appVersion: 应用版本号,通常对应 Docker 镜像 tag
  • dependencies: 依赖的其他 Chart

2.3 values.yaml 详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# 副本数
replicaCount: 1

# 镜像配置
image:
repository: hb.test/crystalforge/openclaw-cn-base
tag: "1.0.3-feishu"
pullPolicy: IfNotPresent
pullSecrets: [] # Harbor 认证

# 服务配置
service:
type: ClusterIP
port: 18789
targetPort: 18789

# 资源配置
resources:
limits:
cpu: 2000m
memory: 4Gi
requests:
cpu: 500m
memory: 2Gi

# 健康检查
livenessProbe:
httpGet:
path: /health
port: 18789
initialDelaySeconds: 60
periodSeconds: 30

readinessProbe:
httpGet:
path: /ready
port: 18789
initialDelaySeconds: 15
periodSeconds: 15

# 持久化存储
persistence:
enabled: true
storageClass: "csi-cephfs-sc"
size: 50Gi
accessModes:
- ReadWriteMany

# 环境变量
env:
TZ: "Asia/Shanghai"
OPENCLAW_HOME: "/root/.openclaw"

# 密钥(从 Secret 读取)
secrets:
feishu:
appId: ""
appSecret: ""
dashscope:
apiKey: ""

# 依赖配置
postgresql:
enabled: false
redis:
enabled: false

# Ingress 配置
ingress:
enabled: false
className: "nginx"
hosts:
- host: openclaw.example.com
paths:
- path: /
pathType: ImplementationSpecific
tls: []

2.4 多环境配置

values-staging.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 测试环境配置
replicaCount: 1

image:
tag: "1.0.3-feishu"

resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 250m
memory: 1Gi

persistence:
size: 20Gi

ingress:
enabled: true
hosts:
- host: openclaw-staging.example.com

values-prod.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 生产环境配置
replicaCount: 2 # 高可用

image:
tag: "1.0.3-feishu"

resources:
limits:
cpu: 4000m
memory: 8Gi
requests:
cpu: 1000m
memory: 4Gi

persistence:
size: 100Gi # 更多存储

ingress:
enabled: true
hosts:
- host: openclaw.example.com
tls:
- secretName: openclaw-tls
hosts:
- openclaw.example.com

三、模板开发实战

3.1 _helpers.tpl 辅助函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
{{/*
展开 Chart 名称
*/}}
{{- define "openclaw.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
创建完整的 Chart 名称(包含版本)
*/}}
{{- define "openclaw.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
创建标准标签
*/}}
{{- define "openclaw.labels" -}}
helm.sh/chart: {{ include "openclaw.chart" . }}
{{ include "openclaw.selectorLabels" . }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
选择器标签
*/}}
{{- define "openclaw.selectorLabels" -}}
app.kubernetes.io/name: {{ include "openclaw.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
创建 ServiceAccount 名称
*/}}
{{- define "openclaw.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "openclaw.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

3.2 deployment.yaml 模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "openclaw.fullname" . }}
labels:
{{- include "openclaw.labels" . | nindent 4 }}
annotations:
description: "OpenClaw Gateway - AI 助手服务"
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "openclaw.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "openclaw.selectorLabels" . | nindent 8 }}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "18790"
spec:
serviceAccountName: {{ include "openclaw.serviceAccountName" . }}

{{- with .Values.image.pullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}

containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}

ports:
- name: gateway
containerPort: {{ .Values.service.port }}
protocol: TCP
- name: metrics
containerPort: 18790
protocol: TCP

env:
- name: TZ
value: {{ .Values.env.TZ | quote }}
- name: OPENCLAW_HOME
value: {{ .Values.env.OPENCLAW_HOME | quote }}
{{- range $key, $value := .Values.secrets }}
{{- range $subKey, $subValue := $value }}
- name: {{ $key | upper }}_{{ $subKey | upper }}
valueFrom:
secretKeyRef:
name: {{ include "openclaw.fullname" $ }}-secrets
key: {{ $key }}-{{ $subKey }}
{{- end }}
{{- end }}

{{- with .Values.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}

{{- with .Values.readinessProbe }}
readinessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}

resources:
{{- toYaml .Values.resources | nindent 12 }}

volumeMounts:
- name: config-volume
mountPath: /root/.openclaw
subPath: config
- name: workspace-volume
mountPath: /openclaw/workspace
subPath: workspace

volumes:
- name: config-volume
persistentVolumeClaim:
claimName: {{ include "openclaw.fullname" . }}-config-pvc
- name: workspace-volume
persistentVolumeClaim:
claimName: {{ include "openclaw.fullname" . }}-workspace-pvc

{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}

{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}

{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

3.3 service.yaml 模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: Service
metadata:
name: {{ include "openclaw.fullname" . }}
labels:
{{- include "openclaw.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.targetPort }}
protocol: TCP
name: gateway
- port: 18790
targetPort: 18790
protocol: TCP
name: metrics
selector:
{{- include "openclaw.selectorLabels" . | nindent 4 }}

3.4 secret.yaml 模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{{- if .Values.secrets }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "openclaw.fullname" . }}-secrets
labels:
{{- include "openclaw.labels" . | nindent 4 }}
type: Opaque
stringData:
{{- range $key, $value := .Values.secrets }}
{{- range $subKey, $subValue := $value }}
{{ $key }}-{{ $subKey }}: {{ $subValue | quote }}
{{- end }}
{{- end }}
{{- end }}

四、Harbor 发布流程

4.1 打包 Chart

1
2
3
4
5
6
7
# 验证 Chart
helm lint ./openclaw

# 打包
helm package ./openclaw --version 1.0.0 --app-version "1.0.3-feishu"

# 输出:openclaw-1.0.0.tgz

4.2 推送到 Harbor

1
2
3
4
5
6
7
8
9
10
11
12
13
# 登录 Harbor
helm registry login hb.test \
--username crystalcreator \
--password 'glpat-FxE8Ka5HaApPLHnAQDtz'

# 添加仓库
helm repo add harbor oci://hb.test/crystalforge

# 推送 Chart
helm push openclaw-1.0.0.tgz harbor

# 验证
helm search repo harbor/openclaw

4.3 从 Harbor 安装

1
2
3
4
5
6
7
8
9
10
11
# 安装
helm install openclaw harbor/openclaw \
--version 1.0.0 \
-n openclaw \
--create-namespace

# 或使用 values 文件
helm install openclaw harbor/openclaw \
--version 1.0.0 \
-n openclaw \
-f values-prod.yaml

五、实战案例

5.1 部署 OpenClaw

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. 添加 Helm 仓库
helm repo add harbor oci://hb.test/crystalforge
helm repo update

# 2. 创建命名空间
kubectl create namespace openclaw

# 3. 创建 PVC
kubectl apply -f pvc.yaml -n openclaw

# 4. 安装 Chart
helm install openclaw harbor/openclaw \
--version 1.0.0 \
-n openclaw \
-f values-prod.yaml

# 5. 验证
helm status openclaw -n openclaw
kubectl get pods -n openclaw

5.2 升级应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 升级镜像版本
helm upgrade openclaw harbor/openclaw \
--version 1.0.1 \
-n openclaw \
--set image.tag=1.0.4-feishu

# 查看修订历史
helm history openclaw -n openclaw

# 回滚到上一个版本
helm rollback openclaw -n openclaw

# 回滚到指定版本
helm rollback openclaw 1 -n openclaw

5.3 多环境部署

1
2
3
4
5
6
7
8
9
10
11
# 测试环境
helm install openclaw-staging harbor/openclaw \
--version 1.0.0 \
-n openclaw-staging \
-f values-staging.yaml

# 生产环境
helm install openclaw-prod harbor/openclaw \
--version 1.0.0 \
-n openclaw-prod \
-f values-prod.yaml

六、踩坑记录

6.1 模板语法错误

问题

1
2
3
Error: template: openclaw/templates/deployment.yaml:25:12: 
executing "openclaw/templates/deployment.yaml" at <.Values.image.repository>:
nil pointer evaluating interface {}.repository

原因

  • values.yaml 中缺少 image.repository 字段
  • 模板中引用了不存在的值

解决

1
2
3
4
# values.yaml 中添加默认值
image:
repository: hb.test/crystalforge/openclaw-cn-base
tag: "1.0.3-feishu"

6.2 缩进错误

问题

1
2
Error: YAML parse error on openclaw/templates/deployment.yaml: 
error converting YAML to JSON: yaml: line 35: mapping values are not allowed in this context

原因

  • YAML 缩进不正确
  • 使用了 tab 而不是空格

解决

1
2
3
4
5
# 验证 YAML 语法
helm template openclaw ./openclaw > /dev/null

# 使用编辑器检查缩进
vim -c "set list" templates/deployment.yaml

6.3 依赖版本冲突

问题

1
Error: found in Chart.yaml, but missing in charts/ directory: postgresql, redis

原因

  • Chart.yaml 声明了依赖
  • 但没有下载依赖 Chart

解决

1
2
3
4
5
6
7
# 下载依赖
helm dependency update ./openclaw

# 输出:
# Saving 2 charts
# Downloading postgresql from repo https://charts.bitnami.com/bitnami
# Downloading redis from repo https://charts.bitnami.com/bitnami

七、最佳实践

7.1 Chart 开发

✅ 推荐做法

  1. 使用 _helpers.tpl 封装重复逻辑
  2. 为所有 values 提供默认值
  3. 使用条件判断控制资源创建
  4. 添加完整的 labels 和 annotations
  5. 提供多环境 values 文件

❌ 避免做法

  1. 硬编码值(应该参数化)
  2. 缺少默认值
  3. 复杂的模板逻辑(应该简化)
  4. 不验证 Chart(应该 helm lint

7.2 版本管理

Chart 版本

  • 遵循 SemVer(MAJOR.MINOR.PATCH)
  • 破坏性变更升级 MAJOR
  • 新功能升级 MINOR
  • Bug 修复升级 PATCH

App 版本

  • 对应 Docker 镜像 tag
  • 可以是 SemVer 或 Git commit hash

7.3 安全配置

Secrets

  • 不要提交到 Git
  • 使用 values-secret.yaml(加入.gitignore)
  • 或使用外部密钥管理(Vault)

RBAC

  • 最小权限原则
  • 创建专用 ServiceAccount
  • 限制命名空间范围

八、总结

8.1 核心要点

  1. Chart 结构:Chart.yaml、values.yaml、templates/
  2. 模板开发:_helpers.tpl、条件判断、循环
  3. 多环境:values-staging.yaml、values-prod.yaml
  4. Harbor 发布:打包、推送、安装

8.2 实战经验

这篇文章是今晚 1 小时实战的总结

  • 创建 OpenClaw Helm Chart
  • 配置 Harbor 仓库
  • 测试多环境部署
  • 记录踩坑经验

8.3 后续优化

本周

  • 添加完整的单元测试
  • 配置 CI/CD 自动发布
  • 完善文档

本月

  • 支持更多依赖 Chart
  • 实现自动版本管理
  • 添加监控告警

作者:John,高级技术架构师,CrystalForge 项目负责人
时间:2026-03-11 02:30
地点:深圳
项目:OpenClaw Helm Chart 开发实战