11 KiB
11 KiB
Helm Chart 结构参考
Helm Chart 组织结构、文件规范与最佳实践完整指南。
标准 Chart 目录结构
my-app/
├── Chart.yaml # Chart 元数据(必需)
├── Chart.lock # 依赖锁定文件(自动生成)
├── values.yaml # 默认配置值(必需)
├── values.schema.json # values 验证 JSON Schema
├── .helmignore # 打包时忽略的文件模式
├── README.md # Chart 文档
├── LICENSE # Chart 许可证
├── charts/ # Chart 依赖(打包内置)
│ └── postgresql-12.0.0.tgz
├── crds/ # 自定义资源定义(CRD)
│ └── my-crd.yaml
├── templates/ # Kubernetes 清单模板(必需)
│ ├── NOTES.txt # 安装后说明
│ ├── _helpers.tpl # 模板辅助函数
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── secret.yaml
│ ├── serviceaccount.yaml
│ ├── hpa.yaml
│ ├── pdb.yaml
│ ├── networkpolicy.yaml
│ └── tests/
│ └── test-connection.yaml
└── files/ # 附加文件
└── config/
└── app.conf
Chart.yaml 规范
API 版本 v2(Helm 3+)
apiVersion: v2 # 必需:API 版本
name: my-application # 必需:Chart 名称
version: 1.2.3 # 必需:Chart 版本(SemVer)
appVersion: "2.5.0" # 应用版本
description: A Helm chart for my application # 必需
type: application # Chart 类型:application 或 library
keywords: # 搜索关键词
- web
- api
- backend
home: https://example.com # 项目主页
sources: # 源码地址
- https://github.com/example/my-app
maintainers: # 维护者列表
- name: John Doe
email: john@example.com
url: https://github.com/johndoe
icon: https://example.com/icon.png # Chart 图标 URL
kubeVersion: ">=1.24.0" # 兼容的 Kubernetes 版本
deprecated: false # 标记为已弃用
annotations: # 自定义注解
example.com/release-notes: https://example.com/releases/v1.2.3
dependencies: # Chart 依赖
- name: postgresql
version: "12.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
tags:
- database
import-values:
- child: database
parent: database
alias: db
Chart 类型
Application Chart(应用 Chart)
type: application
- 标准 Kubernetes 应用
- 可安装和管理
- 包含 K8s 资源模板
Library Chart(库 Chart)
type: library
- 共享模板辅助函数
- 不可直接安装
- 作为其他 Chart 的依赖使用
- 无 templates/ 目录
Values 文件组织
values.yaml(默认值)
# 全局值(与子 Chart 共享)
global:
imageRegistry: docker.io
imagePullSecrets: []
# 镜像配置
image:
registry: docker.io
repository: myapp/web
tag: "" # 默认使用 .Chart.AppVersion
pullPolicy: IfNotPresent
# Deployment 配置
replicaCount: 1
revisionHistoryLimit: 10
# Pod 配置
podAnnotations: {}
podSecurityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
# 容器安全
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
# Service
service:
type: ClusterIP
port: 80
targetPort: http
annotations: {}
# 资源限制
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
# 自动伸缩
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# 节点选择
nodeSelector: {}
tolerations: []
affinity: {}
# 监控
serviceMonitor:
enabled: false
interval: 30s
values.schema.json(值校验)
{
"$schema": "https://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"replicaCount": {
"type": "integer",
"minimum": 1
},
"image": {
"type": "object",
"required": ["repository"],
"properties": {
"repository": {
"type": "string"
},
"tag": {
"type": "string"
},
"pullPolicy": {
"type": "string",
"enum": ["Always", "IfNotPresent", "Never"]
}
}
}
},
"required": ["image"]
}
模板文件
模板命名规范
- 小写加连字符:
deployment.yaml、service-account.yaml - 局部模板:以下划线开头,如
_helpers.tpl - 测试文件:放在
templates/tests/目录下 - CRD:放在
crds/目录下(不做模板化)
常用模板
_helpers.tpl
{{/*
标准命名辅助函数
*/}}
{{- define "my-app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "my-app.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- define "my-app.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
通用标签
*/}}
{{- define "my-app.labels" -}}
helm.sh/chart: {{ include "my-app.chart" . }}
{{ include "my-app.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}
{{- define "my-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "my-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
{{/*
镜像名称辅助函数
*/}}
{{- define "my-app.image" -}}
{{- $registry := .Values.global.imageRegistry | default .Values.image.registry -}}
{{- $repository := .Values.image.repository -}}
{{- $tag := .Values.image.tag | default .Chart.AppVersion -}}
{{- printf "%s/%s:%s" $registry $repository $tag -}}
{{- end -}}
NOTES.txt
感谢安装 {{ .Chart.Name }}。
您的 Release 名称为 {{ .Release.Name }}。
查看 Release 详情,请运行:
$ helm status {{ .Release.Name }}
$ helm get all {{ .Release.Name }}
{{- if .Values.ingress.enabled }}
应用访问地址:
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ .host }}{{ .path }}
{{- end }}
{{- else }}
通过以下命令获取应用访问地址:
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "my-app.name" . }}" -o jsonpath="{.items[0].metadata.name}")
kubectl port-forward $POD_NAME 8080:80
echo "访问 http://127.0.0.1:8080"
{{- end }}
依赖管理
声明依赖
# Chart.yaml
dependencies:
- name: postgresql
version: "12.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled # 通过 values 启用/禁用
tags: # 依赖分组
- database
import-values: # 从子 Chart 导入 values
- child: database
parent: database
alias: db # 通过 .Values.db 引用
管理依赖
# 更新依赖
helm dependency update
# 列出依赖
helm dependency list
# 构建依赖
helm dependency build
Chart.lock
由 helm dependency update 自动生成:
dependencies:
- name: postgresql
repository: https://charts.bitnami.com/bitnami
version: 12.0.0
digest: sha256:abcd1234...
generated: "2024-01-01T00:00:00Z" # 生成时间
.helmignore
从 Chart 包中排除的文件:
# 开发文件
.git/
.gitignore
*.md
docs/
# 构建产物
*.swp
*.bak
*.tmp
*.orig
# CI/CD
.travis.yml
.gitlab-ci.yml
Jenkinsfile
# 测试
test/
*.test
# IDE
.vscode/
.idea/
*.iml
自定义资源定义(CRDs)
将 CRD 放在 crds/ 目录下:
crds/
├── my-app-crd.yaml
└── another-crd.yaml
CRD 重要说明:
- CRD 在所有模板之前安装
- CRD 不支持模板化(不可使用
{{ }}语法) - CRD 不会随 Chart 升级或删除
- 使用
helm install --skip-crds可跳过安装
Chart 版本管理
语义化版本
-
Chart 版本:Chart 有变更时递增
- MAJOR:不兼容的破坏性变更
- MINOR:新功能,向后兼容
- PATCH:Bug 修复
-
App 版本:所部署应用的版本号
- 可为任意字符串
- 不强制遵循 SemVer
version: 2.3.1 # Chart 版本
appVersion: "1.5.0" # 应用版本
Chart 测试
测试文件
# templates/tests/test-connection.yaml(连接测试)
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "my-app.fullname" . }}-test-connection"
annotations:
"helm.sh/hook": test
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "my-app.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never
运行测试
helm test my-release
helm test my-release --logs
Hooks(钩子)
Helm Hooks 允许在特定生命周期节点介入执行:
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "my-app.fullname" . }}-migration
annotations:
"helm.sh/hook": pre-upgrade,pre-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
Hook 类型
pre-install:模板渲染前执行post-install:所有资源加载完成后执行pre-delete:任何资源删除前执行post-delete:所有资源删除后执行pre-upgrade:升级前执行post-upgrade:升级后执行pre-rollback:回滚前执行post-rollback:回滚后执行test:配合helm test执行
Hook 权重
控制 Hook 执行顺序(-5 到 5,数值越小越先执行)
Hook 删除策略
before-hook-creation:创建新 Hook 前删除上一个hook-succeeded:执行成功后删除hook-failed:执行失败后删除
最佳实践
- 使用辅助函数处理重复的模板逻辑
- 字符串加引号:
{{ .Values.name | quote }} - 使用 values.schema.json 校验 values
- 在 values.yaml 中注释所有字段
- 使用语义化版本管理 Chart 版本
- 精确锁定依赖版本
- 包含 NOTES.txt 提供使用说明
- 为关键功能编写测试
- 使用 Hooks 处理数据库迁移
- 保持 Chart 职责单一——每个 Chart 只负责一个应用
Chart 仓库结构
helm-charts/
├── index.yaml
├── my-app-1.0.0.tgz
├── my-app-1.1.0.tgz
├── my-app-1.2.0.tgz
└── another-chart-2.0.0.tgz
创建仓库索引
helm repo index . --url https://charts.example.com