2. Helm Chart 基础回顾:Chart 结构、Values、Templates 与依赖管理
在深入镜像拉取依赖图与集群升级适配测试之前,必须牢固掌握 Helm Chart 的核心构造。Chart 并非简单的 YAML 文件集合,而是一个具备模板引擎、参数注入与依赖解析能力的应用打包格式。本节将拆解其四大支柱:目录结构、Values 参数体系、Template 渲染机制以及依赖管理。
2.1 Chart 标准目录结构
一个标准的 Helm Chart 遵循固定布局,Helm CLI 通过识别这些约定文件来执行打包、验证与安装。下表列出了核心文件与目录的作用:
| 路径 / 文件 | 是否必需 | 作用说明 |
|---|---|---|
Chart.yaml |
是 | Chart 元数据:名称、版本、API 版本、描述、关键字等 |
values.yaml |
是 | 默认配置值,供模板引用;用户可通过 --set 或自定义 values 文件覆盖 |
templates/ |
是 | Go 模板文件目录,渲染后生成 Kubernetes 资源清单 |
charts/ |
否 | 子 Chart 或依赖 Chart 的本地存储目录(helm dependency update 后生成) |
crds/ |
否 | 自定义资源定义(CRD),Helm 会在安装时优先应用此目录下的 YAML |
templates/NOTES.txt |
否 | 安装成功后向用户展示的说明文本(如访问地址、默认密码等) |
templates/tests/ |
否 | 测试 Pod 模板,用于 helm test 验证部署是否正常 |
Chart.yaml 中的 apiVersion 字段决定了 Helm 的行为模式(v1 为旧版,v2 为当前主流)。务必确认 Chart 的 apiVersion 与 Helm 客户端版本兼容,否则可能导致依赖解析失败。
2.2 Values 参数注入与作用域
Values 是 Chart 的配置接口。Helm 通过三层合并策略将用户提供的值注入模板:
- 内置对象:
.Release、.Chart、.Files、.Capabilities等由 Helm 自动注入。 - 用户 Values:
--values myvals.yaml或--set key=value传入。 - 父 Chart 传递:子 Chart 通过
requirements.yaml或Chart.yaml的dependencies字段接收父 Chart 的 values。
作用域规则遵循“全局优先,局部覆盖”原则。以下是一个典型的 values 层级示例:
# values.yaml
replicaCount: 3
image:
repository: nginx
tag: "1.25"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
在模板中通过 .Values.image.repository 引用。当用户执行 helm install --set image.tag=1.26 时,tag 被覆盖为 1.26,其余字段保持默认。
.Values.image 字段。在集群升级场景中,需要确保 image.repository 指向的镜像仓库在目标集群中可访问,且 image.tag 对应的镜像架构与目标节点 CPU 架构(amd64 / arm64)匹配。
2.3 Template 渲染引擎与内置函数
Helm 使用 Go 模板引擎(text/template)扩展了 60+ 个模板函数,包括 Sprig 库、流控制、管道操作等。模板文件通常以 .yaml 为后缀,但实际是 Go 模板语法与 YAML 的混合体。
一个典型的 Deployment 模板片段:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myapp.fullname" . }}
labels:
{{- include "myapp.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "myapp.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "myapp.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.port }}
模板中使用了 include 函数引用命名模板(_helpers.tpl 中定义),nindent 控制缩进,. 表示当前作用域上下文。在升级适配测试中,需要特别关注 imagePullPolicy 的渲染结果——如果 tag 为 latest 或未指定,Helm 默认会将其设为 Always,这会影响集群升级时的镜像拉取行为。
imagePullPolicy 如果被硬编码为 IfNotPresent,在集群升级后节点缓存了旧版本镜像时,Kubelet 不会主动拉取新版本,导致 Pod 仍运行旧镜像。建议在 values 中暴露 pullPolicy 字段,并在升级前通过 --set 临时覆盖为 Always。
2.4 依赖管理:从 requirements.yaml 到 Chart.yaml
Helm 2 使用独立的 requirements.yaml 管理依赖,Helm 3 将其合并到 Chart.yaml 的 dependencies 字段。依赖管理决定了子 Chart 的下载、版本锁定与 values 传递方式。
以下是一个 Helm 3 风格的依赖声明:
# Chart.yaml
apiVersion: v2
name: myapp
version: 1.0.0
dependencies:
- name: redis
version: ">=16.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled
tags:
- cache
- name: postgresql
version: "12.x.x"
repository: "https://charts.bitnami.com/bitnami"
alias: db
import-values:
- child: defaults
parent: postgres
关键字段说明:
| 字段 | 作用 | 升级适配影响 |
|---|---|---|
condition |
条件控制:当 redis.enabled=false 时跳过安装 |
升级时需确认条件值是否变化,避免子 Chart 被意外启用或禁用 |
tags |
标签分组:可通过 --set tags.cache=false 批量禁用 |
标签覆盖优先级高于 condition,升级时需检查标签冲突 |
alias |
别名:避免同名 Chart 冲突,子 Chart values 通过别名访问 | 别名变更会导致 values 路径失效,升级前必须对齐 |
import-values |
值导入:将子 Chart 的 defaults 映射到父 Chart 的 postgres 路径 | 映射关系错误会导致子 Chart 使用空值或默认值,引发配置漂移 |
repository |
Chart 仓库 URL 或 OCI 地址 | 集群升级后若仓库迁移或鉴权变更,helm dependency update 会失败 |
执行 helm dependency update 后,Helm 会生成 Chart.lock 文件锁定精确版本,并将 Chart 包下载到 charts/ 目录。在集群升级适配测试中,必须重新执行 helm dependency update 以确保子 Chart 版本与目标集群的 Kubernetes API 版本兼容。
2.5 依赖解析与镜像拉取的关联
依赖管理直接影响镜像拉取依赖图的构建。每个子 Chart 可能定义自己的镜像仓库与标签,父 Chart 无法直接控制子 Chart 的 image 字段,除非通过 import-values 或全局 values 传递。
下图展示了 Helm Chart 依赖树与镜像拉取路径的关系:
从图中可以看出:
- 父 Chart 通过
dependencies声明子 Chart,但不直接控制子 Chart 的镜像。 - 每个子 Chart 的
values.yaml中定义了各自的image.repository和image.tag。 - 镜像拉取依赖图需要递归遍历所有子 Chart 的 values,才能构建完整的镜像列表。
- 在集群升级场景中,如果子 Chart 版本升级导致镜像仓库或标签变更,父 Chart 的升级测试必须覆盖这些变更。
helm template --generate-name 渲染所有模板,然后通过 grep -E 'image:' 提取所有镜像地址,构建完整的镜像拉取清单。对比升级前后的清单,识别新增、删除或变更的镜像,提前在目标集群中验证镜像拉取权限与架构兼容性。
2.6 依赖版本约束与升级兼容性
Helm 支持语义化版本范围约束,常用的操作符包括:
| 操作符 | 示例 | 匹配版本 | 升级风险 |
|---|---|---|---|
>= |
>= 16.0.0 |
16.0.0 及以上所有版本 | 可能引入不兼容的 API 变更 |
~(波浪号) |
~16.0 |
16.0.x 范围内的最新补丁版本 | 补丁升级通常安全,但需验证 |
^(脱字符) |
^16.0.0 |
16.0.0 到 17.0.0 以下(不含主版本变更) | 次版本升级可能引入新特性或弃用 |
= |
=16.0.1 |
精确匹配 16.0.1 | 无版本漂移风险,但需手动更新 |
在集群升级适配测试中,建议将依赖版本约束从 >= 或 ^ 收紧为 ~ 或精确版本,避免 helm dependency update 自动拉取不兼容的子 Chart 版本。同时,Chart.lock 文件应纳入版本控制,确保所有环境使用相同的依赖版本。
apiVersion 可能从 v1 变为 v2。如果父 Chart 的 Chart.yaml 中 apiVersion: v1,则无法引用 apiVersion: v2 的子 Chart。此时必须先将父 Chart 升级为 apiVersion: v2,否则 helm dependency build 会报错。