Skip to content

Helm 与 Chart:模板化部署 ​

同一套 YAML 要部署到 dev/test/prod,只是镜像 tag、副本数、资源限额不同。Helm 把这些差异抽成 values.yaml,其余全部模板化。

一、三个核心概念 ​

概念含义
Chart一个应用的可部署包(模板 + 默认值 + 元数据)
Values覆盖模板变量的配置
ReleaseChart 在集群里的一个实例(有名字、有版本历史)

同一个 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" . }}-config
yaml
# 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: info
yaml
# 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.yaml
text
NAME: redis
LAST DEPLOYED: Wed Oct 28 00:20:11 2026
NAMESPACE: infra
STATUS: deployed
REVISION: 1
bash
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 infra

helm 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 --debug
text
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 userelease 名已存在且未 uninstallhelm upgrade --install
rendered manifests contain a resource that already exists资源是手工创建的加 --force,或先删旧资源
UPGRADE FAILED: another operation in progress有未完成的 releasehelm rollback 或 helm uninstall
nil pointer evaluating interface {}values 里少了某个键--set 或补默认值
error converting YAML to JSON模板缩进/nindent 用错helm template 看渲染结果
release not foundnamespace 不对-n 一致

九、踩过的坑 ​

现象根因处置
改了 values 但集群没变值路径写错,被默认值覆盖helm get values 看实际生效值
数组配置被清空数组是整体替换在 override 里写完整数组
--atomic 回滚了但不知道原因没看事件kubectl get events + helm history
镜像 tag 一直是 latestvalues 里默认 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 }}