0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Helm包管理与模板化部署实战

马哥Linux运维 来源:马哥Linux运维 2026-02-26 16:37 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

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历史
helmhistorymy-nginx -n web

# 升级Release
helm upgrade my-nginx bitnami/nginx -n web --setreplicaCount=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历史
helmhistorymyapp-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}"
 --setimage.tag="${IMAGE_TAG}"
 --dry-run

# 实际部署
helm upgrade --install"${RELEASE_NAME}""${CHART_PATH}"
 -f"${VALUES_FILE}"
 -n"${NAMESPACE}"--create-namespace 
 --setimage.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

# 清理已有的旧版本
helmhistorymyapp -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/ -n production

问题二:Release状态为failed,无法upgrade

# 诊断命令
helmhistorymyapp -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
fornsin$(kubectl get ns -o jsonpath='{.items[*].metadata.name}');do
forreleasein$(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 -f -n

验证完整性:helm status -n

重启服务:确认所有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
helmhistory -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

    文章

    182

    浏览量

    11716
  • 微服务
    +关注

    关注

    0

    文章

    151

    浏览量

    8150

原文标题:别再手工改 YAML:Helm 包管理与模板化部署全解

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Kubernetes Helm入门指南

    Helm 是 Kubernetes 的包管理工具,它允许开发者和系统管理员通过定义、打包和部署应用程序来简化 Kubernetes 应用的管理
    的头像 发表于 04-30 13:42 3299次阅读
    Kubernetes <b class='flag-5'>Helm</b>入门指南

    【「仓颉编程快速上手」阅读体验】简洁包管理的命脉

    包管理,一个简简单单,又复复杂杂的内容。其实包管理原理不难,但是做好确实不容易。 仓颉具备自己的包管理。 从C++这种语言来说。除了针对特定系统的包管理,平时的
    发表于 09-26 22:18

    HarmonyOS5云服务技术分享--Serverless抽奖模板部署

    手把手教你部署HarmonyOS Serverless抽奖活动模板(附贴心提醒) 嘿,小伙伴们!今天给大家分享一个超实用的教程——如何用华为HarmonyOS的Serverless模板快速搭建抽奖
    发表于 05-22 20:25

    使用Helm 在容器服务k8s集群一键部署wordpress

    摘要: Helm 是啥? 微服务和容器给复杂应用部署管理带来了极大的挑战。Helm是目前Kubernetes服务编排领域的唯一开源子项目
    发表于 03-29 13:38

    Helm Kubernetes包管理

    helm.zip
    发表于 04-27 14:25 2次下载
    <b class='flag-5'>Helm</b> Kubernetes<b class='flag-5'>包管理</b>器

    Helm常用命令(chart安装、升级、回滚、卸载等操作)

    Helm 针对 Kubernetes 的 Helm 包管理器。
    的头像 发表于 09-13 14:54 9393次阅读

    Helm的一些概念及用法

    应用,使用 Helm (https://helm.sh)是一个很不错的选择,它具备如下的能力: 简化部署 :Helm允许使用单个命令轻松部署
    的头像 发表于 05-30 09:51 2045次阅读
    <b class='flag-5'>Helm</b>的一些概念及用法

    Helm部署MinIO集群

    Helm部署MinIO集群
    的头像 发表于 12-03 09:44 1769次阅读
    <b class='flag-5'>Helm</b><b class='flag-5'>部署</b>MinIO集群

    使用Jenkins和单个模板部署多个Kubernetes组件

    在持续集成和部署中,我们通常需要部署多个实例或组件到Kubernetes集群中。通过Jenkins的管道脚本,我们可以自动这个过程。在本文中,我将演示如何使用Jenkins Pipeline及单个
    的头像 发表于 01-02 11:40 2108次阅读
    使用Jenkins和单个<b class='flag-5'>模板</b><b class='flag-5'>部署</b>多个Kubernetes组件

    鸿蒙开发实战:【包管理子系统】

    包管理子系统负责应用安装包的管理,提供安装包的信息查询、安装、更新、卸载和包信息存储等能力
    的头像 发表于 03-14 15:23 1763次阅读
    鸿蒙开发<b class='flag-5'>实战</b>:【<b class='flag-5'>包管理</b>子系统】

    Kubernetes包管理工具Helm的安装和使用

    Helm 可以帮助我们管理 Kubernetes 应用程序 - Helm Charts 可以定义、安装和升级复杂的 Kubernetes 应用程序,Charts 包很容易创建、版本管理
    的头像 发表于 03-13 16:06 2471次阅读

    Helm仓库管理常用配置

    Helm 仓库(Repository)是存储 Helm 图表(Chart)的地方,类似于软件包管理器的仓库(如 apt、yum 仓库)。
    的头像 发表于 06-07 09:27 1601次阅读

    Helm详细介绍和使用

    Helm是Kubernetes 应用的包管理工具,主要用来管理 Charts,类似Linux系统的yum。
    的头像 发表于 06-17 13:56 1670次阅读

    Helm实现容器运维高效包管理与应用部署

    在当今快速演变的云原生生态系统中,容器技术已成为运维工程师不可或缺的核心能力。
    的头像 发表于 07-14 11:16 1076次阅读

    企业级应用模板部署Helm包管理实战

    生产环境中一个微服务体系动辄几十个 Deployment、Service、ConfigMap、Secret、Ingress,如果全部用裸 YAML 手工维护,版本迭代时改错一个 label selector 就能导致滚动更新断流。
    的头像 发表于 03-17 14:32 279次阅读