3. Helm 基础回顾:Chart 结构、模板渲染机制、Values 与依赖管理、Release 生命周期
在深入 Kyverno 与 Helm 的故障域隔离策略冲突排查之前,必须牢固掌握 Helm 的核心运行机制。Helm 作为 Kubernetes 的包管理工具,其 Chart 结构、模板渲染、Values 传递以及 Release 管理构成了策略冲突发生的底层土壤。本节将系统梳理这些基础概念,为后续分析策略注入点与冲突根因奠定基础。
3.1 Chart 目录结构
一个标准的 Helm Chart 是一个遵循特定布局的目录集合。每个 Chart 都包含描述自身元数据的 Chart.yaml 文件,以及用于生成 Kubernetes 资源的模板文件。
| 文件/目录 | 用途说明 |
|---|---|
Chart.yaml |
Chart 的元数据文件,包含名称、版本、描述、API 版本、依赖声明等。 |
values.yaml |
默认的配置值文件,定义了模板中使用的所有可配置参数的默认值。 |
templates/ |
存放 Go 模板文件的目录,模板渲染后生成 Kubernetes 资源清单(YAML)。 |
charts/ |
存放子 Chart(依赖)的目录,当 Chart 有依赖时,依赖包会被下载到此目录。 |
crds/ |
存放自定义资源定义(CRD)的目录,Helm 会在安装时优先安装这些 CRD。 |
templates/NOTES.txt |
安装成功后向用户显示的帮助文本,通常包含使用说明或访问地址。 |
templates/_helpers.tpl |
存放可复用的模板片段(命名模板),通过 include 或 template 函数调用。 |
策略冲突关注点: Kyverno 策略通常作用于
templates/ 目录渲染出的最终资源。如果 _helpers.tpl 中定义的标签或注解与策略的匹配规则冲突,会导致安装失败或资源被策略拒绝。
3.2 模板渲染机制
Helm 的模板引擎基于 Go 的 text/template 包,并扩展了 50 多个模板函数。渲染过程将 values.yaml 中的值注入到 templates/ 目录下的 Go 模板文件中,最终生成纯 YAML 资源清单。
核心渲染流程:
- 值合并: 将默认
values.yaml、用户提供的--set参数、外部 values 文件按优先级合并为一个全局 Values 对象。 - 模板解析: 遍历
templates/目录下的所有.yaml、.tpl、.txt文件,解析其中的模板指令(如{{ .Values.replicaCount }})。 - 函数执行: 执行模板中的控制结构(
if、range、with)和函数调用(include、required、toYaml)。 - 输出生成: 将渲染后的结果输出为标准的 Kubernetes YAML 资源,每个模板文件对应一个或多个资源。
# 示例:templates/deployment.yaml 中的模板片段
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 }}"
策略冲突风险: 模板中的
include 函数可能动态生成标签或注解,这些动态值若与 Kyverno 策略中的 match 或 exclude 规则不匹配,会导致策略无法正确应用到预期资源,或错误地拦截本应放行的资源。
3.3 Values 与依赖管理
Values 是 Helm 配置的核心,它通过层级结构和优先级规则实现灵活的配置覆盖。依赖管理则允许一个 Chart 引用其他 Chart,形成复合应用。
Values 优先级(从低到高)
- Chart 内置的
values.yaml:最低优先级,提供默认值。 - 父 Chart 的
values.yaml:当 Chart 作为子 Chart 被依赖时,父 Chart 的值可以覆盖子 Chart 的默认值。 - 用户提供的 values 文件:通过
-f或--values参数指定的 YAML 文件。 - 命令行
--set参数:最高优先级,直接覆盖所有层级的值。
依赖管理机制
在 Chart.yaml 中使用 dependencies 字段声明依赖,Helm 会解析并下载依赖 Chart 到 charts/ 目录。依赖 Chart 的 Values 可以通过全局值(global)或子 Chart 名称作用域进行传递。
# Chart.yaml 中的依赖声明示例
dependencies:
- name: redis
version: "17.3.0"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled
tags:
- cache
- name: postgresql
version: "12.1.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
策略冲突关注点: 依赖 Chart 的 Values 传递路径复杂,父 Chart 的
global 值会穿透到所有子 Chart。如果 Kyverno 策略检查资源上的特定注解(如 policy.kyverno.io/inject-sidecar),而该注解通过 global 值传递时被覆盖或遗漏,会导致策略行为异常。
3.4 Release 生命周期
Release 是 Helm Chart 的一次部署实例。每个 Release 都有唯一的名称和版本号,Helm 通过 Release 对象管理应用的安装、升级、回滚和卸载。
Release 状态转换说明
| 状态 | 触发操作 | 策略冲突典型场景 |
|---|---|---|
| PENDING | helm install 执行中 |
Kyverno 策略在资源创建前拦截,导致安装卡在 PENDING 状态。 |
| DEPLOYED | 安装/升级成功 | 策略允许资源创建,但后续策略变更可能导致下次升级失败。 |
| FAILED | 安装/升级过程中出错 | 模板渲染后的资源违反 Kyverno 策略(如缺少必需标签、镜像来源受限)。 |
| SUPERSEDED | 新版本 Release 被部署 | 旧版本 Release 被标记为 SUPERSEDED,但其资源可能仍被策略审计。 |
| UNINSTALLED | helm uninstall |
卸载时,Kyverno 策略可能阻止删除某些资源(如 PVC、Namespace)。 |
关键排查线索: 当 Release 处于
FAILED 状态时,使用 helm get manifest RELEASE_NAME 可以查看 Helm 实际提交给 Kubernetes 的最终 YAML 清单。将此清单与 Kyverno 策略的匹配规则进行比对,是定位冲突的最直接方法。
3.5 模板渲染与策略注入点
理解 Helm 模板渲染的时机和输出,对于定位 Kyverno 策略冲突至关重要。策略引擎在 Helm 提交资源清单后介入,因此冲突发生在渲染后的 YAML 层面。
排查实用命令:
helm template RELEASE_NAME CHART_DIR— 本地渲染模板,输出 YAML 到标准输出,用于离线检查策略合规性。helm get manifest RELEASE_NAME— 获取已安装 Release 的最终资源清单,用于对比实际部署与策略要求。helm get values RELEASE_NAME— 查看 Release 使用的最终 Values 值,帮助定位值传递问题。