3. Chart 目录结构:核心文件作用与规范

一个标准的 Helm Chart 遵循固定的目录布局。理解每个文件和目录的职责,是进行 Chart 开发、治理与运维的基础。本章将详细拆解 Chart 目录结构,并明确各核心文件的编写规范。

核心原则: Helm Chart 的目录结构是约定优于配置的体现。严格遵循官方规范,可以确保 Chart 的可移植性、可维护性以及被 Helm 工具链正确解析。

3.1 标准 Chart 目录全景

一个典型的 Chart 包(如 my-app-1.0.0.tgz)解压后,其内部目录结构如下所示。所有文件均位于以 Chart 名称命名的顶级目录下。

my-app/
├── Chart.yaml          # Chart 元数据定义文件(必需)
├── values.yaml         # 默认配置值文件(必需)
├── values.schema.json  # values.yaml 的 JSON Schema 校验文件(可选)
├── charts/             # 子 Chart 依赖目录(可选)
│   └── redis-17.3.0.tgz
├── templates/          # Kubernetes 资源模板目录(必需)
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── _helpers.tpl    # 模板辅助函数(可选)
│   └── tests/
│       └── test-connection.yaml
├── templates/NOTES.txt # 部署后的使用说明模板(可选)
├── README.md           # Chart 的说明文档(推荐)
├── LICENSE             # 许可证文件(可选)
└── .helmignore         # 打包时忽略的文件列表(可选)
运维提示: 在 CI/CD 流水线中,应使用 helm lint 命令对 Chart 目录结构进行静态检查。该命令会验证必需文件是否存在、YAML 语法是否正确以及模板是否能被正常渲染。

3.2 核心文件作用与规范

下表详细列出了每个核心文件的作用、规范要求以及常见治理检查点。

文件/目录 必需性 核心作用 关键规范与治理要点
Chart.yaml 必需 定义 Chart 的名称、版本、API 版本、描述、关键字等元数据。
  • apiVersion:必须为 v2(Helm 3+)。
  • version:遵循 SemVer 2 规范,如 1.2.3。
  • appVersion:对应被部署应用的版本,可与 Chart 版本不同。
  • dependencies:声明子 Chart 依赖,需指定仓库地址和版本约束。
values.yaml 必需 提供所有可配置参数的默认值,是 Chart 的配置接口。
  • 所有参数必须有默认值,且值类型明确。
  • 使用层级结构组织参数,避免扁平化。
  • 每个参数必须附带 # @schema 注释或配合 values.schema.json 进行校验。
  • 禁止硬编码敏感信息(如密码),应使用 --set 或 Secret 引用。
templates/ 必需 存放 Go 模板文件,用于渲染 Kubernetes 资源清单。
  • 每个资源类型建议单独一个文件(如 deployment.yaml)。
  • 模板逻辑应尽量简单,复杂逻辑放入 _helpers.tpl。
  • 必须包含 metadata.labels 和 metadata.namespace 的模板化定义。
  • 使用 include 函数复用标签和注解块。
charts/ 可选 存放子 Chart 的打包文件(.tgz),用于管理依赖。
  • 依赖应通过 Chart.yaml 的 dependencies 声明,并使用 helm dependency update 下载。
  • 避免手动将子 Chart 放入此目录,除非是私有或本地依赖。
  • 治理要求:锁定依赖版本,防止意外升级。
templates/NOTES.txt 推荐 在 helm install 或 helm upgrade 成功后,向用户打印使用说明。
  • 内容应包含:如何访问应用、默认凭据、后续操作步骤。
  • 支持 Go 模板语法,可动态获取 release 名称、端口等信息。
  • 避免输出敏感信息,如明文密码。

3.3 文件依赖与数据流关系

下图展示了 Chart 在渲染过程中,各核心文件之间的数据流与依赖关系。理解此流程有助于定位配置问题。

Chart 核心文件数据流与依赖关系 Chart 核心文件数据流与依赖关系 Chart.yaml 元数据 + 依赖声明 values.yaml 默认配置值 charts/ 子 Chart 包 依赖解析 templates/ K8s 资源模板 模板上下文 值注入 子 Chart 模板 K8s 资源清单 YAML 输出 模板渲染 NOTES.txt 使用说明 动态信息

3.4 关键文件编写规范详解

3.4.1 Chart.yaml:Chart 的身份证

Chart.yaml 是 Helm 识别一个 Chart 的首要文件。其内容必须遵循严格的格式和字段要求。

apiVersion: v2
name: my-app
description: A Helm chart for deploying my-app on Kubernetes
type: application

# Chart 版本,每次发布新 Chart 包时必须递增
version: 1.2.3

# 被部署应用的版本,可独立于 Chart 版本更新
appVersion: "3.0.0"

