Helm包管理实战
一、概述
1.1 背景介绍
直接用kubectl管理K8s资源,10个微服务就要维护几十个YAML文件,版本管理靠文件夹命名,回滚靠手动替换文件。Helm把一组相关的K8s资源打包成Chart,支持模板化、版本管理、一键部署和回滚,是K8s生态中事实上的包管理标准。
生产环境中的痛点:开发团队每次部署都要改十几个YAML里的镜像版本、副本数、资源限制,改漏一个就出问题。用Helm后,这些可变参数抽成values.yaml,部署时只需要helm upgrade -f prod-values.yaml一条命令,CI/CD流水线也更容易集成。
本文基于Helm v3.13.x版本,覆盖Chart开发、仓库管理、生产部署、回滚策略等内容。Helm v2已于2020年停止维护,不再讨论。
1.2 技术特点
模板引擎:基于Go template,支持变量、条件判断、循环、函数,一套模板适配多环境
Release管理:每次安装/升级都是一个Release,记录完整的版本历史,支持一键回滚到任意版本
依赖管理:Chart可以声明对其他Chart的依赖,自动拉取和安装子Chart
仓库生态:Artifact Hub上有数千个社区Chart,常用中间件(MySQL、Redis、Kafka)开箱即用
1.3 适用场景
场景一:多环境部署(dev/staging/prod),同一套Chart用不同的values文件区分配置
场景二:CI/CD流水线集成,Jenkins/GitLab CI中用helm命令自动化部署
场景三:复杂应用编排,一个Chart包含Deployment、Service、ConfigMap、Ingress等多个资源
场景四:第三方中间件部署,用社区Chart快速部署Prometheus、Grafana、Nginx Ingress等
1.4 环境要求
| 组件 | 版本要求 | 说明 |
|---|---|---|
| Kubernetes | 1.24+ | Helm 3.13支持K8s 1.24-1.28 |
| Helm | 3.13+ | 当前稳定版本 |
| kubectl | 与集群版本匹配 | Helm依赖kubeconfig访问集群 |
| OCI Registry | Harbor 2.x / Docker Registry | 存储Helm Chart的OCI仓库 |
二、详细步骤
2.1 准备工作
2.1.1 安装Helm
# 方式一:官方脚本安装
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# 方式二:手动下载
wget https://get.helm.sh/helm-v3.13.3-linux-amd64.tar.gz
tar xzf helm-v3.13.3-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/helm
# 验证
helm version
# version.BuildInfo{Version:"v3.13.3", ...}
# 配置命令补全
helm completion bash > /etc/bash_completion.d/helm
source /etc/bash_completion.d/helm
2.1.2 配置Chart仓库
# 添加常用仓库 helm repo add bitnami https://charts.bitnami.com/bitnami 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 ingress-nginx https://kubernetes.github.io/ingress-nginx # 更新仓库索引 helm repo update # 查看已添加的仓库 helm repo list # 搜索Chart helm search repo nginx helm search repo mysql --versions # 查看所有版本 # 搜索Artifact Hub helm search hub prometheus
2.1.3 Helm基本操作
# 查看Chart信息 helm show chart bitnami/nginx helm show values bitnami/nginx # 查看默认values helm show readme bitnami/nginx # 安装Chart helm install my-nginx bitnami/nginx -n web --create-namespace # 查看Release helm list -A helm status my-nginx -n web # 查看Release历史 helm history my-nginx -n web # 升级Release helm upgrade my-nginx bitnami/nginx -n web --set replicaCount=3 # 回滚 helm rollback my-nginx 1 -n web # 回滚到版本1 # 卸载 helm uninstall my-nginx -n web
2.2 核心配置
2.2.1 创建自定义Chart
# 创建Chart骨架 helm create myapp # 目录结构 # myapp/ # ├── Chart.yaml # Chart元数据 # ├── values.yaml # 默认配置值 # ├── charts/ # 依赖Chart # ├── templates/ # 模板文件 # │ ├── deployment.yaml # │ ├── service.yaml # │ ├── ingress.yaml # │ ├── hpa.yaml # │ ├── serviceaccount.yaml # │ ├── configmap.yaml # │ ├── _helpers.tpl # 模板辅助函数 # │ ├── NOTES.txt # 安装后提示信息 # │ └── tests/ # │ └── test-connection.yaml # └── .helmignore # 打包时忽略的文件
Chart.yaml定义:
# 文件:myapp/Chart.yaml apiVersion:v2 name:myapp description:ProductionbackendAPIservice type:application version:1.0.0 appVersion:"2.1.0" keywords: -api -backend maintainers: -name:ops-team email:ops@company.com dependencies: -name:redis version:"18.x.x" repository:"https://charts.bitnami.com/bitnami" condition:redis.enabled -name:postgresql version:"13.x.x" repository:"https://charts.bitnami.com/bitnami" condition:postgresql.enabled
2.2.2 编写values.yaml
# 文件:myapp/values.yaml
# 镜像配置
image:
repository:registry.company.com/backend/myapp
tag:""# 默认使用Chart的appVersion
pullPolicy:IfNotPresent
imagePullSecrets:
-name:registry-secret
# 副本数
replicaCount:3
# 资源限制
resources:
requests:
cpu:200m
memory:256Mi
limits:
cpu:"1"
memory:1Gi
# Service配置
service:
type:ClusterIP
port:8080
# Ingress配置
ingress:
enabled:true
className:nginx
annotations:
nginx.ingress.kubernetes.io/proxy-body-size:"50m"
nginx.ingress.kubernetes.io/proxy-read-timeout:"60"
hosts:
-host:api.company.com
paths:
-path:/
pathType:Prefix
tls:
-secretName:api-tls
hosts:
-api.company.com
# HPA自动伸缩
autoscaling:
enabled:true
minReplicas:3
maxReplicas:20
targetCPUUtilizationPercentage:70
targetMemoryUtilizationPercentage:80
# 健康检查
livenessProbe:
httpGet:
path:/health
port:http
initialDelaySeconds:30
periodSeconds:10
failureThreshold:3
readinessProbe:
httpGet:
path:/ready
port:http
initialDelaySeconds:10
periodSeconds:5
failureThreshold:3
# 环境变量
env:
-name:APP_ENV
value:"production"
-name:LOG_LEVEL
value:"info"
-name:DB_HOST
valueFrom:
secretKeyRef:
name:myapp-db-secret
key:host
# ConfigMap数据
config:
app.conf:|
server.port=8080
server.graceful-shutdown=30s
cache.ttl=300
# 持久化存储
persistence:
enabled:false
storageClass:"ceph-rbd"
size:10Gi
# Pod调度
nodeSelector:{}
tolerations:[]
affinity:{}
topologySpreadConstraints:
-maxSkew:1
topologyKey:topology.kubernetes.io/zone
whenUnsatisfiable:DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/name:myapp
# 依赖服务开关
redis:
enabled:true
architecture:standalone
auth:
password:"redis-password"
postgresql:
enabled:false
2.2.3 编写模板文件
Deployment模板:
# 文件:myapp/templates/deployment.yaml
apiVersion:apps/v1
kind:Deployment
metadata:
name:{{include"myapp.fullname".}}
labels:
{{-include"myapp.labels".|nindent4}}
spec:
{{-ifnot.Values.autoscaling.enabled}}
replicas:{{.Values.replicaCount}}
{{-end}}
selector:
matchLabels:
{{-include"myapp.selectorLabels".|nindent6}}
strategy:
type:RollingUpdate
rollingUpdate:
maxSurge:25%
maxUnavailable:0
template:
metadata:
annotations:
checksum/config:{{include(print$.Template.BasePath"/configmap.yaml").|sha256sum}}
labels:
{{-include"myapp.selectorLabels".|nindent8}}
spec:
{{-with.Values.imagePullSecrets}}
imagePullSecrets:
{{-toYaml.|nindent8}}
{{-end}}
serviceAccountName:{{include"myapp.serviceAccountName".}}
securityContext:
runAsNonRoot:true
runAsUser:1000
fsGroup:1000
containers:
-name:{{.Chart.Name}}
image:"{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy:{{.Values.image.pullPolicy}}
ports:
-name:http
containerPort:{{.Values.service.port}}
protocol:TCP
{{-with.Values.env}}
env:
{{-toYaml.|nindent12}}
{{-end}}
{{-with.Values.livenessProbe}}
livenessProbe:
{{-toYaml.|nindent12}}
{{-end}}
{{-with.Values.readinessProbe}}
readinessProbe:
{{-toYaml.|nindent12}}
{{-end}}
resources:
{{-toYaml.Values.resources|nindent12}}
volumeMounts:
-name:config
mountPath:/app/config
readOnly:true
{{-if.Values.persistence.enabled}}
-name:data
mountPath:/app/data
{{-end}}
volumes:
-name:config
configMap:
name:{{include"myapp.fullname".}}-config
{{-if.Values.persistence.enabled}}
-name:data
persistentVolumeClaim:
claimName:{{include"myapp.fullname".}}-data
{{-end}}
{{-with.Values.nodeSelector}}
nodeSelector:
{{-toYaml.|nindent8}}
{{-end}}
{{-with.Values.tolerations}}
tolerations:
{{-toYaml.|nindent8}}
{{-end}}
{{-with.Values.topologySpreadConstraints}}
topologySpreadConstraints:
{{-toYaml.|nindent8}}
{{-end}}
说明:
checksum/config注解:ConfigMap内容变化时自动触发Pod滚动更新,不加这个的话改了ConfigMap但Pod不会重启
maxUnavailable: 0:滚动更新时不允许有Pod不可用,保证零停机部署
securityContext:以非root用户运行,生产安全基线
辅助函数模板:
# 文件:myapp/templates/_helpers.tpl
{{/*
生成应用全名
*/}}
{{-define"myapp.fullname"-}}
{{-if.Values.fullnameOverride}}
{{-.Values.fullnameOverride|trunc63|trimSuffix"-"}}
{{-else}}
{{-$name:=default.Chart.Name.Values.nameOverride}}
{{-ifcontains$name.Release.Name}}
{{-.Release.Name|trunc63|trimSuffix"-"}}
{{-else}}
{{-printf"%s-%s".Release.Name$name|trunc63|trimSuffix"-"}}
{{-end}}
{{-end}}
{{-end}}
{{/*
通用标签
*/}}
{{-define"myapp.labels"-}}
helm.sh/chart:{{include"myapp.chart".}}
{{include"myapp.selectorLabels".}}
app.kubernetes.io/version:{{.Chart.AppVersion|quote}}
app.kubernetes.io/managed-by:{{.Release.Service}}
{{-end}}
{{/*
选择器标签
*/}}
{{-define"myapp.selectorLabels"-}}
app.kubernetes.io/name:{{include"myapp.name".}}
app.kubernetes.io/instance:{{.Release.Name}}
{{-end}}
{{/*
Chart名称
*/}}
{{-define"myapp.name"-}}
{{-default.Chart.Name.Values.nameOverride|trunc63|trimSuffix"-"}}
{{-end}}
{{/*
Chart版本标签
*/}}
{{-define"myapp.chart"-}}
{{-printf"%s-%s".Chart.Name.Chart.Version|replace"+""_"|trunc63|trimSuffix"-"}}
{{-end}}
{{/*
ServiceAccount名称
*/}}
{{-define"myapp.serviceAccountName"-}}
{{-default(include"myapp.fullname".).Values.serviceAccount.name}}
{{-end}}
2.2.4 多环境values文件
# 文件:values-dev.yaml(开发环境覆盖) replicaCount:1 image: tag:"latest" pullPolicy:Always resources: requests: cpu:100m memory:128Mi limits: cpu:500m memory:512Mi ingress: enabled:true hosts: -host:api-dev.company.com paths: -path:/ pathType:Prefix tls:[] autoscaling: enabled:false env: -name:APP_ENV value:"development" -name:LOG_LEVEL value:"debug"
# 文件:values-prod.yaml(生产环境覆盖) replicaCount:5 image: tag:"2.1.0" resources: requests: cpu:500m memory:512Mi limits: cpu:"2" memory:2Gi autoscaling: enabled:true minReplicas:5 maxReplicas:30 env: -name:APP_ENV value:"production" -name:LOG_LEVEL value:"warn"
2.2.5 Chart打包和发布
# 更新依赖 helm dependency update myapp/ helm dependency build myapp/ # 模板渲染测试(不实际部署,只看生成的YAML) helm template myapp-release myapp/ -f values-prod.yaml -n production # Lint检查 helm lint myapp/ # 打包 helm package myapp/ # 输出:myapp-1.0.0.tgz # 推送到OCI仓库(Harbor) helm push myapp-1.0.0.tgz oci://harbor.company.com/helm-charts # 推送到ChartMuseum curl --data-binary "@myapp-1.0.0.tgz" http://chartmuseum.company.com/api/charts
2.3 启动和验证
2.3.1 部署到各环境
# 部署到开发环境 helm upgrade --install myapp-dev myapp/ -f values-dev.yaml -n dev --create-namespace --wait --timeout 5m # 部署到生产环境 helm upgrade --install myapp-prod myapp/ -f values-prod.yaml -n production --create-namespace --wait --timeout 10m --atomic # --atomic:部署失败自动回滚到上一个版本 # --wait:等待所有Pod Ready才算成功 # --timeout:超时时间,超时视为失败
2.3.2 验证部署
# 查看Release状态 helm status myapp-prod -n production # 查看实际生成的资源 helm get manifest myapp-prod -n production # 查看使用的values helm get values myapp-prod -n production # 查看所有信息 helm get all myapp-prod -n production # 验证Pod运行 kubectl get pods -n production -l app.kubernetes.io/name=myapp kubectl get svc -n production -l app.kubernetes.io/name=myapp kubectl get ingress -n production
2.3.3 版本管理和回滚
# 查看Release历史 helm history myapp-prod -n production # REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION # 1 2024-01-15 1000 superseded myapp-1.0.0 2.0.0 Install complete # 2 2024-01-20 1400 superseded myapp-1.1.0 2.1.0 Upgrade complete # 3 2024-01-25 0900 deployed myapp-1.2.0 2.2.0 Upgrade complete # 回滚到指定版本 helm rollback myapp-prod 2 -n production --wait # 查看两个版本的差异 helm diff upgrade myapp-prod myapp/ -f values-prod.yaml -n production # 需要安装helm-diff插件:helm plugin install https://github.com/databus23/helm-diff
三、示例代码和配置
3.1 完整配置示例
3.1.1 Ingress模板
# 文件:myapp/templates/ingress.yaml
{{-if.Values.ingress.enabled-}}
apiVersion:networking.k8s.io/v1
kind:Ingress
metadata:
name:{{include"myapp.fullname".}}
labels:
{{-include"myapp.labels".|nindent4}}
{{-with.Values.ingress.annotations}}
annotations:
{{-toYaml.|nindent4}}
{{-end}}
spec:
{{-if.Values.ingress.className}}
ingressClassName:{{.Values.ingress.className}}
{{-end}}
{{-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"myapp.fullname"$}}
port:
number:{{$.Values.service.port}}
{{-end}}
{{-end}}
{{-end}}
3.1.2 HPA模板
# 文件:myapp/templates/hpa.yaml
{{-if.Values.autoscaling.enabled}}
apiVersion:autoscaling/v2
kind:HorizontalPodAutoscaler
metadata:
name:{{include"myapp.fullname".}}
labels:
{{-include"myapp.labels".|nindent4}}
spec:
scaleTargetRef:
apiVersion:apps/v1
kind:Deployment
name:{{include"myapp.fullname".}}
minReplicas:{{.Values.autoscaling.minReplicas}}
maxReplicas:{{.Values.autoscaling.maxReplicas}}
metrics:
{{-if.Values.autoscaling.targetCPUUtilizationPercentage}}
-type:Resource
resource:
name:cpu
target:
type:Utilization
averageUtilization:{{.Values.autoscaling.targetCPUUtilizationPercentage}}
{{-end}}
{{-if.Values.autoscaling.targetMemoryUtilizationPercentage}}
-type:Resource
resource:
name:memory
target:
type:Utilization
averageUtilization:{{.Values.autoscaling.targetMemoryUtilizationPercentage}}
{{-end}}
behavior:
scaleDown:
stabilizationWindowSeconds:300
policies:
-type:Percent
value:10
periodSeconds:60
scaleUp:
stabilizationWindowSeconds:30
policies:
-type:Percent
value:50
periodSeconds:60
-type:Pods
value:4
periodSeconds:60
selectPolicy:Max
{{-end}}
注意:HPA的scaleDown.stabilizationWindowSeconds: 300表示缩容前等待5分钟,防止流量波动导致频繁缩扩容。生产环境这个值不要设太小,实测设为60秒时一天内缩扩容了200多次。
3.1.3 CI/CD集成脚本
#!/bin/bash
# 文件:deploy.sh
# GitLab CI/Jenkins中调用的部署脚本
set -euo pipefail
# 参数
RELEASE_NAME="${1:?Usage: deploy.sh }"
NAMESPACE="${2:?}"
ENV="${3:?}"
CHART_PATH="./helm/myapp"
VALUES_FILE="./helm/values-${ENV}.yaml"
IMAGE_TAG="${CI_COMMIT_SHORT_SHA:-latest}"
echo"=== Deploying ${RELEASE_NAME} to ${NAMESPACE} (${ENV}) ==="
echo"Image tag: ${IMAGE_TAG}"
# Lint检查
helm lint "${CHART_PATH}" -f "${VALUES_FILE}"
# Dry-run验证
helm upgrade --install "${RELEASE_NAME}""${CHART_PATH}"
-f "${VALUES_FILE}"
-n "${NAMESPACE}"
--set image.tag="${IMAGE_TAG}"
--dry-run
# 实际部署
helm upgrade --install "${RELEASE_NAME}""${CHART_PATH}"
-f "${VALUES_FILE}"
-n "${NAMESPACE}" --create-namespace
--set image.tag="${IMAGE_TAG}"
--wait --timeout 10m
--atomic
--history-max 10
echo"=== Deployment completed ==="
helm status "${RELEASE_NAME}" -n "${NAMESPACE}"
3.2 实际应用案例
案例一:用Helm部署Prometheus监控栈
场景描述:用kube-prometheus-stack Chart一键部署Prometheus + Grafana + AlertManager,替代手动维护几十个YAML文件。
实现代码:
# 添加仓库 helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update
# 文件:prometheus-values.yaml prometheus: prometheusSpec: retention:30d storageSpec: volumeClaimTemplate: spec: storageClassName:ceph-rbd accessModes:["ReadWriteOnce"] resources: requests: storage:100Gi resources: requests: cpu:"1" memory:2Gi limits: cpu:"2" memory:4Gi grafana: adminPassword:"your-secure-password" persistence: enabled:true storageClassName:ceph-rbd size:10Gi ingress: enabled:true ingressClassName:nginx hosts: -grafana.company.com tls: -secretName:grafana-tls hosts: -grafana.company.com alertmanager: alertmanagerSpec: storage: volumeClaimTemplate: spec: storageClassName:ceph-rbd accessModes:["ReadWriteOnce"] resources: requests: storage:10Gi config: route: receiver:'slack-notifications' group_by:['alertname','namespace'] group_wait:30s group_interval:5m repeat_interval:4h receivers: -name:'slack-notifications' slack_configs: -api_url:'https://hooks.slack.com/services/xxx/yyy/zzz' channel:'#alerts' send_resolved:true
# 部署 helm upgrade --install prometheus prometheus-community/kube-prometheus-stack -f prometheus-values.yaml -n monitoring --create-namespace --wait --timeout 10m # 验证 kubectl get pods -n monitoring helm list -n monitoring
案例二:Helm Hooks实现数据库迁移
场景描述:应用升级时需要先执行数据库Schema迁移,迁移成功后才部署新版本。用Helm的pre-upgrade Hook实现。
实现代码:
# 文件:myapp/templates/db-migration-job.yaml
apiVersion:batch/v1
kind:Job
metadata:
name:{{include"myapp.fullname".}}-db-migrate
labels:
{{-include"myapp.labels".|nindent4}}
annotations:
"helm.sh/hook":pre-upgrade
"helm.sh/hook-weight":"-5"
"helm.sh/hook-delete-policy":before-hook-creation,hook-succeeded
spec:
backoffLimit:3
activeDeadlineSeconds:300
template:
spec:
restartPolicy:Never
containers:
-name:migrate
image:"{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
command:["./migrate","--direction=up"]
env:
-name:DB_HOST
valueFrom:
secretKeyRef:
name:myapp-db-secret
key:host
-name:DB_PASSWORD
valueFrom:
secretKeyRef:
name:myapp-db-secret
key:password
resources:
requests:
cpu:100m
memory:128Mi
说明:
helm.sh/hook: pre-upgrade:在upgrade之前执行
helm.sh/hook-weight: "-5":多个Hook时按weight排序,数字小的先执行
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded:下次执行前删除旧Job,成功后也删除
四、最佳实践和注意事项
4.1 最佳实践
4.1.1 性能优化
限制Release历史数量:每次upgrade都会在K8s Secret中存储一份Release记录,默认不限制。集群运行一年后,频繁部署的服务可能积累几百个历史版本,占用etcd空间。
# 部署时限制历史版本数 helm upgrade --install myapp ./myapp -n production --history-max 10 # 清理已有的旧版本 helm history myapp -n production # 手动无法直接删除历史,只能通过--history-max在下次upgrade时自动清理
使用OCI Registry替代ChartMuseum:Helm 3.8+原生支持OCI格式存储Chart,Harbor 2.x直接支持。OCI Registry比ChartMuseum性能更好,且不需要额外维护一个服务。
# 登录OCI仓库 helm registry login harbor.company.com # 推送Chart helm push myapp-1.0.0.tgz oci://harbor.company.com/helm-charts # 从OCI仓库安装 helm install myapp oci://harbor.company.com/helm-charts/myapp --version 1.0.0
模板渲染缓存:大型Chart(50+模板文件)的渲染时间可能超过10秒,CI/CD中频繁的helm template会拖慢流水线。把渲染结果缓存,只在Chart或values变化时重新渲染。
4.1.2 安全加固
values中不存储敏感信息:数据库密码、API Key等不要写在values.yaml中,用External Secrets Operator或Sealed Secrets从外部密钥管理系统注入。
# 不推荐:密码明文写在values中 database: password:"my-secret-password" # 推荐:引用已存在的Secret env: -name:DB_PASSWORD valueFrom: secretKeyRef: name:myapp-db-secret# 由External Secrets创建 key:password
Chart签名验证:用GPG签名Chart包,安装时验证签名防止篡改。
# 签名 helm package --sign --key 'ops-team' --keyring ~/.gnupg/secring.gpg myapp/ # 验证 helm verify myapp-1.0.0.tgz --keyring ~/.gnupg/pubring.gpg # 安装时验证 helm install myapp myapp-1.0.0.tgz --verify --keyring ~/.gnupg/pubring.gpg
RBAC限制Helm操作权限:不同团队只能在自己的namespace中操作Helm Release,通过K8s RBAC限制ServiceAccount权限。
4.1.3 高可用配置
HA方案一:--atomic参数保证部署失败自动回滚,不会出现半部署状态
HA方案二:GitOps模式(ArgoCD + Helm),Chart和values存储在Git仓库,ArgoCD自动同步,避免手动操作失误
备份策略:Chart源码纳入Git版本管理,Release历史保留10个版本,values文件按环境分别管理
4.2 注意事项
4.2.1 配置注意事项
警告:Helm upgrade操作会直接修改集群资源,生产环境务必先dry-run确认变更内容。
注意helm upgrade默认会合并新旧values,不是完全替换。如果旧版本有个参数新版本删掉了,upgrade后旧参数仍然存在。用--reset-values可以只使用新的values,但要确保新values是完整的。
注意helm install和helm upgrade是两个不同的命令,用helm upgrade --install可以合并为一个,首次执行是install,后续是upgrade。CI/CD中统一用这个命令。
注意 Chart的version(Chart版本)和appVersion(应用版本)是两个独立的字段。Chart模板改了要升version,只改镜像tag不需要升version但建议升appVersion。
4.2.2 常见错误
| 错误现象 | 原因分析 | 解决方案 |
|---|---|---|
| Error: UPGRADE FAILED: another operation is in progress | 上次操作未完成或异常中断 |
helm rollback |
| Error: rendered manifests contain a resource that already exists | 资源已存在但不属于当前Release | 给已有资源添加Helm标签:app.kubernetes.io/managed-by: Helm |
| 模板渲染报nil pointer evaluating interface | values中缺少必要字段 | 模板中用{{ default "" .Values.xxx }}或{{- if .Values.xxx }}做空值判断 |
| upgrade后Pod没有更新 | ConfigMap/Secret内容变了但Pod没重启 | 在Deployment模板中加checksum/config注解 |
| 依赖Chart下载失败 | 仓库不可达或版本不存在 | helm repo update 更新索引;检查Chart.yaml中的依赖版本 |
4.2.3 兼容性问题
版本兼容:Helm 3.13.x支持K8s 1.24-1.28,不同Helm版本生成的Release Secret格式可能不同
平台兼容:Helm CLI支持Linux/macOS/Windows,但Windows下路径分隔符可能导致模板渲染问题
组件依赖:helm-diff插件版本需要和Helm版本匹配;ArgoCD的Helm支持有版本要求
五、故障排查和监控
5.1 故障排查
5.1.1 日志查看
# 查看Helm操作日志(增加debug输出) helm upgrade --install myapp ./myapp -n production --debug 2>&1 | tee helm-debug.log # 查看Release的manifest helm get manifest myapp -n production # 查看Release的hooks helm get hooks myapp -n production # 查看Release的notes helm get notes myapp -n production # 对比当前Release和Chart的差异 helm diff upgrade myapp ./myapp -f values-prod.yaml -n production
5.1.2 常见问题排查
问题一:upgrade卡住不动,超时失败
# 诊断命令 helm status myapp -n production kubectl get pods -n production -l app.kubernetes.io/name=myapp kubectl describe pod-n production
解决方案:
Pod镜像拉取失败:检查镜像地址和imagePullSecrets
Pod资源不足:检查节点可用资源
readinessProbe失败:检查健康检查路径和端口
Hook Job失败:kubectl logs job/
问题二:Release状态为failed,无法upgrade
# 诊断命令 helm history myapp -n production helm status myapp -n production
解决方案:
# 方式一:回滚到上一个成功版本 helm rollback myapp-n production # 方式二:强制替换(谨慎使用) helm upgrade --install myapp ./myapp -n production --force # 方式三:卸载后重装(会短暂中断服务) helm uninstall myapp -n production helm install myapp ./myapp -f values-prod.yaml -n production
问题三:模板渲染错误
症状:helm upgrade报模板语法错误
排查:
# 本地渲染模板,查看具体错误 helm template myapp ./myapp -f values-prod.yaml --debug # 只渲染特定模板 helm template myapp ./myapp -s templates/deployment.yaml -f values-prod.yaml
解决:检查Go template语法,常见错误是缩进不对、变量名拼写错误、缺少{{- end }}
5.1.3 调试模式
# Helm debug模式 helm install myapp ./myapp --debug --dry-run -n production -f values-prod.yaml # 查看Helm使用的kubeconfig helm env # 查看Helm缓存 ls ~/.cache/helm/ # 查看Helm插件 helm plugin list # 验证Chart结构 helm lint ./myapp --strict
5.2 性能监控
5.2.1 关键指标监控
# 查看所有Release状态 helm list -A --all # 查看failed的Release helm list -A --failed # 查看pending的Release helm list -A --pending # 统计各namespace的Release数量 helm list -A -o json | jq -r '.[].namespace' | sort | uniq -c | sort -rn
5.2.2 监控指标说明
| 指标名称 | 正常范围 | 告警阈值 | 说明 |
|---|---|---|---|
| Release状态 | deployed | failed/pending | failed需要排查,pending说明操作卡住 |
| Release历史版本数 | <10 | >20 | 过多历史版本占用etcd空间 |
| 部署耗时 | <5分钟 | >10分钟 | 超时通常是Pod启动慢或镜像拉取慢 |
| Hook执行时间 | <2分钟 | >5分钟 | 数据库迁移等Hook不应该太慢 |
| Chart Lint警告数 | 0 | >0 | 警告可能导致部署异常 |
5.2.3 Prometheus监控规则
# 文件:helm-alerts.yaml
# 通过kube-state-metrics监控Helm管理的资源
apiVersion:monitoring.coreos.com/v1
kind:PrometheusRule
metadata:
name:helm-release-alerts
namespace:monitoring
spec:
groups:
-name:helm-releases
rules:
-alert:HelmReleaseDeploymentUnavailable
expr:|
kube_deployment_status_replicas_unavailable{namespace=~"production|staging"}
* on(deployment, namespace) group_left()
label_replace(
kube_deployment_labels{label_app_kubernetes_io_managed_by="Helm"},
"deployment", "$1", "deployment", "(.*)"
) > 0
for:10m
labels:
severity:warning
annotations:
summary:"Helm-managed deployment {{ $labels.deployment }} has unavailable replicas"
-alert:HelmReleasePodCrashLooping
expr:|
increase(kube_pod_container_status_restarts_total{namespace=~"production|staging"}[1h]) > 5
for:5m
labels:
severity:warning
annotations:
summary:"Pod {{ $labels.pod }} in {{ $labels.namespace }} is crash looping"
5.3 备份与恢复
5.3.1 备份策略
#!/bin/bash
# Helm Release备份脚本
# 文件:/opt/scripts/helm-backup.sh
set -euo pipefail
BACKUP_DIR="/data/helm-backup/$(date +%Y%m%d)"
mkdir -p "${BACKUP_DIR}"
# 备份所有Release的values和manifest
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
for release in $(helm list -n "$ns" -q 2>/dev/null); do
mkdir -p "${BACKUP_DIR}/${ns}"
helm get values "$release" -n "$ns" -o yaml > "${BACKUP_DIR}/${ns}/${release}-values.yaml" 2>/dev/null || true
helm get manifest "$release" -n "$ns" > "${BACKUP_DIR}/${ns}/${release}-manifest.yaml" 2>/dev/null || true
echo"[$(date)] Backed up: ${ns}/${release}"
done
done
# 压缩
tar czf "/data/helm-backup/helm-backup-$(date +%Y%m%d).tar.gz" -C "/data/helm-backup""$(date +%Y%m%d)"
rm -rf "${BACKUP_DIR}"
echo"[$(date)] Helm backup completed"
5.3.2 恢复流程
停止服务:通知相关团队准备维护窗口
恢复数据:helm upgrade --install
验证完整性:helm status
重启服务:确认所有Pod Running
六、总结
6.1 技术要点回顾
要点一:helm upgrade --install统一安装和升级操作,配合--atomic保证部署失败自动回滚
要点二:values.yaml按环境拆分(dev/staging/prod),敏感信息不写在values中,用External Secrets注入
要点三:Deployment模板中加checksum/config注解,ConfigMap变更时自动触发Pod滚动更新
要点四:--history-max 10限制Release历史版本数量,避免占用过多etcd空间
要点五:Chart源码纳入Git版本管理,CI/CD中用helm lint和--dry-run做部署前验证
6.2 进阶学习方向
Helmfile多Release编排:管理多个Helm Release的声明式工具,一个helmfile.yaml定义整个环境的所有服务
学习资源:Helmfile GitHub
实践建议:从单个环境开始,逐步扩展到多环境管理
ArgoCD + Helm GitOps:用ArgoCD监控Git仓库中的Chart和values变更,自动同步到集群
学习资源:ArgoCD Helm支持
实践建议:先在staging环境实践GitOps流程
自定义Chart Library:把公司通用的模板抽成Library Chart,业务Chart引用Library减少重复代码
6.3 参考资料
Helm官方文档 - 完整的Helm使用指南
Chart开发指南 - 模板语法详解
Artifact Hub - Helm Chart公共仓库
helm-diff插件 - Release差异对比工具
附录
A. 命令速查表
# 仓库管理 helm repo add# 添加仓库 helm repo update # 更新仓库索引 helm repo list # 查看仓库列表 helm search repo # 搜索Chart # Release管理 helm install -n # 安装 helm upgrade --install -n # 安装或升级 helm upgrade -n -f values.yaml # 升级 helm rollback -n # 回滚 helm uninstall -n # 卸载 helm list -A # 查看所有Release helm history -n # 查看历史 helm status -n # 查看状态 # Chart开发 helm create # 创建Chart骨架 helm lint # 语法检查 helm template # 本地渲染模板 helm package # 打包 helm push # 推送到OCI仓库 helm dependency update # 更新依赖 # 调试 helm get values -n # 查看values helm get manifest -n # 查看manifest helm get all -n # 查看所有信息 helm diff upgrade # 差异对比(需要插件)
B. 配置参数详解
helm upgrade常用参数:
| 参数 | 说明 | 建议 |
|---|---|---|
| --install | 不存在时自动install | CI/CD中必用 |
| --atomic | 失败自动回滚 | 生产环境必用 |
| --wait | 等待Pod Ready | 生产环境必用 |
| --timeout | 超时时间 | 生产设10m,开发设5m |
| --history-max | 历史版本上限 | 建议10 |
| --dry-run | 模拟执行 | 部署前验证 |
| --debug | 调试输出 | 排查问题时用 |
| --force | 强制替换资源 | 谨慎使用 |
| --reset-values | 不合并旧values | 完整values时使用 |
| --reuse-values | 复用旧values | 只改个别参数时使用 |
| -f | 指定values文件 | 可多次使用,后面覆盖前面 |
| --set | 命令行设置值 | 优先级最高 |
Helm Hook类型:
| Hook | 执行时机 | 典型用途 |
|---|---|---|
| pre-install | install前 | 创建前置资源 |
| post-install | install后 | 发送通知 |
| pre-upgrade | upgrade前 | 数据库迁移 |
| post-upgrade | upgrade后 | 清理缓存 |
| pre-delete | uninstall前 | 数据备份 |
| post-delete | uninstall后 | 清理外部资源 |
| pre-rollback | rollback前 | 数据库回滚 |
| post-rollback | rollback后 | 通知 |
| test | helm test时 | 连通性测试 |
C. 术语表
| 术语 | 英文 | 解释 |
|---|---|---|
| Chart | - | Helm的包格式,包含K8s资源模板和配置 |
| Release | - | Chart的一次安装实例,每次install/upgrade产生新版本 |
| Repository | - | Chart仓库,存储和分发Chart包 |
| Values | - | Chart的配置参数,通过values.yaml或--set传入 |
| Template | - | Go template格式的K8s资源模板 |
| Hook | - | 在Release生命周期特定阶段执行的操作 |
| Dependency | - | Chart对其他Chart的依赖关系 |
| OCI | Open Container Initiative | 容器镜像标准,Helm 3.8+支持OCI格式存储Chart |
全部0条评论
快来发表一下你的评论吧 !