Skip to content

Helm Chart 编写

Helm Chart 本质上是一组带模板语法的 Kubernetes YAML。Chart 编写的重点不是把所有字段都参数化,而是把稳定结构留在模板里,把环境差异、镜像版本、资源规格、入口域名、存储大小这些变化项放到 values 里。

Chart 写得过度灵活会很难维护。业务 Chart 通常只暴露部署时确实会变的字段,其他部分保持固定。平台型 Chart 才需要更强的可配置性。

一、目录结构

创建一个 Chart:

bash
helm create webapp
tree webapp

常见结构:

text
webapp/
  Chart.yaml
  values.yaml
  templates/
    deployment.yaml
    service.yaml
    ingress.yaml
    _helpers.tpl
文件说明
Chart.yamlChart 元信息,名称、版本、应用版本、依赖
values.yaml默认参数
templates/模板目录,渲染后变成 Kubernetes YAML
_helpers.tpl公共模板函数,常用于统一名称和标签

Chart.yaml 示例:

yaml
apiVersion: v2
name: webapp
description: Web application chart
type: application
version: 0.1.0
appVersion: "1.0.0"

version 是 Chart 自己的版本,appVersion 是应用版本。Chart 模板调整但镜像不变时,version 也应该变化。

二、values 设计

一个简化的 values.yaml

yaml
replicaCount: 2

image:
  repository: registry.example.com/demo/webapp
  tag: "1.0.0"
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 500m
    memory: 512Mi

env:
  LOG_LEVEL: info

values 命名保持稳定很重要。CI/CD、Argo CD、环境 overlay 都会引用这些字段。字段改名等于部署接口变化,需要像代码接口一样谨慎。

三、模板里的对象

Deployment 模板:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "webapp.fullname" . }}
  labels:
    {{- include "webapp.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "webapp.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "webapp.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: webapp
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 8080
          env:
            {{- range $name, $value := .Values.env }}
            - name: {{ $name }}
              value: {{ $value | quote }}
            {{- end }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}

nindent 用来处理缩进,quote 避免 YAML 把某些字符串识别成布尔值或数字。模板错误里最常见的就是缩进错误和空值渲染。

四、helpers 和统一标签

templates/_helpers.tpl 常用于统一命名:

gotemplate
{{- define "webapp.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

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

{{- define "webapp.labels" -}}
{{ include "webapp.selectorLabels" . }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
{{- end -}}

selector label 创建后不适合随意变化。Deployment 的 selector 是不可变字段,改了会导致升级失败。通常把 selector label 控制在 nameinstance 这类稳定字段,不把 chart version、app version 放进 selector。

五、条件渲染

可选资源用 if

yaml
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "webapp.fullname" . }}
spec:
  ingressClassName: {{ .Values.ingress.className | quote }}
  rules:
    - host: {{ .Values.ingress.host | quote }}
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: {{ include "webapp.fullname" . }}
                port:
                  number: {{ .Values.service.port }}
{{- end }}

条件渲染适合开关 Ingress、ServiceMonitor、HPA 这类可选资源。核心 Deployment 不建议做太多条件分支,否则渲染结果会很难预测。

六、schema 校验

values.schema.json 可以限制 values 类型和必填字段:

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

schema 能提前拦住 replicaCount: "two"、漏写镜像 tag 这类问题。平台 Chart、团队共用 Chart 很适合加 schema。

七、检查命令

bash
# 检查 Chart 结构和模板语法
helm lint ./webapp

# 渲染出最终 YAML,检查缩进、名称、标签和资源字段
helm template web ./webapp -n demo -f values.yaml

# 模拟安装,连接集群做校验
helm install web ./webapp -n demo --dry-run

模板渲染报错时,优先看报错里的模板文件和行号。渲染成功但集群拒绝时,再看 API Server 的字段校验、不可变字段、RBAC、准入策略。

八、常见问题

问题表现
缩进错误渲染出的 YAML 结构不对,API Server 报字段类型错误
空值没处理image、host、secretName 变成空字符串
selector 标签变化Deployment 升级失败,提示 selector 不可变
values 层级太深使用时很难知道该改哪个字段
把 Secret 明文放 valuesvalues 进入 Git 后泄漏敏感信息
Chart 过度通用模板分支太多,排查渲染结果困难

Chart 编写的检查顺序比较固定:helm lint 看结构,helm template 看最终 YAML,kubectl apply --dry-run=server 或 Helm dry-run 看集群是否接受,最后再实际安装或升级。