# 关键字,用于 helm search 索引
keywords:
  - web
  - application

# 维护者信息
maintainers:
  - name: DevOps Team
    email: devops@example.com

# 依赖声明
dependencies:
  - name: redis
    version: "~17.3.0"
    repository: "https://charts.bitnami.com/bitnami"
    condition: redis.enabled
    tags:
      - cache
治理红线:
  • 版本不可变: 一旦 Chart 被发布到仓库,其 version 字段对应的包内容就不可再修改。任何变更都必须通过递增 version 来发布新版本。
  • 依赖版本锁定: 在 Chart.yaml 中使用 ~ 或 ^ 等范围约束时,必须配合 Chart.lock 文件锁定具体版本,确保可重复构建。

3.4.2 values.yaml:配置的单一入口

values.yaml 是 Chart 与用户交互的核心界面。良好的 values.yaml 设计能极大降低使用复杂度。

# 全局配置
global:
  imageRegistry: ""

# 应用副本数
replicaCount: 3

# 镜像配置
image:
  repository: nginx
  tag: "1.25.3"
  pullPolicy: IfNotPresent

# 服务配置
service:
  type: ClusterIP
  port: 80

# 资源限制
resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

# 是否启用 ingress
ingress:
  enabled: false
  className: ""
  hosts:
    - host: my-app.local
      paths:
        - path: /
          pathType: Prefix

# 子 Chart 控制
redis:
  enabled: true
  architecture: standalone
最佳实践:
  • 为每个参数添加 # -- 描述 注释,便于生成文档。
  • 使用 values.schema.json 对参数类型、取值范围进行强制校验,防止错误配置导致部署失败。
  • 将敏感参数(如密码)的默认值设为空字符串 "",并在 NOTES.txt 中提示用户必须通过 --set 或外部 Secret 提供。

3.4.3 templates/ 目录:资源模板的规范

templates/ 目录下的每个文件都应遵循以下规范,以确保模板的可读性和可维护性。

{{- /* 文件头:声明 API 版本和资源类型 */ -}}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-app.fullname" . }}
  labels:
    {{- include "my-app.labels" . | nindent 4 }}
spec:
  {{- /* 使用 values.yaml 中的配置 */}}
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "my-app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "my-app.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - containerPort: {{ .Values.service.port }}
模板治理清单:
  1. 标签标准化: 所有资源必须包含 app.kubernetes.io/name、app.kubernetes.io/instance、app.kubernetes.io/version 等推荐标签。
  2. 命名空间隔离: 模板中不应硬编码 namespace,应使用 {{ .Release.Namespace }} 动态获取。
  3. 辅助函数复用: 将重复的标签、名称定义提取到 _helpers.tpl 中,通过 include 引用。
  4. 条件渲染: 使用 {{- if .Values.ingress.enabled }} 控制可选资源的生成。

3.4.4 templates/NOTES.txt:部署后的用户手册

NOTES.txt 是 Helm 与用户交互的最后一个环节。一个优秀的 NOTES.txt 能显著提升用户体验。

Thank you for installing {{ .Chart.Name }}.

Your release is named {{ .Release.Name }}.

To access the application from outside the cluster, follow these steps:

1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
  http://{{ (index .Values.ingress.hosts 0).host }}{{ (index (index .Values.ingress.hosts 0).paths 0).path }}
{{- else if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "my-app.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "my-app.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
  echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- end }}

2. Default credentials (if applicable):
   Username: admin
   Password: {{ .Values.adminPassword | default "NOT SET - please set adminPassword" }}
安全警告: 不要在 NOTES.txt 中直接输出明文密码。如果必须提供默认凭据,应使用 {{ .Values.adminPassword | default "请通过 --set 设置 adminPassword" }} 的方式提示用户。

3.5 目录结构治理检查清单

在 Chart 发布前,运维团队应使用以下清单进行自动化检查。

  1. 必需文件完整性: 确认 Chart.yaml、values.yaml、templates/ 目录存在且非空。
  2. YAML 语法校验: 使用 helm lint 检查所有 YAML 文件的语法正确性。
  3. 模板渲染测试: 使用 helm template --debug 检查模板是否能正确渲染,且输出符合 K8s 资源规范。
  4. 依赖完整性: 检查 Chart.lock 文件是否存在,且与 Chart.yaml 中的依赖声明一致。
  5. 敏感信息扫描: 扫描 values.yaml 和 templates/ 中是否包含硬编码的密码、密钥或 。
  6. NOTES.txt 可读性: 确认 NOTES.txt 模板语法正确,且不输出未定义的变量。
自动化集成: 将上述检查清单集成到 CI/CD 流水线的 pre-commit 钩子或 chart-testing 工具中,实现 Chart 质量的左移。