外观
Helm 与 Chart:模板化部署
同一套 YAML 要部署到 dev/test/prod,只是镜像 tag、副本数、资源限额不同。Helm 把这些差异抽成 values.yaml,其余全部模板化。
一、三个核心概念
| 概念 | 含义 |
|---|---|
| Chart | 一个应用的可部署包(模板 + 默认值 + 元数据) |
| Values | 覆盖模板变量的配置 |
| Release | Chart 在集群里的一个实例(有名字、有版本历史) |
同一个 Chart 可以用不同 release 名装多次:
bash
helm install shop-prod ./order-api -n prod -f values-prod.yaml
helm install shop-test ./order-api -n test -f values-test.yaml二、Chart 结构
text
order-api/
├── Chart.yaml
├── values.yaml
├── templates/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ └── _helpers.tpl
└── charts/ # 子 chart 依赖yaml
# Chart.yaml
apiVersion: v2
name: order-api
description: Order service
type: application
version: 1.4.2
appVersion: "1.4.2"version 是 Chart 版本,appVersion 是应用版本。两者可以不同步。
三、模板写法
yaml
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "order-api.fullname" . }}
labels:
{{- include "order-api.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "order-api.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "order-api.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: app
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.targetPort }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
envFrom:
- configMapRef:
name: {{ include "order-api.fullname" . }}-configyaml
# values.yaml
replicaCount: 2
image:
repository: registry.internal:5000/shop/order-api
tag: "1.4.2"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
targetPort: 8080
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: "2"
memory: 2Gi
config:
SPRING_PROFILES_ACTIVE: prod
LOG_LEVEL: infoyaml
# values-prod.yaml(只写差异)
replicaCount: 6
resources:
requests:
cpu: "1"
memory: 2Gi
limits:
cpu: "4"
memory: 4Gi
config:
LOG_LEVEL: warn覆盖是合并,不是替换
-f values-prod.yaml 会与 values.yaml 深度合并:标量覆盖,map 逐键合并,数组整体替换。
所以 resources.limits 只写 cpu 时,memory 会保留默认值;但写 env: [...] 会整体替换掉默认的环境变量列表。
四、常用命令
bash
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm search repo bitnami/redis
helm show values bitnami/redis > redis-values.yaml
helm install redis bitnami/redis -n infra --create-namespace -f redis-values.yamltext
NAME: redis
LAST DEPLOYED: Wed Oct 28 00:20:11 2026
NAMESPACE: infra
STATUS: deployed
REVISION: 1bash
helm list -A
helm status redis -n infra
helm get values redis -n infra
helm get manifest redis -n infra
helm upgrade redis bitnami/redis -n infra -f redis-values.yaml
helm rollback redis 1 -n infra
helm history redis -n infra
helm uninstall redis -n infrahelm history 输出:
text
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Wed Oct 28 00:20:11 2026 superseded redis-20.0.0 7.4.1 Install complete
2 Wed Oct 28 00:31:42 2026 deployed redis-20.0.1 7.4.2 Upgrade complete五、调试模板
bash
# 渲染成最终 YAML,不提交给集群
helm template order-api ./order-api -f values-prod.yaml -n prod
# 只渲染某个模板
helm template order-api ./order-api -s templates/deployment.yaml
# 检查语法 + 与集群对比
helm lint ./order-api
helm install order-api ./order-api -n prod --dry-run --debugtext
NAME: order-api
LAST DEPLOYED: Wed Oct 28 00:35:02 2026
NAMESPACE: prod
STATUS: pending-install
REVISION: 1
HOOKS:
MANIFEST:
---
# Source: order-api/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
...--dry-run --debug 会把渲染后的 manifest 全打出来,是排查"为什么部署出来的东西和我写的不一样"的首选。
六、values 分层策略
bash
helm upgrade --install order-api ./order-api \
-n prod \
-f values.yaml \
-f values-prod.yaml \
--set image.tag=1.4.3优先级:后面的覆盖前面的,--set 最高。
推荐三层:
| 层 | 文件 | 内容 |
|---|---|---|
| 默认 | values.yaml | 通用默认值,可安全用于本地 |
| 环境 | values-{env}.yaml | 副本数、资源、外部地址 |
| 发布 | --set image.tag=x.y.z | 只放版本号 |
不要用 --set 传复杂结构
--set 'env[0].name=A,env[0].value=B' 这种写法又长又容易错(逗号、点号都要转义)。复杂配置写进 values 文件。
七、CI 里的标准流程
bash
set -euo pipefail
CHART=./order-api
TAG="${CI_COMMIT_SHORT_SHA}"
helm lint "$CHART" -f values-prod.yaml
helm upgrade --install order-api "$CHART" \
-n prod \
-f values.yaml -f values-prod.yaml \
--set image.tag="$TAG" \
--atomic \
--timeout 5m \
--wait| 参数 | 作用 |
|---|---|
--atomic | 失败自动回滚到上一版本 |
--wait | 等所有资源就绪才返回 |
--timeout 5m | 超时时间 |
--atomic --wait 是 CI 部署的推荐组合:部署失败不会留下半成品。
八、常见错误
| 报错 | 原因 | 处置 |
|---|---|---|
Error: cannot re-use a name that is still in use | release 名已存在且未 uninstall | helm upgrade --install |
rendered manifests contain a resource that already exists | 资源是手工创建的 | 加 --force,或先删旧资源 |
UPGRADE FAILED: another operation in progress | 有未完成的 release | helm rollback 或 helm uninstall |
nil pointer evaluating interface {} | values 里少了某个键 | --set 或补默认值 |
error converting YAML to JSON | 模板缩进/nindent 用错 | helm template 看渲染结果 |
release not found | namespace 不对 | -n 一致 |
九、踩过的坑
| 现象 | 根因 | 处置 |
|---|---|---|
| 改了 values 但集群没变 | 值路径写错,被默认值覆盖 | helm get values 看实际生效值 |
| 数组配置被清空 | 数组是整体替换 | 在 override 里写完整数组 |
--atomic 回滚了但不知道原因 | 没看事件 | kubectl get events + helm history |
| 镜像 tag 一直是 latest | values 里默认 latest | 强制 --set image.tag=<commit> |
| ConfigMap 改了 Pod 没重启 | 环境变量不会热更新 | 加 checksum 注解触发 rollout |
| 卸载后 PVC 还在 | StatefulSet 的卷默认保留 | 手动删 PVC,或配 persistentVolumeClaimRetentionPolicy |
让 ConfigMap 变更自动触发滚动更新:
yaml
spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}