helm

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Helm

Helm

Covers the full lifecycle: chart creation, templating, dependency management, validation, OCI distribution, debugging, and release operations.
涵盖完整生命周期:Chart创建、模板编写、依赖管理、验证、OCI分发、调试及版本发布操作。

Chart structure

Chart结构

text
mychart/
  Chart.yaml
  values.yaml
  values.schema.json       # optional JSON Schema validation
  charts/                   # dependencies
  crds/                     # CRDs (applied before templates)
  templates/
    NOTES.txt
    _helpers.tpl
    deployment.yaml
    service.yaml
    ingress.yaml
    configmap.yaml
    secret.yaml
    hpa.yaml
    tests/
      test-connection.yaml
  .helmignore
text
mychart/
  Chart.yaml
  values.yaml
  values.schema.json       # optional JSON Schema validation
  charts/                   # dependencies
  crds/                     # CRDs (applied before templates)
  templates/
    NOTES.txt
    _helpers.tpl
    deployment.yaml
    service.yaml
    ingress.yaml
    configmap.yaml
    secret.yaml
    hpa.yaml
    tests/
      test-connection.yaml
  .helmignore

Chart.yaml

Chart.yaml

yaml
apiVersion: v2
name: myapp
description: A production-grade web application
type: application
version: 1.0.0
appVersion: "2.0.1"
kubeVersion: ">=1.30.0"

maintainers:
  - name: DevOps Team
    email: devops@example.com

dependencies:
  - name: postgresql
    version: "16.x.x"
    repository: "oci://registry-1.docker.io/bitnamicharts"
    condition: postgresql.enabled
yaml
apiVersion: v2
name: myapp
description: A production-grade web application
type: application
version: 1.0.0
appVersion: "2.0.1"
kubeVersion: ">=1.30.0"

maintainers:
  - name: DevOps Team
    email: devops@example.com

dependencies:
  - name: postgresql
    version: "16.x.x"
    repository: "oci://registry-1.docker.io/bitnamicharts"
    condition: postgresql.enabled

values.yaml

values.yaml

Organize hierarchically; document every field with comments.
yaml
replicaCount: 3

image:
  repository: myregistry.io/myapp
  tag: ""
  pullPolicy: IfNotPresent

imagePullSecrets: []

serviceAccount:
  create: true
  annotations: {}
  name: ""

podAnnotations:
  prometheus.io/scrape: "true"
  prometheus.io/port: "9090"

podSecurityContext:
  runAsNonRoot: true
  runAsUser: 1000
  fsGroup: 2000

securityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop: [ALL]

service:
  type: ClusterIP
  port: 80
  targetPort: 8080

ingress:
  enabled: false
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: myapp.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: myapp-tls
      hosts: [myapp.example.com]

resources:
  requests:
    cpu: 250m
    memory: 256Mi
  limits:
    cpu: 500m
    memory: 512Mi

autoscaling:
  enabled: false
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70

nodeSelector: {}
tolerations: []

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
              - key: app.kubernetes.io/name
                operator: In
                values: [myapp]
          topologyKey: kubernetes.io/hostname

postgresql:
  enabled: false
按层级组织;为每个字段添加注释说明。
yaml
replicaCount: 3

image:
  repository: myregistry.io/myapp
  tag: ""
  pullPolicy: IfNotPresent

imagePullSecrets: []

serviceAccount:
  create: true
  annotations: {}
  name: ""

podAnnotations:
  prometheus.io/scrape: "true"
  prometheus.io/port: "9090"

podSecurityContext:
  runAsNonRoot: true
  runAsUser: 1000
  fsGroup: 2000

securityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop: [ALL]

service:
  type: ClusterIP
  port: 80
  targetPort: 8080

ingress:
  enabled: false
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: myapp.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: myapp-tls
      hosts: [myapp.example.com]

resources:
  requests:
    cpu: 250m
    memory: 256Mi
  limits:
    cpu: 500m
    memory: 512Mi

autoscaling:
  enabled: false
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70

nodeSelector: {}
tolerations: []

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
              - key: app.kubernetes.io/name
                operator: In
                values: [myapp]
          topologyKey: kubernetes.io/hostname

postgresql:
  enabled: false

Template helpers (
_helpers.tpl
)

