2.1 Chart 结构解析
2.1.1 Chart 目录结构
my-app/
├── Chart.yaml # Chart 元数据文件
├── values.yaml # 默认配置值
├── charts/ # 依赖的子 Chart
├── templates/ # 模板文件目录
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── _helpers.tpl # 模板助手函数
│ └── NOTES.txt # 安装后的提示信息
├── .helmignore # 忽略文件列表
└── README.md # Chart 说明文档
2.1.2 Chart.yaml 详解
# Chart.yaml - Chart 元数据
apiVersion: v2
name: my-app
description: A Helm chart for my application
type: application
version: 0.1.0
appVersion: "1.0.0"
# 可选字段
keywords:
- web
- application
- microservice
home: https://example.com
sources:
- https://github.com/example/my-app
maintainers:
- name: John Doe
email: john@example.com
url: https://johndoe.dev
# 依赖声明
dependencies:
- name: postgresql
version: "11.6.12"
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
# 注解
annotations:
category: Application
licenses: Apache-2.0
2.1.3 values.yaml 结构
# values.yaml - 默认配置值
# 应用配置
replicaCount: 1
image:
repository: nginx
pullPolicy: IfNotPresent
tag: "1.21.0"
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
# 服务账户
serviceAccount:
create: true
annotations: {}
name: ""
# Pod 注解和标签
podAnnotations: {}
podLabels: {}
# 安全上下文
podSecurityContext:
fsGroup: 2000
securityContext:
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
# 服务配置
service:
type: ClusterIP
port: 80
targetPort: 8080
# Ingress 配置
ingress:
enabled: false
className: ""
annotations: {}
hosts:
- host: chart-example.local
paths:
- path: /
pathType: Prefix
tls: []
# 资源限制
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
# 自动扩缩容
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# 节点选择
nodeSelector: {}
tolerations: []
affinity: {}
2.2 Go 模板语法基础
2.2.1 模板语法概述
Helm 使用 Go 的 text/template
包进行模板渲染,支持变量替换、条件判断、循环等功能。
graph LR
A[模板文件] --> B[Go Template 引擎]
C[Values] --> B
D[内置对象] --> B
B --> E[渲染后的 YAML]
E --> F[Kubernetes 资源]
2.2.2 基本语法
变量引用
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.nameOverride | default .Chart.Name }}
labels:
app: {{ .Chart.Name }}
version: {{ .Chart.Version }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Chart.Name }}
template:
metadata:
labels:
app: {{ .Chart.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.targetPort }}
条件判断
# templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ include "my-app.fullname" . }}
labels:
{{- include "my-app.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.targetPort }}
protocol: TCP
name: http
selector:
{{- include "my-app.selectorLabels" . | nindent 4 }}
{{- if eq .Values.service.type "LoadBalancer" }}
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
{{- end }}
{{- if .Values.service.annotations }}
annotations:
{{- toYaml .Values.service.annotations | nindent 4 }}
{{- end }}
循环遍历
# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "my-app.fullname" . }}-config
data:
{{- range $key, $value := .Values.config }}
{{ $key }}: {{ $value | quote }}
{{- end }}
# 遍历列表
allowed-hosts: |
{{- range .Values.allowedHosts }}
- {{ . }}
{{- end }}
2.2.3 管道和函数
常用函数
# 字符串处理
name: {{ .Values.name | upper }} # 转大写
name: {{ .Values.name | lower }} # 转小写
name: {{ .Values.name | title }} # 首字母大写
name: {{ .Values.name | quote }} # 添加引号
name: {{ .Values.name | squote }} # 添加单引号
# 默认值
name: {{ .Values.name | default "my-app" }}
port: {{ .Values.port | default 8080 }}
# 类型转换
replicas: {{ .Values.replicas | int }}
enabled: {{ .Values.enabled | bool }}
# 编码
data: {{ .Values.data | b64enc }} # Base64 编码
password: {{ .Values.password | sha256sum }} # SHA256 哈希
# 日期时间
created: {{ now | date "2006-01-02T15:04:05Z" }}
YAML 处理
# toYaml 函数
resources:
{{- toYaml .Values.resources | nindent 2 }}
# 缩进控制
labels:
{{- include "my-app.labels" . | nindent 4 }}
# 去除空白
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
2.3 内置对象详解
2.3.1 根对象
# .Values - 来自 values.yaml 和用户提供的值
image: {{ .Values.image.repository }}
# .Chart - Chart.yaml 中的信息
name: {{ .Chart.Name }}
version: {{ .Chart.Version }}
# .Release - 当前 Release 信息
release-name: {{ .Release.Name }}
release-namespace: {{ .Release.Namespace }}
release-service: {{ .Release.Service }}
# .Capabilities - Kubernetes 集群能力
api-version: {{ .Capabilities.APIVersions.Has "apps/v1" }}
kube-version: {{ .Capabilities.KubeVersion.Version }}
# .Template - 当前模板信息
template-name: {{ .Template.Name }}
template-basepath: {{ .Template.BasePath }}
2.3.2 .Values 对象使用
# 访问嵌套值
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
# 使用 with 简化访问
{{- with .Values.image }}
image: {{ .repository }}:{{ .tag }}
pullPolicy: {{ .pullPolicy }}
{{- end }}
# 检查值是否存在
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
# ...
{{- end }}
2.3.3 .Chart 对象应用
# 使用 Chart 信息作为标签
labels:
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
# 生成资源名称
name: {{ .Chart.Name }}-{{ .Release.Name }}
2.4 模板助手函数
2.4.1 _helpers.tpl 文件
{{/*
_helpers.tpl - 模板助手函数定义
*/}}
{{/*
展开 Chart 全名
*/}}
{{- 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 }}
{{/*
创建 Chart 名称和版本标签
*/}}
{{- 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.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "my-app.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
生成安全的资源名称
*/}}
{{- define "my-app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
2.4.2 使用助手函数
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-app.fullname" . }}
labels:
{{- include "my-app.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "my-app.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "my-app.selectorLabels" . | nindent 8 }}
spec:
serviceAccountName: {{ include "my-app.serviceAccountName" . }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
2.5 实践练习
2.5.1 练习1:创建基础 Chart
# 1. 创建新的 Chart
helm create web-app
cd web-app
# 2. 查看生成的文件结构
tree .
# 3. 检查模板语法
helm lint .
# 4. 渲染模板查看输出
helm template my-release .
# 5. 安装测试
helm install my-web-app . --dry-run --debug
2.5.2 练习2:自定义模板
# 修改 values.yaml
replicaCount: 2
image:
repository: nginx
tag: "1.21.0"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
targetPort: 80
# 添加自定义配置
config:
server_name: "my-web-app"
worker_processes: "auto"
client_max_body_size: "1m"
allowedHosts:
- "example.com"
- "www.example.com"
- "api.example.com"
# 创建 templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "web-app.fullname" . }}-config
labels:
{{- include "web-app.labels" . | nindent 4 }}
data:
nginx.conf: |
server {
listen {{ .Values.service.targetPort }};
server_name {{ .Values.config.server_name }};
{{- range .Values.allowedHosts }}
# Allow {{ . }}
{{- end }}
client_max_body_size {{ .Values.config.client_max_body_size }};
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
{{- range $key, $value := .Values.config }}
{{ $key }}: {{ $value | quote }}
{{- end }}
2.5.3 练习3:条件渲染
# 修改 values.yaml 添加功能开关
features:
monitoring: true
logging: false
backup: true
monitoring:
enabled: true
port: 9090
path: "/metrics"
logging:
level: "info"
format: "json"
# 创建 templates/monitoring.yaml
{{- if .Values.features.monitoring }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "web-app.fullname" . }}-monitoring
labels:
{{- include "web-app.labels" . | nindent 4 }}
component: monitoring
spec:
type: ClusterIP
ports:
- port: {{ .Values.monitoring.port }}
targetPort: monitoring
protocol: TCP
name: monitoring
selector:
{{- include "web-app.selectorLabels" . | nindent 4 }}
---
apiVersion: v1
kind: ServiceMonitor
metadata:
name: {{ include "web-app.fullname" . }}
labels:
{{- include "web-app.labels" . | nindent 4 }}
spec:
selector:
matchLabels:
{{- include "web-app.selectorLabels" . | nindent 6 }}
component: monitoring
endpoints:
- port: monitoring
path: {{ .Values.monitoring.path }}
{{- end }}
2.6 调试和验证
2.6.1 模板调试技巧
# 1. 语法检查
helm lint my-chart/
# 2. 渲染模板(不安装)
helm template my-release my-chart/
# 3. 调试模式渲染
helm template my-release my-chart/ --debug
# 4. 指定 Values 文件
helm template my-release my-chart/ -f custom-values.yaml
# 5. 设置特定值
helm template my-release my-chart/ --set replicaCount=3
# 6. 只渲染特定模板
helm template my-release my-chart/ -s templates/deployment.yaml
2.6.2 常见错误和解决
# 错误1:模板语法错误
# Error: template: my-chart/templates/deployment.yaml:10:14:
# executing "my-chart/templates/deployment.yaml" at <.Values.image.tag>:
# nil pointer evaluating interface {}.tag
# 解决:检查 Values 路径是否正确
{{- with .Values.image }}
image: {{ .repository }}:{{ .tag | default "latest" }}
{{- end }}
# 错误2:缩进问题
# Error: YAML parse error on my-chart/templates/service.yaml
# 解决:使用正确的缩进函数
labels:
{{- include "my-app.labels" . | nindent 4 }}
# 错误3:未定义的模板函数
# Error: template: my-chart/templates/deployment.yaml:5:22:
# executing "my-chart/templates/deployment.yaml" at <include "my-app.fullname" .>:
# error calling include: template: no template "my-app.fullname" associated with template
# 解决:确保在 _helpers.tpl 中定义了函数
2.7 本章小结
2.7.1 核心概念回顾
- Chart 结构:标准的目录布局和文件组织
- 模板语法:Go template 的基本语法和高级特性
- 内置对象:.Values、.Chart、.Release 等对象的使用
- 助手函数:可重用的模板片段定义和调用
2.7.2 技术要点总结
- 文件组织:合理的目录结构和文件命名
- 语法掌握:变量引用、条件判断、循环遍历
- 函数应用:内置函数和自定义函数的使用
- 调试技能:模板渲染和错误排查方法
- 最佳实践:代码复用和可维护性
2.7.3 最佳实践
- 使用有意义的变量名和注释
- 合理使用助手函数避免重复代码
- 添加适当的条件判断和默认值
- 保持模板的简洁和可读性
- 定期进行语法检查和测试
2.7.4 下一章预告
下一章我们将深入学习 Values 文件与配置管理,包括: - Values 文件的层级结构 - 配置覆盖和合并机制 - 环境特定配置管理 - 配置验证和约束
通过下一章的学习,你将掌握如何灵活地管理不同环境的配置。