Helm Kubernetes 应用包管理部署与运维实战

一、背景与目标

Helm 是 Kubernetes 生态系统中最重要的包管理工具,被誉为”Kubernetes 的 apt/yum”。它通过 Chart 的形式封装 Kubernetes 应用,简化了应用的部署、升级和管理流程。

本文档将介绍:

  • Helm 核心概念与架构
  • Helm 3 安装与配置
  • Chart 开发与定制
  • 应用部署与升级实战
  • Helm 运维最佳实践
  • 企业级 Helm 仓库搭建

二、Helm 核心概念

2.1 核心术语

术语 描述
Chart Helm 应用包,包含 Kubernetes 资源模板和配置
Release Chart 在集群中运行的实例
Repository Chart 仓库,用于存储和分享 Chart
Values 用户自定义配置,覆盖 Chart 默认值
Hook 在特定生命周期阶段执行的临时资源

2.2 Helm 3 vs Helm 2

特性 Helm 2 Helm 3
服务端组件 Tiller 无(纯客户端)
存储方式 ConfigMap(kube-system) Secret(release 命名空间)
安全性 依赖 RBAC 配置 Tiller 使用用户 kubeconfig
发布版本管理 数字版本 语义化版本
JSON Schema 验证 不支持 支持

三、Helm 安装与配置

3.1 安装 Helm 3

1
2
3
4
5
6
7
8
9
10
# 方法 1: 官方脚本安装
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# 方法 2: 手动下载
wget https://get.helm.sh/helm-v3.14.0-linux-amd64.tar.gz
tar -zxvf helm-v3.14.0-linux-amd64.tar.gz
sudo mv linux-amd64/helm /usr/local/bin/helm

# 验证安装
helm version

3.2 配置 Helm 仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 添加官方 Stable 仓库
helm repo add stable https://charts.helm.sh/stable

# 添加 Bitnami 仓库(推荐)
helm repo add bitnami https://charts.bitnami.com/bitnami

# 添加 Harbor 仓库
helm repo add harbor https://helm.goharbor.io

# 添加 Prometheus 社区仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts

# 更新仓库索引
helm repo update

# 列出已配置的仓库
helm repo list

# 搜索 Chart
helm search repo nginx
helm search repo redis --versions

3.3 Helm 环境配置

1
2
3
4
5
6
7
8
9
10
11
# 查看 Helm 配置
helm env

# 设置自定义仓库配置文件
export HELM_CONFIG_HOME=~/.config/helm
export HELM_CACHE_HOME=~/.cache/helm
export HELM_DATA_HOME=~/.local/share/helm

# 配置 HTTP 代理(企业环境)
export http_proxy=http://proxy.company.com:8080
export https_proxy=http://proxy.company.com:8080

四、Chart 结构解析

4.1 Chart 目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
my-chart/
├── Chart.yaml # Chart 元数据
├── values.yaml # 默认配置值
├── values.schema.json # Values 的 JSON Schema(可选)
├── .helmignore # 打包时忽略的文件
├── charts/ # 子 Chart 依赖
│ └── postgresql-12.0.0.tgz
├── templates/ # Kubernetes 模板
│ ├── _helpers.tpl # 模板辅助函数
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── configmap.yaml
│ ├── secret.yaml
│ ├── ingress.yaml
│ └── tests/ # 测试模板
│ └── test-connection.yaml
└── files/ # 静态文件(可选)
└── config.json

4.2 Chart.yaml 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: v2
name: my-application
description: 企业级微服务应用 Helm Chart
type: application
version: 1.0.0
appVersion: "2.5.0"
keywords:
- microservice
- api
- production
home: https://github.com/company/my-application
sources:
- https://github.com/company/my-application
maintainers:
- name: DevOps Team
email: devops@company.com
dependencies:
- name: postgresql
version: "12.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
- name: redis
version: "18.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled

4.3 values.yaml 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# 副本数配置
replicaCount: 3

# 镜像配置
image:
repository: registry.company.com/my-application
pullPolicy: IfNotPresent
tag: "2.5.0"

# 镜像拉取密钥
imagePullSecrets:
- name: registry-secret

# 服务名称
nameOverride: ""
fullnameOverride: "my-application-prod"

# 服务账户配置
serviceAccount:
create: true
annotations: {}
name: ""

# Pod 注解
podAnnotations: {}

# Pod 安全上下文
podSecurityContext:
fsGroup: 1000

# 容器安全上下文
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false

# 服务配置
service:
type: ClusterIP
port: 80
targetPort: 8080

# Ingress 配置
ingress:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
hosts:
- host: api.company.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: api-tls-secret
hosts:
- api.company.com

# 资源限制
resources:
limits:
cpu: 2000m
memory: 4Gi
requests:
cpu: 500m
memory: 1Gi