模板助手(
_helpers.tpl

yaml
{{- define "myapp.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{- define "myapp.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 "myapp.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{- define "myapp.labels" -}}
helm.sh/chart: {{ include "myapp.chart" . }}
{{ include "myapp.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{- define "myapp.selectorLabels" -}}
app.kubernetes.io/name: {{ include "myapp.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{- define "myapp.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "myapp.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
yaml
{{- define "myapp.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{- define "myapp.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 "myapp.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{- define "myapp.labels" -}}
helm.sh/chart: {{ include "myapp.chart" . }}
{{ include "myapp.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{- define "myapp.selectorLabels" -}}
app.kubernetes.io/name: {{ include "myapp.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{- define "myapp.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "myapp.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

Key template patterns

核心模板模式

Conditional resource:
yaml
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
...
{{- end }}
Config checksum (force pod restart on config change):
yaml
annotations:
  checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
Iterate over env list:
yaml
env:
{{- range .Values.env }}
- name: {{ .name }}
  value: {{ .value | quote }}
{{- end }}
Safe defaults:
yaml
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
replicas: {{ .Values.replicaCount | default 3 }}
条件化资源:
yaml
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
...
{{- end }}
配置校验和(配置变更时强制重启Pod):
yaml
annotations:
  checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
遍历环境变量列表:
yaml
env:
{{- range .Values.env }}
- name: {{ .name }}
  value: {{ .value | quote }}
{{- end }}
安全默认值:
yaml
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
replicas: {{ .Values.replicaCount | default 3 }}

Validation workflow

验证流程

Always follow this progression:
bash
undefined
请始终遵循以下步骤:
bash
undefined

1. Static lint

1. 静态检查

helm lint ./mychart --strict
helm lint ./mychart --strict

2. Render templates locally

2. 本地渲染模板

helm template myapp ./mychart --debug --values values.yaml
helm template myapp ./mychart --debug --values values.yaml

3. Server-side dry-run (resolves lookup functions against the real API)

3. 服务端预运行(针对真实API解析查找函数)

helm install myapp ./mychart
--namespace prod
--values values.yaml
--dry-run=server --debug
helm install myapp ./mychart
--namespace prod
--values values.yaml
--dry-run=server --debug

4. Install

4. 安装

helm install myapp ./mychart
--namespace prod
--values values.yaml
--atomic --wait
helm install myapp ./mychart
--namespace prod
--values values.yaml
--atomic --wait

5. Post-deploy tests

5. 部署后测试

helm test myapp --namespace prod --logs

Use `--dry-run=server` (not the bare `--dry-run`) when templates contain `lookup` calls that need to resolve against live cluster state.
helm test myapp --namespace prod --logs

当模板包含需要针对真实集群状态解析的`lookup`调用时,请使用`--dry-run=server`(而非单纯的`--dry-run`)。

Common commands

常用命令

Inspect a deployed release:
bash
helm get manifest myapp -n prod
helm get values myapp -n prod --all
helm status myapp -n prod --show-resources
Upgrade:
bash
helm upgrade myapp ./mychart -f values.yaml
helm upgrade --install myapp ./mychart
helm upgrade myapp ./mychart --atomic --timeout 5m
Rollback:
bash
helm history myapp -n prod
helm rollback myapp 3 -n prod --cleanup-on-fail
Dependencies:
bash
helm dependency list ./mychart
helm dependency update ./mychart
helm dependency build ./mychart
Repositories:
bash
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm search repo postgresql
helm show values bitnami/postgresql
查看已部署的版本:
bash
helm get manifest myapp -n prod
helm get values myapp -n prod --all
helm status myapp -n prod --show-resources
升级:
bash
helm upgrade myapp ./mychart -f values.yaml
helm upgrade --install myapp ./mychart
helm upgrade myapp ./mychart --atomic --timeout 5m
回滚:
bash
helm history myapp -n prod
helm rollback myapp 3 -n prod --cleanup-on-fail
依赖管理:
bash
helm dependency list ./mychart
helm dependency update ./mychart
helm dependency build ./mychart
仓库管理:
bash
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm search repo postgresql
helm show values bitnami/postgresql

OCI registry workflow

OCI镜像仓库流程

OCI is the preferred distribution method. No
helm repo add
required.
bash
undefined
OCI是推荐的分发方式,无需执行
helm repo add
bash
undefined

Authenticate

认证

helm registry login registry.example.com -u <user>
helm registry login registry.example.com -u <user>

Push a packaged chart

推送打包后的Chart

helm package ./mychart helm push mychart-1.0.0.tgz oci://registry.example.com/charts
helm package ./mychart helm push mychart-1.0.0.tgz oci://registry.example.com/charts

Pull

拉取

helm pull oci://registry.example.com/charts/mychart --version 1.0.0
helm pull oci://registry.example.com/charts/mychart --version 1.0.0

Install directly from OCI

直接从OCI安装

helm install myapp oci://registry.example.com/charts/mychart --version 1.0.0
helm install myapp oci://registry.example.com/charts/mychart --version 1.0.0

Template, show, upgrade all work with oci:// refs

模板渲染、查看、升级等操作均支持oci://引用

helm show values oci://registry.example.com/charts/mychart --version 1.0.0

OCI dependencies in `Chart.yaml`:

```yaml
dependencies:
- name: redis
  version: "18.x.x"
  repository: "oci://registry-1.docker.io/bitnamicharts"
helm show values oci://registry.example.com/charts/mychart --version 1.0.0

`Chart.yaml`中的OCI依赖:

```yaml
dependencies:
- name: redis
  version: "18.x.x"
  repository: "oci://registry-1.docker.io/bitnamicharts"

Post-renderers

后处理器

Post-renderers transform rendered manifests before Helm applies them. Common use case: injecting labels/annotations via Kustomize without forking the chart.
bash
helm install myapp ./mychart --post-renderer ./kustomize-labels.sh
helm upgrade myapp ./mychart --post-renderer ./kustomize-labels.sh
helm template myapp ./mychart --post-renderer ./kustomize-labels.sh
The executable receives rendered YAML on stdin and must emit valid YAML on stdout. Chain multiple renderers with pipes:
renderer1 | renderer2
.
后处理器会在Helm应用渲染后的清单前对其进行转换。常见用途:通过Kustomize注入标签/注释,无需fork Chart。
bash
helm install myapp ./mychart --post-renderer ./kustomize-labels.sh
helm upgrade myapp ./mychart --post-renderer ./kustomize-labels.sh
helm template myapp ./mychart --post-renderer ./kustomize-labels.sh
可执行文件从标准输入接收渲染后的YAML,并必须向标准输出输出有效的YAML。可通过管道串联多个渲染器:
renderer1 | renderer2

Multi-environment layout

多环境布局

text
mychart/
  values.yaml
  values-dev.yaml
  values-staging.yaml
  values-prod.yaml
bash
helm install myapp ./mychart -f values-prod.yaml -n production
text
mychart/
  values.yaml
  values-dev.yaml
  values-staging.yaml
  values-prod.yaml
bash
helm install myapp ./mychart -f values-prod.yaml -n production

Hooks

钩子

Pre-install/pre-upgrade job (e.g., DB migration):
yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "myapp.fullname" . }}-migration
  annotations:
    "helm.sh/hook": pre-install,pre-upgrade
    "helm.sh/hook-weight": "0"
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: migration
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        command: ["./migrate.sh"]
Test pod:
yaml
apiVersion: v1
kind: Pod
metadata:
  name: {{ include "myapp.fullname" . }}-test
  annotations:
    "helm.sh/hook": test
spec:
  containers:
  - name: curl
    image: curlimages/curl:latest
    command: ['curl']
    args: ['{{ include "myapp.fullname" . }}:{{ .Values.service.port }}/health']
  restartPolicy: Never
预安装/预升级任务(如数据库迁移):
yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "myapp.fullname" . }}-migration
  annotations:
    "helm.sh/hook": pre-install,pre-upgrade
    "helm.sh/hook-weight": "0"
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: migration
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        command: ["./migrate.sh"]
测试Pod:
yaml
apiVersion: v1
kind: Pod
metadata:
  name: {{ include "myapp.fullname" . }}-test
  annotations:
    "helm.sh/hook": test
spec:
  containers:
  - name: curl
    image: curlimages/curl:latest
    command: ['curl']
    args: ['{{ include "myapp.fullname" . }}:{{ .Values.service.port }}/health']
  restartPolicy: Never

Debugging reference

调试参考

SymptomLikely causeFix
error converting YAML to JSON
Indentation errorUse
{{- ... }}
for whitespace chomping
nil pointer evaluating interface
Missing valueAdd
| default "value"
cannot unmarshal string into Go value of type int
Wrong value typeUse
| int
in template
resource that already exists
Conflicting releaseUninstall conflicting release or adopt resource
ImagePullBackOff
Wrong image name or missing pull secretFix image ref; create
imagePullSecrets
no matches for kind
CRD not installed
kubectl apply -f crds/
first
timed out waiting for the condition
Readiness probe failure or slow startIncrease
--timeout
; review probes
pre-upgrade hooks failed
Hook job failedDelete failed job; retry with
--no-hooks
Context safety -- always pass
--kube-context
and
-n
explicitly to avoid targeting the wrong cluster:
bash
helm --kube-context=prod-cluster status myapp -n prod
kubectl --context=prod-cluster get pods -n prod
Verbose output for template errors:
bash
helm template myapp ./mychart --debug 2>&1 | head -100
症状可能原因解决方法
error converting YAML to JSON
缩进错误使用
{{- ... }}
处理空白字符
nil pointer evaluating interface
值缺失添加
| default "value"
设置默认值
cannot unmarshal string into Go value of type int
值类型错误在模板中使用
| int
转换类型
resource that already exists
版本发布冲突卸载冲突版本或接管资源
ImagePullBackOff
镜像名称错误或缺少拉取密钥修正镜像引用;创建
imagePullSecrets
no matches for kind
CRD未安装先执行
kubectl apply -f crds/
timed out waiting for the condition
就绪探针失败或启动缓慢增加
--timeout
时长;检查探针配置
pre-upgrade hooks failed
钩子任务执行失败删除失败任务;使用
--no-hooks
重试
上下文安全 -- 请始终显式传递
--kube-context
-n
参数,避免误操作目标集群:
bash
helm --kube-context=prod-cluster status myapp -n prod
kubectl --context=prod-cluster get pods -n prod
模板错误的详细输出:
bash
helm template myapp ./mychart --debug 2>&1 | head -100

Values schema validation

Values Schema验证

json
{
  "$schema": "https://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["replicaCount", "image"],
  "properties": {
    "replicaCount": { "type": "integer", "minimum": 1 },
    "image": {
      "type": "object",
      "required": ["repository"],
      "properties": {
        "repository": { "type": "string" },
        "tag":        { "type": "string"  }
      }
    }
  }
}
json
{
  "$schema": "https://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["replicaCount", "image"],
  "properties": {
    "replicaCount": { "type": "integer", "minimum": 1 },
    "image": {
      "type": "object",
      "required": ["repository"],
      "properties": {
        "repository": { "type": "string" },
        "tag":        { "type": "string"  }
      }
    }
  }
}

Best practices

最佳实践

  • Use semantic versioning for both
    version
    and
    appVersion
    .
  • Always define
    resources
    requests and limits.
  • Never commit secrets to
    values.yaml
    ; use Vault, Sealed Secrets, or External Secrets.
  • Pin dependency versions explicitly.
  • Include
    NOTES.txt
    with post-install usage instructions.
  • Use
    values.schema.json
    to catch misconfiguration early.
  • Add
    checksum/config
    annotations to force restarts on ConfigMap changes.
  • Use
    --atomic
    for upgrades in CI to auto-rollback on failure.
  • Prefer OCI registries over classic Helm repos for chart distribution.
  • Use
    --dry-run=server
    when templates use
    lookup
    to validate against real cluster state.
  • version
    appVersion
    使用语义化版本控制。
  • 始终定义
    resources
    的请求值和限制值。
  • 切勿将密钥提交到
    values.yaml
    ;使用Vault、Sealed Secrets或External Secrets管理密钥。
  • 显式固定依赖版本。
  • 包含
    NOTES.txt
    文件,提供安装后使用说明。
  • 使用
    values.schema.json
    提前捕获配置错误。
  • 添加
    checksum/config
    注释,在ConfigMap变更时强制重启Pod。
  • 在CI中使用
    --atomic
    参数执行升级,失败时自动回滚。
  • 优先使用OCI镜像仓库而非传统Helm仓库进行Chart分发。
  • 当模板使用
    lookup
    时,使用
    --dry-run=server
    针对真实集群状态进行验证。

Anti-patterns

反模式

  • Hardcoded values in templates instead of
    .Values.*
    references.
  • Missing resource limits (causes unbounded resource consumption).
  • Plain-text secrets in
    values.yaml
    or committed chart files.
  • Relying on implicit
    kubectl
    context without
    --context
    .
  • Deeply nested
    _helpers.tpl
    logic that makes templates unreadable.
  • Using bare
    --dry-run
    with
    lookup
    -heavy templates -- the lookups return empty without
    --dry-run=server
    .
  • 在模板中使用硬编码值而非
    .Values.*
    引用。
  • 缺失资源限制(导致资源消耗无上限)。
  • values.yaml
    或已提交的Chart文件中使用明文密钥。
  • 依赖隐式
    kubectl
    上下文而不指定
    --context
  • _helpers.tpl
    中包含过于复杂的嵌套逻辑,导致模板难以阅读。
  • 对包含大量
    lookup
    的模板使用单纯的
    --dry-run
    -- 若不使用
    --dry-run=server
    ,lookup会返回空值。