2. Helm Chart 开发:Chart.yaml 规范、values.yaml 设计模式、模板函数与管道、命名模板
Helm Chart 是 Kubernetes 应用交付的标准打包格式。理解 Chart 的核心文件规范与模板引擎设计模式,是构建可维护、可复用的云原生基础设施的前提。本节将围绕 Chart.yaml 元数据声明、values.yaml 分层设计、模板函数与管道链式处理、以及命名模板的复用机制展开。
2.1 Chart.yaml 规范:元数据声明与版本约束
Chart.yaml 是 Chart 的“身份证”,位于 Chart 根目录。它定义了 Chart 的名称、版本、API 版本、依赖关系以及应用版本等关键元数据。Helm v3 要求 apiVersion 必须为 v2。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
apiVersion |
string | 是 | Chart API 版本,v2 为 Helm 3+ 标准 |
name |
string | 是 | Chart 名称,需符合 DNS-1123 子域名规范 |
version |
string | 是 | Chart 语义化版本,如 1.2.3 |
appVersion |
string | 否 | 所包含应用的版本,支持语义化或任意字符串 |
kubeVersion |
string | 否 | 兼容的 Kubernetes 版本约束,如 >=1.21.0-0 <1.28.0-0 |
dependencies |
list | 否 | 子 Chart 依赖列表,包含 name、version、repository |
type |
string | 否 | Chart 类型:application(默认)或 library |
最佳实践:始终在
Chart.yaml 中声明 kubeVersion 约束,避免 Chart 被安装到不兼容的集群中。使用 annotations 字段记录维护者、许可证或 CI 构建元数据。
# Chart.yaml 示例
apiVersion: v2
name: dns-resolver
description: A DNS resolver with SLO-aware failover
type: application
version: 0.3.1
appVersion: "2.1.0"
kubeVersion: ">=1.22.0-0 <1.30.0-0"
dependencies:
- name: common
version: "2.x"
repository: "https://charts.bitnami.com/bitnami"
annotations:
category: Network
licenses: Apache-2.0
2.2 values.yaml 设计模式:分层、默认与覆盖
values.yaml 是 Chart 的配置入口。良好的设计模式应遵循“三层结构”:全局默认值、组件级配置、环境覆盖。通过 YAML 的层级嵌套与 Helm 的 --values / --set 机制,实现配置的灵活组合。
设计原则:将可变参数暴露在
values.yaml 顶层,将内部实现细节隐藏在子层级。避免在模板中硬编码环境特定值。
| 层级 | 示例 | 用途 |
|---|---|---|
| 全局 | global.imageRegistry |
跨组件共享的镜像仓库、标签、PullSecret |
| 组件 | resolver.replicas |
单个组件的副本数、资源限制、端口 |
| 环境覆盖 | prod-values.yaml |
生产环境专用的资源配额、HPA 阈值 |
# values.yaml 设计示例
global:
imageRegistry: docker.io/myorg
dnsDomain: cluster.local
resolver:
name: dns-resolver
replicas: 3
image:
repository: dns-resolver
tag: "2.1.0"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 53
protocol: UDP
resources:
requests:
cpu: 500m
memory: 256Mi
limits:
cpu: 1000m
memory: 512Mi
monitoring:
enabled: true
prometheusRule:
sloLatency: "0.05" # 50ms SLO 阈值
2.3 模板函数与管道:数据转换与链式处理
Helm 模板引擎基于 Go text/template,内置了 Sprig 函数库(超过 70 个函数)。管道(Pipeline) 允许将前一个函数的输出作为后一个函数的输入,形成链式处理流。这是 Helm 模板最强大的特性之一。
常见陷阱:忘记对字符串值使用
quote 或 squote 函数,导致 YAML 解析错误。始终对用户输入的值进行类型转换或引用。
{{- /* 管道链式处理示例 */ -}}
{{- $imageFull := printf "%s/%s:%s" .Values.global.imageRegistry .Values.resolver.image.repository .Values.resolver.image.tag | lower -}}
image: {{ $imageFull | quote }}
{{- /* 默认值回退 */ -}}
replicas: {{ .Values.resolver.replicas | default 1 | int }}
{{- /* 字符串截断与格式化 */ -}}
name: {{ .Values.resolver.name | upper | trunc 12 | quote }}
{{- /* 列表过滤与连接 */ -}}
{{- $ports := list "53" "853" "5353" -}}
ports: {{ $ports | join "," | quote }}
常用函数分类:
- 字符串:
upper、lower、trim、quote、squote、trunc - 数学:
add、sub、mul、div、ceil、floor - 列表:
list、append、prepend、first、last、join - 字典:
dict、hasKey、keys、values、merge - 类型转换:
int、float64、toString、toJson - 流程控制:
default、ternary、coalesce
2.4 命名模板:复用逻辑与作用域控制
命名模板(Named Templates)通过 define 关键字定义,使用 template 或 include 调用。它们通常存储在 templates/_helpers.tpl 文件中,用于封装重复的标签、名称生成、条件判断等逻辑。include 比 template 更灵活,因为它允许将输出传递给管道。
命名规范:使用
chartName.templateName 的命名空间前缀,避免与其他 Chart 的命名模板冲突。例如 dns-resolver.labels。
{{- /* _helpers.tpl 文件内容 */ -}}
{{- define "dns-resolver.labels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
{{- end -}}
{{- define "dns-resolver.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
{{- define "dns-resolver.fullname" -}}
{{- $name := default .Chart.Name .Values.resolver.name -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- /* 在 Deployment 模板中调用命名模板 */ -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "dns-resolver.fullname" . }}
labels:
{{- include "dns-resolver.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.resolver.replicas }}
selector:
matchLabels:
{{- include "dns-resolver.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "dns-resolver.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: resolver
image: {{ printf "%s/%s:%s" .Values.global.imageRegistry .Values.resolver.image.repository .Values.resolver.image.tag | lower | quote }}
作用域控制:命名模板默认继承调用处的上下文(
.)。如果需要传递子作用域,使用 include "templateName" (dict "key" .Values.subKey) 显式传递。避免在模板内部直接引用全局 .Values,保持模板的纯函数特性。
2.5 综合实践:构建可测试的 Chart 结构
一个生产级的 Helm Chart 目录结构应遵循以下布局,确保模板、测试、文档与 CI 配置分离:
dns-resolver/
├── Chart.yaml # 元数据与依赖声明
├── values.yaml # 默认配置值
├── values.schema.json # JSON Schema 校验(可选)
├── charts/ # 子 Chart 依赖(helm dependency 生成)
├── templates/
│ ├── _helpers.tpl # 命名模板定义
│ ├── deployment.yaml # 工作负载模板
│ ├── service.yaml # 网络暴露模板
│ ├── servicemonitor.yaml # 监控指标模板
│ ├── prometheusrule.yaml # SLO 告警规则模板
│ ├── hpa.yaml # 弹性伸缩模板
│ ├── configmap.yaml # 配置注入模板
│ └── tests/
│ ├── test-connection.yaml # 连通性测试
│ └── test-dns-resolution.yaml # DNS 解析测试
├── ci/ # CI 测试用的 values 覆盖文件
│ ├── prod-values.yaml
│ └── stress-values.yaml
└── README.md # 使用说明与参数文档
版本管理:始终将
Chart.yaml 中的 version 与 Git tag 保持一致。使用 helm lint 和 helm template --debug 在 CI 中验证模板渲染结果。对于 SLO 相关的 Chart,建议在 values.schema.json 中约束延迟阈值、副本数等关键参数的类型与范围。