1. Helm 简介
Helm 是 Kubernetes 的包管理器,被称为"Kubernetes 的 apt/yum"。它简化了 Kubernetes 应用的部署、管理和版本控制,通过模板化的方式管理复杂的 Kubernetes 配置。
1.1 核心概念
- Chart: Helm 包,包含运行应用所需的所有 Kubernetes 资源定义
- Release: Chart 在 Kubernetes 集群中的一个实例
- Repository: 存储和分享 Charts 的地方
- Values: 用于自定义 Chart 配置的参数
1.2 Helm 架构演进
Helm v2 (已弃用) Helm v3 (当前版本)
┌─────────────┐ ┌─────────────┐
│ Helm │ │ Helm │
│ Client │ --> │ Client │
└─────────────┘ └─────────────┘
│ │
v v
┌─────────────┐ ┌─────────────┐
│ Tiller │ │ Kubernetes │
│ (Server) │ │ API │
└─────────────┘ └─────────────┘
2. Helm 安装和配置
2.1 安装 Helm
# 方式一:使用脚本安装
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# 方式二:使用包管理器
# macOS
brew install helm
# Ubuntu/Debian
curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get update
sudo apt-get install helm
# Windows (使用 Chocolatey)
choco install kubernetes-helm
# 方式三:直接下载二进制文件
wget https://get.helm.sh/helm-v3.13.0-linux-amd64.tar.gz
tar -zxvf helm-v3.13.0-linux-amd64.tar.gz
sudo mv linux-amd64/helm /usr/local/bin/helm
2.2 验证安装
# 查看版本
helm version
# 查看帮助
helm help
# 初始化(可选,添加官方仓库)
helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
3. Chart 结构详解
3.1 标准 Chart 目录结构
mychart/
├── Chart.yaml # Chart 元数据
├── values.yaml # 默认配置值
├── charts/ # 依赖的子 Charts
├── templates/ # 模板文件
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── _helpers.tpl # 模板辅助函数
│ └── NOTES.txt # 安装后显示的说明
├── .helmignore # 忽略文件列表
└── README.md # 文档
3.2 Chart.yaml 文件
# Chart.yaml
apiVersion: v2
name: mychart
description: A Helm chart for my application
type: application
version: 0.1.0 # Chart 版本
appVersion: "1.0.0" # 应用版本
maintainers:
- name: Your Name
email: your.email@example.com
home: https://github.com/yourname/mychart
sources:
- https://github.com/yourname/myapp
dependencies:
- name: redis
version: "^17.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled
keywords:
- web
- application
- microservice
3.3 values.yaml 文件
# values.yaml - 默认配置
replicaCount: 1
image:
repository: nginx
pullPolicy: IfNotPresent
tag: "1.21.0"
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
service:
type: ClusterIP
port: 80
targetPort: 8080
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: {}
# 应用特定配置
config:
database:
host: "localhost"
port: 5432
name: "myapp"
redis:
host: "redis-service"
port: 6379
logLevel: "info"
4. 模板语法详解
4.1 基本模板语法
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "mychart.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
labels:
{{- include "mychart.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
env:
- name: DATABASE_URL
value: "postgresql://{{ .Values.config.database.host }}:{{ .Values.config.database.port }}/{{ .Values.config.database.name }}"
- name: REDIS_URL
value: "redis://{{ .Values.config.redis.host }}:{{ .Values.config.redis.port }}"
- name: LOG_LEVEL
value: {{ .Values.config.logLevel | quote }}
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: http
initialDelaySeconds: 5
periodSeconds: 5
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
4.2 模板辅助函数
# templates/_helpers.tpl
{{/*
展开 chart 的名称
*/}}
{{- define "mychart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
创建完整的名称
*/}}
{{- define "mychart.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 "mychart.labels" -}}
helm.sh/chart: {{ include "mychart.chart" . }}
{{ include "mychart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
选择器标签
*/}}
{{- define "mychart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "mychart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Chart 版本
*/}}
{{- define "mychart.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
4.3 条件和循环
# 条件渲染
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "mychart.fullname" . }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "mychart.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}
# 循环示例
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
5. Helm 命令详解
5.1 Chart 管理命令
# 创建新 Chart
helm create mychart
# 验证 Chart 语法
helm lint mychart/
# 渲染模板(不安装)
helm template my-release mychart/
# 打包 Chart
helm package mychart/
# 查看 Chart 信息
helm show chart mychart/
helm show values mychart/
helm show readme mychart/
# 检查 Chart 依赖
helm dependency list mychart/
helm dependency update mychart/
5.2 Release 管理命令
# 安装 Chart
helm install my-release mychart/
# 使用自定义值文件安装
helm install my-release mychart/ -f custom-values.yaml
# 设置特定值
helm install my-release mychart/ --set image.tag=v2.0.0
# 从仓库安装
helm install my-nginx bitnami/nginx
# 升级 Release
helm upgrade my-release mychart/ -f new-values.yaml
# 回滚 Release
helm rollback my-release 1
# 卸载 Release
helm uninstall my-release
# 保留历史记录卸载
helm uninstall my-release --keep-history
5.3 查看和调试命令
# 列出所有 Release
helm list
helm list --all-namespaces
# 查看 Release 状态
helm status my-release
# 查看 Release 历史
helm history my-release
# 获取 Release 的 values
helm get values my-release
# 获取 Release 的 manifest
helm get manifest my-release
# 获取完整信息
helm get all my-release
# 调试安装(不实际安装)
helm install my-release mychart/ --debug --dry-run
5.4 仓库管理命令
# 添加仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add elastic https://helm.elastic.co
# 列出仓库
helm repo list
# 更新仓库索引
helm repo update
# 搜索 Chart
helm search repo nginx
helm search hub wordpress
# 移除仓库
helm repo remove bitnami
6. 高级功能和最佳实践
6.1 依赖管理
# Chart.yaml 中定义依赖
dependencies:
- name: postgresql
version: "^12.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
- name: redis
version: "^17.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled
tags:
- cache
- name: common
version: "^2.0.0"
repository: "https://charts.bitnami.com/bitnami"
# 更新依赖
helm dependency update mychart/
# 构建依赖
helm dependency build mychart/
6.2 Hooks 和测试
# templates/post-install-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ include "mychart.fullname" . }}-post-install"
annotations:
"helm.sh/hook": post-install
"helm.sh/hook-weight": "1"
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
spec:
restartPolicy: Never
containers:
- name: post-install
image: busybox
command: ['sh', '-c', 'echo "Post-install hook executed"']
# templates/tests/connection-test.yaml
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "mychart.fullname" . }}-test-connection"
annotations:
"helm.sh/hook": test
spec:
restartPolicy: Never
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "mychart.fullname" . }}:{{ .Values.service.port }}']
# 运行测试
helm test my-release
6.3 子 Chart 和全局值
# 父 Chart 的 values.yaml
global:
imageRegistry: "my-registry.com"
storageClass: "fast-ssd"
postgresql:
enabled: true
auth:
postgresPassword: "mypassword"
redis:
enabled: true
auth:
enabled: false
# 在模板中使用全局值
image: "{{ .Values.global.imageRegistry }}/{{ .Values.image.repository }}"
6.4 命名模板和库 Chart
# library-chart/templates/_common.tpl
{{- define "common.deployment" -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "common.fullname" . }}
labels:
{{- include "common.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "common.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "common.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
{{- end }}
# 在应用 Chart 中使用
{{- template "common.deployment" . }}
7. 安全和最佳实践
7.1 安全配置
# 使用 Secret 管理敏感信息
apiVersion: v1
kind: Secret
metadata:
name: {{ include "mychart.fullname" . }}-secret
type: Opaque
data:
database-password: {{ .Values.database.password | b64enc }}
api-key: {{ .Values.apiKey | b64enc }}
# RBAC 配置
{{- if .Values.rbac.create }}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "mychart.fullname" . }}
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
{{- end }}
7.2 最佳实践
# 1. 使用语义版本控制
version: 1.2.3
# 2. 验证和测试
helm lint mychart/
helm template my-release mychart/ | kubectl apply --dry-run=client -f -
# 3. 使用 .helmignore
echo "*.tmp" >> .helmignore
echo ".git/" >> .helmignore
# 4. 文档化
# 在 README.md 中记录配置选项
# 在 NOTES.txt 中提供使用说明
7.3 多环境配置
# values-dev.yaml
replicaCount: 1
resources:
requests:
memory: "64Mi"
cpu: "250m"
# values-prod.yaml
replicaCount: 3
resources:
requests:
memory: "512Mi"
cpu: "500m"
# 部署到不同环境
helm install my-app-dev mychart/ -f values-dev.yaml
helm install my-app-prod mychart/ -f values-prod.yaml
8. 插件和生态系统
8.1 常用插件
# 安装插件管理器
helm plugin install https://github.com/databus23/helm-diff
# Helm Diff - 比较变更
helm diff upgrade my-release mychart/
# Helm Secrets - 管理加密配置
helm plugin install https://github.com/jkroepke/helm-secrets
helm secrets install my-release mychart/ -f secrets.yaml
# Helm Push - 推送到仓库
helm plugin install https://github.com/chartmuseum/helm-push
helm push mychart/ my-repo
# 查看已安装插件
helm plugin list
8.2 Chart 仓库
# 官方仓库
helm repo add stable https://charts.helm.sh/stable
helm repo add incubator https://charts.helm.sh/incubator
# 第三方仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add elastic https://helm.elastic.co
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add grafana https://grafana.github.io/helm-charts
helm repo add jetstack https://charts.jetstack.io
# 私有仓库
helm repo add myrepo https://charts.example.com --username user --password pass
9. 故障排除和调试
9.1 常见问题诊断
# 检查 Chart 语法
helm lint mychart/
# 渲染模板查看输出
helm template my-release mychart/ --debug
# 检查 Release 状态
helm status my-release
# 查看详细错误信息
kubectl describe pod <pod-name>
kubectl logs <pod-name>
# 检查 Kubernetes 事件
kubectl get events --sort-by=.metadata.creationTimestamp
# 验证资源创建
kubectl get all -l app.kubernetes.io/instance=my-release
9.2 调试技巧
# 在模板中添加调试信息
{{- if .Values.debug }}
# DEBUG: Values dump
{{ toYaml .Values | indent 2 }}
{{- end }}
# 使用 fail 函数进行验证
{{- if not .Values.database.host }}
{{- fail "Database host is required" }}
{{- end }}
# 条件调试
{{- $debug := .Values.debug | default false }}
{{- if $debug }}
annotations:
debug/values: {{ toJson .Values | quote }}
{{- end }}
10. 实际应用示例
10.1 完整的 Web 应用部署
# Chart.yaml
apiVersion: v2
name: webapp
description: A complete web application
version: 0.1.0
appVersion: "1.0.0"
dependencies:
- name: postgresql
version: "^12.0.0"
repository: "https://charts.bitnami.com/bitnami"
- name: redis
version: "^17.0.0"
repository: "https://charts.bitnami.com/bitnami"
# values.yaml
image:
repository: myapp/webapp
tag: "v1.0.0"
service:
type: LoadBalancer
port: 80
ingress:
enabled: true
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: myapp.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: myapp-tls
hosts:
- myapp.example.com
postgresql:
enabled: true
auth:
postgresPassword: "secretpassword"
database: "webapp"
redis:
enabled: true
auth:
enabled: false
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
10.2 微服务架构部署
# umbrella-chart/Chart.yaml
apiVersion: v2
name: microservices-app
description: Microservices application umbrella chart
version: 0.1.0
dependencies:
- name: user-service
version: "^0.1.0"
repository: "file://../user-service"
- name: order-service
version: "^0.1.0"
repository: "file://../order-service"
- name: api-gateway
version: "^0.1.0"
repository: "file://../api-gateway"
- name: postgresql
version: "^12.0.0"
repository: "https://charts.bitnami.com/bitnami"
# values.yaml
global:
imageRegistry: "myregistry.com"
database:
host: "postgres-service"
port: 5432
user-service:
enabled: true
replicaCount: 2
order-service:
enabled: true
replicaCount: 3
api-gateway:
enabled: true
replicaCount: 2
service:
type: LoadBalancer
10.3 部署脚本示例
#!/bin/bash
# deploy.sh
set -e
NAMESPACE=${1:-default}
ENVIRONMENT=${2:-development}
RELEASE_NAME="myapp-${ENVIRONMENT}"
echo "Deploying to ${NAMESPACE} namespace in ${ENVIRONMENT} environment"
# 创建 namespace(如果不存在)
kubectl create namespace ${NAMESPACE} --dry-run=client -o yaml | kubectl apply -f -
# 添加必要的仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# 安装或升级应用
if helm list -n ${NAMESPACE} | grep -q ${RELEASE_NAME}; then
echo "Upgrading ${RELEASE_NAME}..."
helm upgrade ${RELEASE_NAME} ./mychart \
-n ${NAMESPACE} \
-f values-${ENVIRONMENT}.yaml \
--wait \
--timeout=300s
else
echo "Installing ${RELEASE_NAME}..."
helm install ${RELEASE_NAME} ./mychart \
-n ${NAMESPACE} \
-f values-${ENVIRONMENT}.yaml \
--wait \
--timeout=300s
fi
# 运行测试
echo "Running tests..."
helm test ${RELEASE_NAME} -n ${NAMESPACE}
echo "Deployment completed successfully!"
11. 总结
Helm 是 Kubernetes 生态系统中不可或缺的工具,它通过以下方式简化了应用部署:
核心优势
- 模板化: 通过 Go 模板实现配置的参数化
- 版本管理: 支持应用的版本控制和回滚
- 依赖管理: 自动处理复杂的依赖关系
- 生态丰富: 庞大的 Chart 仓库和社区支持
适用场景
- 复杂应用部署: 多组件应用的统一管理
- 多环境部署: 通过不同的 values 文件管理多环境
- CI/CD 集成: 自动化部署流水线
- 应用分发: Chart 仓库实现应用的打包和分发
学习建议
- 从简单的 Chart 开始,逐步掌握模板语法
- 理解 Kubernetes 资源模型是使用 Helm 的基础
- 多实践,通过部署实际应用加深理解
- 关注 Helm 社区和最佳实践的发展
Helm 作为 Kubernetes 的包管理器,极大地简化了在 Kubernetes 上部署和管理应用的复杂性,是每个 Kubernetes 开发者和运维人员必须掌握的重要工具。