1. Helm 基础入门:为什么需要 Chart 管理?

如果你用过 Kubernetes,肯定遇到过这样的场景:部署一个 WordPress 需要创建 Deployment、Service、PVC、ConfigMap 等多个 YAML 文件,每次修改配置都得逐个文件调整。我在第一次尝试时,光是处理这些文件的依赖关系就花了整整两天。而 Helm 的出现,就像给 Kubernetes 装上了"应用商店",把分散的 YAML 打包成一个可版本化的软件包(Chart),用 values.yaml 统一管理配置。

Chart 的本质是一个特定目录结构的文件集合,包含模板文件、默认配置和元数据。比如我们创建一个 WordPress Chart,目录结构是这样的:

wordpress/
├── Chart.yaml          # 版本和依赖声明
├── values.yaml         # 默认配置参数
├── charts/             # 子Chart依赖
└── templates/          # 模板文件
    ├── deployment.yaml
    ├── service.yaml
    └── pvc.yaml

实际工作中最爽的是升级时的体验。以前手动改 YAML 时,总要担心漏改某个文件导致配置不一致。现在只需要 helm upgrade --set image.tag=5.9 就能完成全栈更新。去年我们有个电商项目,大促前紧急修复镜像漏洞,用 Helm 只花了 3 分钟就完成了所有环境的滚动更新。

2. 从零构建你的第一个 Chart

2.1 快速初始化项目

动手永远是最好的学习方式。我们先创建一个真实的 Nginx Chart:

helm create my-nginx
cd my-nginx

这个命令生成的模板可能包含你暂时用不到的组件,我建议先清理下 templates/ 目录,只保留最基础的文件:

rm -rf templates/*
touch templates/{deployment,service}.yaml

现在我们来手写一个极简的 Deployment 模板(templates/deployment.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-nginx
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        ports:
        - containerPort: 80

对应的 values.yaml 应该有这样的配置:

replicaCount: 2
image:
  repository: nginx
  tag: "1.23.4"

2.2 调试技巧与实用命令

写模板最头疼的就是调试。我常用的三板斧:

  1. 语法检查helm lint . 会告诉你是否有 YAML 格式错误
  2. 模板预览helm template --debug ./my-nginx 可以渲染出最终生成的 YAML
  3. 参数覆盖helm install --dry-run --set replicaCount=3 ./my-nginx 测试运行时修改参数

遇到变量渲染问题时,可以在模板中加入调试信息:

{{/* 调试块 - 打印所有可用变量 */}}
{{- printf "|%30s|%50s|\n" "变量路径" "值" }}
{{- range $k,$v := .Values }}
{{- printf "|%30s|%50v|\n" $k $v }}
{{- end }}

3. Chart 的打包与仓库管理

3.1 构建可发布的软件包

当 Chart 开发完成后,打包命令简单到令人发指:

helm package ./my-nginx --version 1.0.0

这会在当前目录生成 my-nginx-1.0.0.tgz 文件。但实际生产环境中,我强烈建议在 CI 流水线中加入版本校验:

# 在CI脚本中加入版本冲突检查
if helm search repo my-nginx --version 1.0.0 | grep -q "1.0.0"; then
  echo "ERROR: 版本 1.0.0 已存在"
  exit 1
fi

3.2 私有仓库实战指南

虽然公共仓库很方便,但企业环境更需要私有仓库。以 Harbor 为例的完整接入流程:

  1. 首先安装推送插件:
helm plugin install https://github.com/chartmuseum/helm-push
  1. 添加仓库认证(建议将密码保存在K8s Secret中):
helm repo add private-repo \
  --username=admin \
  --password=$HARBOR_PASSWORD \
  https://harbor.example.com/chartrepo/my-project
  1. 推送时使用CA证书(常见坑点):
helm cm-push ./my-nginx-1.0.0.tgz private-repo \
  --ca-file ./ca.crt \
  --force  # 覆盖已存在版本

我在实际部署中发现,当Chart超过10MB时可能会超时,解决方法是在Harbor的chartmuseum配置中增加:

storage:
  local:
    rootDirectory: /chart_storage
  cache:
    enabled: true
    maxSize: 256Mi

4. 全生命周期管理实战

4.1 安装策略与参数覆盖