# 自动扩缩容
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 20
targetCPUUtilizationPercentage: 80
targetMemoryUtilizationPercentage: 80

# 节点选择器
nodeSelector: {}

# 容忍度
tolerations: []

# 亲和性
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: my-application
topologyKey: kubernetes.io/hostname

# 依赖组件配置
postgresql:
enabled: true
auth:
postgresPassword: "changeme"
primary:
persistence:
enabled: true
size: 50Gi

redis:
enabled: true
auth:
enabled: true
password: "changeme"
master:
persistence:
enabled: true
size: 10Gi

# 监控配置
metrics:
enabled: true
serviceMonitor:
enabled: true
namespace: monitoring
interval: 30s

4.4 模板辅助函数 (_helpers.tpl)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{{/*
创建标准化的名称
*/}}
{{- define "my-application.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
创建完全限定名称
*/}}
{{- define "my-application.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-application.labels" -}}
helm.sh/chart: {{ include "my-application.chart" . }}
{{ include "my-application.selectorLabels" . }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
创建选择器标签
*/}}
{{- define "my-application.selectorLabels" -}}
app.kubernetes.io/name: {{ include "my-application.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
创建 Chart 版本信息
*/}}
{{- define "my-application.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

五、应用部署实战

5.1 部署前检查

1
2
3
4
5
6
7
8
9
10
11
12
# 渲染模板检查(不实际部署)
helm template my-release ./my-chart --debug

# 带自定义 values 渲染
helm template my-release ./my-chart -f values-prod.yaml --debug

# Lint 检查
helm lint ./my-chart

# 依赖更新
helm dependency update ./my-chart
helm dependency build ./my-chart

5.2 安装 Release

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 基础安装
helm install my-release ./my-chart

# 指定命名空间
helm install my-release ./my-chart -n production

# 使用自定义 values
helm install my-release ./my-chart -f values-prod.yaml

# 覆盖特定值
helm install my-release ./my-chart --set replicaCount=5 --set image.tag=2.6.0

# 干运行(预览)
helm install my-release ./my-chart --dry-run --debug

# 等待资源就绪
helm install my-release ./my-chart --wait --timeout 10m

5.3 查看 Release 状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 列出所有 Release
helm list
helm list -n production
helm list --all-namespaces

# 查看 Release 详情
helm status my-release
helm status my-release -n production

# 查看 Release 历史
helm history my-release

# 查看已部署资源
helm get manifest my-release
helm get values my-release
helm get hooks my-release
helm get notes my-release

# 查看特定资源
helm get manifest my-release | grep -A 20 "kind: Deployment"

5.4 升级 Release

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 基础升级
helm upgrade my-release ./my-chart

# 升级并指定 values
helm upgrade my-release ./my-chart -f values-prod-v2.yaml

# 升级并覆盖值
helm upgrade my-release ./my-chart --set image.tag=2.6.0

# 升级并回滚策略
helm upgrade my-release ./my-chart --atomic --timeout 10m

# 强制升级(跳过某些检查)
helm upgrade my-release ./my-chart --force

# 查看升级差异
helm diff upgrade my-release ./my-chart -f values-prod-v2.yaml

5.5 回滚 Release

1
2
3
4
5
6
7
8
9
10
11
# 回滚到上一版本
helm rollback my-release

# 回滚到指定版本
helm rollback my-release 1

# 查看回滚历史
helm history my-release

# 回滚并等待
helm rollback my-release 2 --wait --timeout 10m

5.6 卸载 Release

1
2
3
4
5
6
7
8
9
10
11
# 基础卸载
helm uninstall my-release

# 卸载并清理 hooks
helm uninstall my-release --no-hooks

# 卸载指定命名空间
helm uninstall my-release -n production

# 干运行(预览)
helm uninstall my-release --dry-run

六、Helm 插件生态

6.1 常用插件安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# helm-diff: 查看变更差异
helm plugin install https://github.com/databus23/helm-diff

# helm-secrets: 加密敏感信息
helm plugin install https://github.com/jkroepke/helm-secrets

# helm-docs: 自动生成文档
helm plugin install https://github.com/norwoodj/helm-docs

# helm-unittest: Chart 单元测试
helm plugin install https://github.com/helm-unittest/helm-unittest

# helm-whatup: 检查依赖更新
helm plugin install https://github.com/mumoshu/helm-whatup

# helm-push: 推送 Chart 到 OCI 仓库
helm plugin install https://github.com/chartmuseum/helm-push

6.2 插件使用示例

1
2
3
4
5
6
7
8
9
10
11
12
# 使用 helm-diff 预览变更
helm diff upgrade my-release ./my-chart -f values-prod.yaml

# 使用 helm-secrets 加密 values
helm secrets enc values-secret.yaml
helm secrets install my-release ./my-chart -f values-secret.yaml

# 运行 Chart 测试
helm unittest ./my-chart

# 生成 Chart 文档
helm-docs

七、企业级 Helm 仓库搭建

7.1 使用 Harbor 搭建 Helm 仓库

1
2
3
4
5
6
7
8
9
10
11
12
# Harbor helm-chartmuseum 配置
chartmuseum:
enabled: true
env:
open:
STORAGE: local
LOCAL_ROOT_DIRECTORY: /storage
DEPTH: 1
persistence:
enabled: true
size: 50Gi
storageClass: nfs-storage

7.2 推送 Chart 到仓库

1
2
3
4
5
6
7
8
9
# 打包 Chart
helm package ./my-chart

# 推送到 Harbor
helm push my-chart-1.0.0.tgz oci://registry.company.com/helm-charts

# 或使用传统方式
helm repo add company-charts https://harbor.company.com/chartrepo/helm-charts
helm push my-chart-1.0.0.tgz company-charts

7.3 使用 OCI 注册表

1
2
3
4
5
6
7
8
9
10
11
# 登录 OCI 注册表
helm registry login registry.company.com -u admin -p password

# 推送 Chart
helm push ./my-chart-1.0.0.tgz oci://registry.company.com/helm-charts

# 拉取 Chart
helm pull oci://registry.company.com/helm-charts/my-chart --version 1.0.0

# 直接从 OCI 安装
helm install my-release oci://registry.company.com/helm-charts/my-chart --version 1.0.0

7.4 Chart 版本管理

1
2
3
4
5
6
7
8
9
10
11
12
13
# Chart 版本规范遵循 SemVer
# major.minor.patch

# 更新 Chart 版本
# Chart.yaml:
version: 1.0.0 -> 1.0.1 # Bug 修复
version: 1.0.0 -> 1.1.0 # 新功能(向后兼容)
version: 1.0.0 -> 2.0.0 # 破坏性变更

# 使用 Chart 版本约束
# dependencies:
# - name: postgresql
# version: ">=12.0.0 <13.0.0"

八、CI/CD 集成

8.1 GitHub Actions 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# .github/workflows/helm-ci.yml
name: Helm CI/CD

on:
push:
branches: [main]
paths:
- 'charts/**'
pull_request:
branches: [main]
paths:
- 'charts/**'

jobs:
lint-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Helm
uses: azure/setup-helm@v3
with:
version: v3.14.0

- name: Set up chart-testing
uses: helm/chart-testing-action@v2.6.0

- name: Run chart-testing (list-changed)
id: list-changed
run: |
changed=$(ct list-changed --target-branch main)
if [[ -n "$changed" ]]; then
echo "changed=true" >> $GITHUB_OUTPUT
fi

- name: Run chart-testing (lint)
run: ct lint --target-branch main --validate-maintainers=false

- name: Create kind cluster
if: steps.list-changed.outputs.changed == 'true'
uses: helm/kind-action@v1.9.0

- name: Run chart-testing (install)
if: steps.list-changed.outputs.changed == 'true'
run: ct install --target-branch main

release:
needs: lint-test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Helm
uses: azure/setup-helm@v3

- name: Package charts
run: |
for chart in charts/*; do
helm package $chart
done

- name: Push to OCI registry
run: |
helm registry login registry.company.com -u ${{ secrets.HARBOR_USER }} -p ${{ secrets.HARBOR_PASSWORD }}
for pkg in *.tgz; do
helm push $pkg oci://registry.company.com/helm-charts
done

8.2 GitLab CI 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# .gitlab-ci.yml
stages:
- lint
- test
- release

variables:
HELM_VERSION: "3.14.0"

.lint-template: &lint
image: alpine/helm:${HELM_VERSION}
script:
- helm lint charts/${CHART_NAME}

lint:
<<: *lint
variables:
CHART_NAME: "my-application"
rules:
- changes:
- charts/**/*

test:
image: quay.io/helmpack/chart-testing:latest
script:
- ct lint --target-branch main
- ct install --target-branch main
rules:
- changes:
- charts/**/*

release:
image: alpine/helm:${HELM_VERSION}
script:
- helm package charts/${CHART_NAME}
- helm registry login ${HARBOR_URL} -u ${HARBOR_USER} -p ${HARBOR_PASSWORD}
- helm push ${CHART_NAME}-*.tgz oci://${HARBOR_URL}/helm-charts
rules:
- if: $CI_COMMIT_BRANCH == "main"
changes:
- charts/**/*

九、运维最佳实践

9.1 命名规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 推荐命名约定
# Release 名称:<应用>-<环境>
# 例如:myapp-prod, myapp-staging, myapp-dev

# Chart 名称:小写,连字符分隔
# 例如:my-application, user-service

# 标签规范
labels:
app.kubernetes.io/name: my-application
app.kubernetes.io/instance: my-release
app.kubernetes.io/version: "2.5.0"
app.kubernetes.io/component: api
app.kubernetes.io/part-of: my-system
app.kubernetes.io/managed-by: helm

9.2 Values 文件管理

1
2
3
4
5
6
7
8
values/
├── values.yaml # 默认值(开发环境)
├── values-staging.yaml # 预发环境
├── values-prod.yaml # 生产环境
├── values-dr.yaml # 灾备环境
└── secrets/
├── values-secrets.yaml.enc
└── values-secrets-prod.yaml.enc

9.3 多环境部署策略

1
2
3
4
5
6
7
8
9
10
# 使用不同 values 文件部署多环境
helm install myapp-dev ./my-chart -f values.yaml -n dev
helm install myapp-staging ./my-chart -f values-staging.yaml -n staging
helm install myapp-prod ./my-chart -f values-prod.yaml -n prod

# 或使用 --set 覆盖
helm install myapp-prod ./my-chart \
--set replicaCount=5 \
--set resources.limits.cpu=4000m \
--set ingress.hosts[0].host=api-prod.company.com

9.4 备份与恢复

1
2
3
4
5
6
7
8
9
10
11
12
13
# 备份 Release
helm get manifest my-release > my-release-manifest.yaml
helm get values my-release > my-release-values.yaml

# 批量备份所有 Release
for release in $(helm list -q); do
mkdir -p backup/$release
helm get manifest $release > backup/$release/manifest.yaml
helm get values $release > backup/$release/values.yaml
done

# 从备份恢复
helm install my-release ./my-chart -f backup/my-release/values.yaml

9.5 安全实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 1. 使用 Secret 存储敏感信息
# values.yaml 中不要硬编码密码
secret:
create: true
data: {} # 使用外部 Secret 管理

# 2. 启用 Pod 安全策略
podSecurityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000

securityContext:
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL

# 3. 使用网络策略
networkPolicy:
enabled: true
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
egress:
- to:
- namespaceSelector:
matchLabels:
name: database

9.6 监控与告警

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 启用 ServiceMonitor
serviceMonitor:
enabled: true
namespace: monitoring
interval: 30s
scrapeTimeout: 10s
labels:
release: prometheus

# 配置告警规则
prometheusRule:
enabled: true
rules:
- alert: HelmReleaseFailed
expr: helm_release_info{status="failed"} == 1
for: 5m
labels:
severity: critical
annotations:
summary: "Helm Release 部署失败"
description: "Release {{ $labels.release }} 部署失败"

十、常见问题与解决方案

10.1 Release 卡在 pending 状态

1
2
3
4
5
6
7
8
9
# 检查集群资源
kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>

# 检查 Helm 锁
kubectl get secret -n <namespace> | grep sh.helm.release

# 清理锁(谨慎使用)
kubectl delete secret sh.helm.release.v1.<release>.v<version> -n <namespace>

10.2 升级失败无法回滚

1
2
3
4
5
6
7
8
9
# 查看历史版本
helm history my-release

# 强制回滚
helm rollback my-release <revision> --force

# 如果仍然失败,手动清理后重新安装
helm uninstall my-release --no-hooks
helm install my-release ./my-chart -f values.yaml

10.3 Chart 依赖问题

1
2
3
4
5
6
7
8
9
# 更新依赖
helm dependency update

# 检查依赖版本
helm dependency list

# 清理并重建
rm -rf charts/
helm dependency build

10.4 模板渲染错误

1
2
3
4
5
6
7
8
# 调试模板
helm template my-release ./my-chart --debug

# 检查 values 格式
helm lint ./my-chart --with-subcharts

# 验证 JSON Schema
# 确保 values.schema.json 格式正确

十一、总结

Helm 作为 Kubernetes 事实标准的包管理工具,具有以下优势:

  • 简化部署: 一键部署复杂应用
  • 版本管理: 清晰的 Release 版本历史
  • 配置复用: Values 文件支持多环境
  • 生态丰富: 大量现成 Chart 可用
  • CI/CD 友好: 易于集成自动化流程

建议在企业环境中:

  1. 建立内部 Helm 仓库,统一管理 Chart
  2. 制定 Chart 开发规范和审核流程
  3. 集成 CI/CD 实现自动化部署
  4. 使用 helm-secrets 等工具管理敏感信息
  5. 定期审计和更新 Chart 依赖

十二、参考资料

  1. Helm 官方文档 - https://helm.sh/docs/
  2. Helm Chart 开发指南 - https://helm.sh/docs/chart_template_guide/
  3. Artifact Hub(Chart 搜索) - https://artifacthub.io/
  4. Bitnami Charts - https://github.com/bitnami/charts
  5. Helm 最佳实践 - https://helm.sh/docs/chart_best_practices/
  6. Helm 插件列表 - https://helm.sh/docs/community/related/#helm-plugins