安装一个Chart至少有三种传参方式,各有用武之地:

  1. 直接覆盖默认值(适合临时测试):
helm install nginx ./my-nginx --set replicaCount=3
  1. 多环境配置管理(生产环境推荐):
# 准备生产环境配置
echo "replicaCount: 5
image:
  tag: '1.23.4-prod'" > values-prod.yaml

helm install nginx ./my-nginx -f values-prod.yaml
  1. 动态生成配置(高级用法):
# 从外部系统获取最新镜像标签
LATEST_TAG=$(curl -s https://registry.example.com/v2/nginx/tags/list | jq -r '.tags[0]')

helm install nginx ./my-nginx --set image.tag=$LATEST_TAG

4.2 升级与回滚的艺术

升级时有个重要技巧:使用--atomic参数可以在失败时自动回滚。去年我们线上环境的一次升级让我深刻体会到这个参数的价值:

helm upgrade nginx ./my-nginx \
  --set image.tag=1.24.0 \
  --atomic \          # 失败自动回滚
  --timeout 10m \     # 适当延长超时
  --cleanup-on-fail   # 清理失败资源

查看历史记录时,添加--max参数控制显示数量,配合-o yaml输出更详细的信息:

helm history nginx --max=5 -o yaml

回滚到特定版本时,一定要先检查该版本的配置:

# 先查看第3版的配置
helm get values nginx --revision 3

# 确认无误后再回滚
helm rollback nginx 3

4.3 彻底卸载与资源清理

简单的helm uninstall并不能处理所有情况。我总结的完整清理流程:

  1. 先查看将被删除的资源:
helm get manifest nginx | kubectl get -f - --show-kind
  1. 对于有状态服务,手动备份PVC数据:
kubectl get pvc -l app.kubernetes.io/instance=nginx -o name | xargs -I{} kubectl cp {}:/data ./backup/
  1. 执行卸载并保留历史记录:
helm uninstall nginx --keep-history
  1. 最后清理残留资源(根据label筛选):
kubectl delete secrets,configmaps -l app.kubernetes.io/instance=nginx

5. 企业级进阶技巧

5.1 依赖管理的正确姿势

复杂的微服务架构中,Chart依赖管理尤为关键。比如一个电商系统可能包含:

# Chart.yaml
dependencies:
  - name: redis
    version: "~16.10.0"
    repository: "https://charts.bitnami.com/bitnami"
    condition: redis.enabled
  - name: postgresql
    version: "~11.6.0"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled

管理这类依赖的最佳实践:

  1. 使用helm dependency update生成锁文件:
helm dependency update .
# 会生成 Chart.lock 文件
  1. 在CI流程中加入依赖校验:
helm dependency build --verify
  1. 对私有依赖使用相对路径:
dependencies:
  - name: shared-lib
    version: "1.0.0"
    repository: "file://../shared-charts/library"

5.2 安全加固方案

生产环境必须考虑的安全措施:

  1. 内容校验:在打包时生成签名
helm package . --sign --key 'My Key' --keyring ~/.gnupg/secring.gpg
  1. 安装时验证
helm install nginx ./my-nginx-1.0.0.tgz --verify --keyring ~/.gnupg/pubring.gpg
  1. RBAC控制:通过K8s的ServiceAccount限制权限
# templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ .Release.Name }}-sa
  annotations:
    "helm.sh/hook": "pre-install"
    "helm.sh/hook-weight": "-5"

5.3 与CI/CD流水线集成

在GitLab CI中的典型集成示例:

stages:
  - lint
  - package
  - deploy

helm-lint:
  stage: lint
  image: alpine/helm:3.10.1
  script:
    - helm lint ./chart
    - helm dependency build ./chart

package-chart:
  stage: package
  image: alpine/helm:3.10.1
  script:
    - helm package ./chart --version $CI_COMMIT_TAG
    - helm push myapp-$CI_COMMIT_TAG.tgz private-repo
  only:
    - tags

deploy-prod:
  stage: deploy
  image: alpine/helm-kubectl:3.10.1
  script:
    - helm upgrade --install myapp private-repo/myapp --version $CI_COMMIT_TAG -f values-prod.yaml
  when: manual
  only:
    - tags

在Jenkins中则需要特别注意凭证管理,建议使用Jenkins的Secret文件功能存储kubeconfig和Harbor密码。

更多推荐