1. 为什么 Kubernetes 原生不装软件?Helm 3 的存在不是为了“锦上添花”,而是解决“雪中送炭”的刚需

你刚在 Ubuntu 22.04 上用 KubeKey 搭好一个三节点 Kubernetes 集群,kubectl get nodes 显示全部 Ready,心里正美。接着想装个 Harbor 做镜像仓库——好,写 Deployment、Service、PersistentVolumeClaim、Ingress……光是 PV 和 PVC 的 StorageClass 适配就卡了半小时;等终于跑起来,发现 Ingress 路由不通,查日志发现是 TLS 配置漏了 annotation;再想升级 Harbor 版本?得手动 diff YAML 文件,改完还得逐个 kubectl apply -f,稍有不慎就把生产环境搞挂。这不是在部署软件,是在拼乐高+解谜题+背诵 API 文档三合一的硬核考试。

这就是 Helm 3 存在的根本原因:Kubernetes 本身只管“怎么运行”,不管“装什么”和“怎么装”。它像一台没有操作系统的裸机——你能直接敲汇编指令让它亮灯,但没人会这么干。Kubernetes 的 YAML 是“汇编”,而 Helm Chart 就是它的“Linux 发行版”。它把一套应用(比如 Harbor、Prometheus、Nginx Ingress Controller)所需的全部资源对象(Deployment、ConfigMap、Secret、Service 等)打包成可复用、可参数化、可版本化的模板包,并提供 install/upgrade/rollback/uninstall 这套原子化生命周期管理能力。

Helm 3 和 Helm 2 的本质区别,很多人只记住“去掉了 Tiller”,但真正影响实操的是 权限模型重构 。Helm 2 的 Tiller 运行在集群内,以 cluster-admin 权限工作,所有用户通过 Helm CLI 间接调用它——这等于给所有人发了一把万能钥匙。Helm 3 彻底移除 Tiller,CLI 直接与 kube-apiserver 通信,权限完全继承自当前用户的 kubeconfig。这意味着:你在命名空间 A 里 helm install,生成的所有资源就严格限定在 A 里;你用普通 developer 角色的 kubeconfig,就只能部署到你被授权的命名空间,不可能误删集群级资源。这个改变不是技术炫技,而是让 Helm 真正具备企业级落地的安全底线。

从热搜词“kubernetes菜鸟教程”“helm 作用”能看出,大量新手卡在“为什么不用 kubectl apply 一堆 YAML,非要用 Helm?”这个问题上。答案很直白:当你需要部署的不是一个 Pod,而是一套包含 15 个资源对象、3 层依赖关系(如 Harbor 依赖 Redis + PostgreSQL)、且要支持多环境差异化配置(开发/测试/生产用不同数据库密码和存储路径)的系统时,纯 YAML 方案的维护成本呈指数级上升。Helm Chart 的 values.yaml 就是你的“配置中枢”,所有环境差异只改这一份文件,模板引擎自动渲染出对应环境的完整 YAML 流水线。这不是偷懒,是工程化降本的必然选择。

提示:别被“диспетчера пакетов”(俄语“包管理器”)这个词带偏。Helm 不是 apt 或 yum,它不下载二进制文件,也不管理操作系统层面的依赖。它管理的是 Kubernetes 原生资源对象的声明式定义包。理解这点,才能避免后续踩坑——比如试图用 Helm 安装一个需要宿主机安装 Docker 的组件,那是设计错位。

2. Helm 3 核心机制拆解:Template 渲染、Release 管理与 Chart 结构的底层逻辑

Helm 3 的工作流看似简单:helm install chart-name,背后却是一套精密的模板编译与状态追踪系统。要真正掌控它,必须穿透表层命令,看清三个核心模块如何协同:

2.1 Template 引擎:Go template + Sprig 函数库 = 动态 YAML 工厂

Helm Chart 的 templates/ 目录下不是静态 YAML,而是 Go 语言模板文件(.yaml.gotmpl)。当你执行 helm install 时,Helm CLI 会做三件事:

  1. 加载 values.yaml 中的键值对(如 replicaCount: 3, image.tag: "v2.5.0");
  2. 将这些值注入模板上下文(.Values);
  3. 调用 Go template 引擎,逐行解析模板中的 {{ .Values.replicaCount }}、{{ include "harbor.fullname" . }} 等语法,生成最终的、可被 kubectl 识别的纯 YAML。

这个过程的关键在于 Sprig 函数库 ——Helm 内置的一套增强函数集。比如:

  • {{ .Release.Name | trunc 63 | trimSuffix "-" }} :确保 Release 名称不超过 DNS 标签长度限制(63 字符),并去掉末尾横线(Kubernetes 资源名不允许以 - 结尾);
  • {{ randAlphaNum 10 | b64enc }} :生成 10 位随机字符串并 Base64 编码,常用于 Secret 的 password 字段;
  • {{ include "common.labels" . }} :复用定义在 _helpers.tpl 中的公共标签模板,避免重复代码。

我第一次写 Chart 时,在 values.yaml 里写了 database.password: "myPass!@#" ,结果部署后 Harbor 登录失败。查日志发现 PostgreSQL 报错“invalid byte sequence”。原因在于 YAML 解析器把 !@# 当作 YAML 锚点标记(YAML spec 中 ! 开头是 tag directive)。解决方案不是改密码,而是在模板中用 {{ .Values.database.password | quote }} —— quote 函数会自动给字符串加双引号,强制 YAML 解析为字面量。这种细节,只有亲手调试过模板渲染链路才能刻进肌肉记忆。

2.2 Release 管理:Kubernetes CRD 的巧妙复用与状态隔离

Helm 3 将每个安装实例称为一个 Release(如 my-harbor、prod-prometheus)。它不把 Release 状态存在本地文件或集群外数据库,而是 原生复用 Kubernetes 的 CustomResourceDefinition(CRD)机制 。当你 helm install 时,Helm 会在集群中创建一个名为 helm.sh/v1 的 CRD,并生成对应的 Release 对象(如 my-harbor ),其内容包含:已部署的 Chart 版本、values 哈希值、资源清单快照、上次操作时间戳等。

这个设计带来两个关键优势:

  • 状态强一致性 :Release 对象和它管理的 Pod/Service 等资源同处一个 etcd,天然满足 Kubernetes 的强一致性模型。不会出现“helm list 显示已安装,但 kubectl get pod 却找不到”的状态分裂;
  • 跨环境可迁移 :你可以导出 Release 对象( kubectl get release.v1.helm.sh/my-harbor -o yaml > release-backup.yaml ),在另一套集群中 kubectl apply -f release-backup.yaml ,Helm 会自动根据快照重建资源——这是纯 YAML 部署无法实现的“状态回滚”能力。

但要注意:Release 对象默认存储在 kube-system 命名空间(Helm 2 行为遗留),而 Helm 3 推荐将 Release 绑定到目标命名空间。实际操作中,我们通过 --namespace harbor-prod 参数指定,Helm 会自动在该命名空间下创建 Release 对象。如果忘记指定,Release 会落在 default 命名空间,后续 upgrade 时可能因命名空间不匹配报错。

2.3 Chart 包结构:从 tar.gz 到可执行蓝图的完整解剖

一个标准 Helm Chart 是一个符合特定目录结构的 tar.gz 包。以官方 Harbor Chart 为例,其核心结构如下:

harbor/
├── Chart.yaml          # Chart 元信息:名称、版本、描述、依赖项(如要求 Kubernetes >= 1.19)
├── values.yaml         # 默认配置值:所有可覆盖的参数都在这里,是用户修改的主要入口
├── charts/             # 子 Chart 目录(可选):存放依赖的其他 Chart,如 harbor 依赖的 nginx-ingress
├── templates/          # 模板主目录:
│   ├── _helpers.tpl    # 公共模板片段:定义 name、fullname、labels 等复用逻辑
│   ├── deployment.yaml.gotmpl   # 主应用 Deployment 模板
│   ├── service.yaml.gotmpl      # Service 模板
│   └── ingress.yaml.gotmpl      # Ingress 模板(支持 TLS/rewrite 规则)
└── crds/               # 自定义资源定义(CRD):如 Harbor 的 Project、Registry 等扩展资源

其中 crds/ 目录是 Helm 3.2+ 新增的关键特性。过去,CRD 必须由管理员提前手动安装( kubectl apply -f crd.yaml ),否则 Chart 中引用的自定义资源类型会报错。现在,Helm 可以在 install 时自动检测并安装 CRD(需加 --create-namespace 参数),且 CRD 本身不参与 Release 生命周期管理——即 uninstall 时不会删除 CRD,避免影响其他使用同一 CRD 的 Release。这个设计平衡了便利性与安全性:CRD 是集群级契约,不该随单个应用的启停而消失。

注意:Chart.yaml 中的 version 字段(如 1.10.3)是 Chart 本身的版本号,与应用镜像版本(如 harbor-core:v2.8.1)无关。两者需独立维护。常见错误是只更新镜像 tag 却忘了 bump Chart version,导致 helm upgrade 时因版本未变而跳过更新——Helm 认为“没变化就不动”,但实际镜像已换。

3. 从零构建一个生产级 Harbor Chart:实战步骤、参数精调与 Ingress 通路验证

光看理论不如动手一次。下面以在 Ubuntu 22.04 的 Kubernetes 集群(通过 KubeKey 部署)上部署 Harbor 为例,手把手带你走通 Helm 3 全流程,并重点解决热搜词中高频出现的“Ingress 无法访问”问题。

3.1 环境准备:确认集群状态与 Helm 3 客户端就绪

首先验证基础环境。执行以下命令,确保输出符合预期:

# 检查 Kubernetes 集群状态(KubeKey 部署后应显示 3 个 Ready 节点)
kubectl get nodes -o wide
# NAME     STATUS   ROLES                  AGE   VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
# node1    Ready    control-plane,master   5d    v1.25.6   192.168.1.10   <none>        Ubuntu 22.04.3 LTS   5.15.0-91-generic   containerd://1.6.25

# 检查 Helm 3 CLI 版本(必须 >= 3.8.0,旧版本对 Kubernetes 1.25+ 支持不全)
helm version
# version.BuildInfo{Version:"v3.13.2", GitCommit:"...", GoVersion:"go1.21.4"}

# 添加 Bitnami 官方仓库(Harbor Chart 托管于此)
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

关键检查点:

  • kubectl get nodes 输出中 ROLES 列应包含 control-plane master ,证明控制平面正常;
  • helm version 显示 v3.x 且无 Error ,说明客户端已正确安装;
  • helm repo update 成功后, helm search repo harbor 应返回至少 3 条结果(bitnami/harbor, harbor/harbor, stable/harbor)。

提示:不要用 stable/ 仓库的 Harbor Chart!该仓库已于 2020 年归档,Chart 严重过时(仍基于 Harbor v1.x),且不支持 Kubernetes 1.22+ 的废弃 API(如 extensions/v1beta1 Ingress)。Bitnami 的 bitnami/harbor 是目前最活跃、兼容性最好的选择。

3.2 定制化 values.yaml:破解 Ingress 无法访问的三大根源

热搜词“helm部署harbor 通过ingress 但无法访问”是 Helm 新手最高频问题。根本原因不在 Helm 本身,而在 Ingress 控制器与 Harbor 配置的耦合细节。我们通过定制 values.yaml 一次性解决:

# 创建自定义 values-harbor-prod.yaml
ingress:
  enabled: true
  # 根源一:Ingress Class 必须匹配集群中实际运行的控制器
  # 查看你的 Ingress Controller 类型:kubectl get ingressclass
  # 如果是 Nginx,class 应为 "nginx";如果是 Traefik,则为 "traefik"
  className: "nginx"
  # 根源二:Host 必须与你规划的域名一致,且 DNS 已解析到 Ingress Controller 的 LoadBalancer IP
  hosts:
    - harbor.example.com
  # 根源三:TLS 配置缺失导致 HTTP 重定向失败
  tls:
    - secretName: harbor-tls
      hosts:
        - harbor.example.com

# Harbor 自身配置:确保 UI 和 API 使用 HTTPS
harborCore:
  # 启用 HTTPS 重定向(关键!否则浏览器访问 http://harbor.example.com 会卡住)
  enableHttps: true

# 外部服务地址:告诉 Harbor 它的公网访问入口
externalURL: "https://harbor.example.com"

# 存储配置:Ubuntu 22.04 默认使用 containerd,推荐 hostPath 或 NFS
persistence:
  enabled: true
  resourcePolicy: "keep" # 卸载时保留 PV 数据,避免误删镜像
  persistentVolumeClaim:
    registry:
      storageClass: "local-path" # KubeKey 默认安装的 local-path StorageClass
      accessModes: ["ReadWriteOnce"]
      size: "50Gi"

这份配置直击痛点:

  • className 显式指定 Ingress Class,避免 Helm 默认使用 nginx 但集群实际运行 traefik 的错配;
  • tls.secretName 要求你提前创建 TLS Secret( kubectl create secret tls harbor-tls --cert=cert.pem --key=key.pem -n harbor-prod ),这是 Ingress 正常终止 HTTPS 的前提;
  • harborCore.enableHttps: true 强制 Harbor 内部组件使用 HTTPS 通信,防止因协议混用导致的 502/503 错误。

3.3 一键部署与通路验证:从 install 到 curl 测试的完整闭环

执行部署命令,注意命名空间隔离和权限控制:

# 创建专用命名空间(Helm 3 推荐做法)
kubectl create namespace harbor-prod

# 执行安装(指定自定义 values 文件和命名空间)
helm install my-harbor bitnami/harbor \
  --version 11.2.10 \
  --namespace harbor-prod \
  --values values-harbor-prod.yaml \
  --create-namespace

# 实时观察部署状态(重点关注 harbor-core、harbor-jobservice 的 Pod 是否 Running)
kubectl get pods -n harbor-prod -w
# NAME                                    READY   STATUS    RESTARTS   AGE
# my-harbor-harbor-core-7c8b9d5f4-2xqzr   1/1     Running   0          2m
# my-harbor-harbor-jobservice-5b6c8d9f4-7v8n9  1/1  Running   0          2m

# 验证 Ingress 资源是否正确生成
kubectl get ingress -n harbor-prod
# NAME           CLASS   HOSTS              ADDRESS         PORTS     AGE
# my-harbor      nginx   harbor.example.com 192.168.1.100   80, 443   3m

# 关键验证:curl 测试(需提前在 /etc/hosts 添加 192.168.1.100 harbor.example.com)
curl -k https://harbor.example.com/api/v2.0/systeminfo
# {"registry_url":"https://harbor.example.com","harbor_version":"v2.8.1","...

如果 curl 返回 JSON,说明 Ingress 通路已打通。若返回 curl: (7) Failed to connect ,请按此顺序排查:

  1. kubectl get svc -n ingress-nginx (或你的 Ingress Controller 命名空间),确认 ingress-nginx-controller Service 的 EXTERNAL-IP 是否为 <pending> ?若是,说明 LoadBalancer 类型 Service 未获得云厂商 IP,需改用 NodePort 或 HostNetwork 模式;
  2. kubectl describe ingress my-harbor -n harbor-prod ,检查 Events 中是否有 Failed to fetch endpoints 等错误,指向后端 Service 未就绪;
  3. kubectl logs -n harbor-prod deploy/my-harbor-harbor-core ,搜索 failed to initialize ,确认数据库连接或 Redis 连接是否超时。

4. Helm 3 进阶实战:版本管理、灰度发布与 Chart 仓库私有化搭建

当团队从单人运维走向多人协作,Helm 的价值才真正爆发。以下三个场景,覆盖企业级落地的核心需求。

4.1 Chart 版本管理:用 SemVer 2.0 规范驱动 CI/CD 流水线

Helm Chart 的版本号(Chart.yaml 中的 version )必须遵循 Semantic Versioning 2.0(SemVer)规范: MAJOR.MINOR.PATCH 。这不是形式主义,而是 CI/CD 自动化升级的基石:

  • PATCH (如 1.2.1 → 1.2.2):仅修改 values.yaml 默认值、修复模板小 Bug。 helm upgrade 可无感知滚动更新;
  • MINOR (如 1.2.2 → 1.3.0):新增可选配置项、优化资源请求。需在 CI 中触发兼容性测试;
  • MAJOR (如 1.3.0 → 2.0.0):破坏性变更(如删除旧字段、更改 API 路径)。CI 必须阻断自动升级,强制人工审核。

我们在 GitLab CI 中实践的流水线如下:

stages:
  - lint
  - test
  - package
  - push

lint:
  stage: lint
  script:
    - helm lint ./charts/harbor  # 检查 Chart 语法和最佳实践

test:
  stage: test
  script:
    - helm template ./charts/harbor --set "ingress.enabled=false" | kubectl apply -f - --dry-run=client -o yaml > /dev/null
    # 模拟渲染并校验 YAML 合法性

package:
  stage: package
  script:
    - helm package ./charts/harbor --version $(cat ./charts/harbor/Chart.yaml | grep version | awk '{print $2}')
  artifacts:
    paths:
      - "*.tgz"

push:
  stage: push
  script:
    - helm push harbor-*.tgz my-harbor-repo  # 推送到私有仓库

关键点: helm package 命令会读取 Chart.yaml 中的 version 生成 harbor-1.3.0.tgz ,CI 系统据此触发不同策略。例如,当 version 为 2.0.0 时,流水线自动向 Slack 发送告警:“检测到 MAJOR 版本变更,请立即进行回归测试”。

4.2 灰度发布:用 Helm + Kubernetes 原生能力实现流量切分

Helm 本身不提供流量管理,但可与 Kubernetes 的 Service Mesh(如 Istio)或原生 Ingress 能力深度集成。我们采用最轻量的方案: 双 Release + 权重 Ingress

步骤:

  1. 部署旧版本 Release: helm install harbor-v1 bitnami/harbor --version 11.2.10 --set "ingress.hosts[0]=harbor.example.com" --namespace harbor-prod
  2. 部署新版本 Release: helm install harbor-v2 bitnami/harbor --version 11.3.0 --set "ingress.hosts[0]=harbor-v2.example.com" --namespace harbor-prod
  3. 创建一个统一入口的 Ingress,通过 nginx.ingress.kubernetes.io/canary 注解实现 5% 流量切分:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: harbor-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "insider"
    nginx.ingress.kubernetes.io/canary-weight: "5"
spec:
  ingressClassName: nginx
  rules:
  - host: harbor.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: harbor-v2-harbor-core  # 新版本 Service 名
            port:
              number: 80

这样,携带 insider: always Header 的请求 100% 走新版本;无 Header 请求按 5% 概率走新版本。整个过程无需修改任何 Chart 模板,纯靠 Kubernetes 原生能力实现,成本极低。

4.3 私有 Chart 仓库搭建:用 OCI Registry 替代传统 HTTP 服务

Helm 3.8+ 原生支持 OCI(Open Container Initiative)Registry 作为 Chart 仓库,这是比传统 helm serve 或 ChartMuseum 更安全、更标准的方案。我们用 Harbor 自身作为 OCI 仓库:

# 1. 在 Harbor UI 中创建项目 "helm-charts",启用 "Helm Chart" 类型
# 2. 登录 Harbor OCI 仓库
helm registry login https://harbor.example.com --username admin --password Harbor12345

# 3. 打包并推送 Chart(Helm 3.8+ 语法)
helm package ./charts/harbor
helm push harbor-11.3.0.tgz oci://harbor.example.com/helm-charts

# 4. 客户端拉取(自动处理认证)
helm pull oci://harbor.example.com/helm-charts/harbor --version 11.3.0 --untar

优势:

  • 认证复用 Harbor 的 LDAP/OAuth2,无需额外维护 token;
  • Chart 作为 OCI Artifact,享受 Harbor 的漏洞扫描、镜像签名、保留策略等企业级功能;
  • 推送/拉取全程加密,杜绝中间人篡改风险。

实操心得:首次搭建私有仓库时,务必在 values.yaml 中设置 registry.registryCredentials.create: true ,让 Helm Chart 自动创建 Pull Secret。否则 helm pull 会因认证失败而卡住,错误信息极其晦涩( failed to authorize: failed to fetch anonymous token ),浪费数小时排查。

5. Helm 3 常见故障排查链路:从 “Release not found” 到 “Pending state forever”

再完美的工具也会出问题。以下是我在上百次 Helm 部署中总结的四大高频故障,附带完整的、可复现的排查链路。

5.1 故障现象: Error: release my-harbor not found ,但 kubectl get all -n harbor-prod 显示所有 Pod 正常运行

根因定位过程

  1. 首先确认 Release 是否真的丢失: kubectl get releases.v1.helm.sh -n harbor-prod 。如果返回空,说明 Release 对象被意外删除(如误执行 kubectl delete -f release.yaml );
  2. 检查 Helm CLI 的当前上下文: helm list --all-namespaces 。如果输出为空,但 kubectl config current-context 显示 context 正确,说明 Helm 未找到 kubeconfig 中的用户证书;
  3. 深入验证: kubectl auth can-i list releases.v1.helm.sh --namespace harbor-prod 。如果返回 no ,证明当前用户角色绑定(RoleBinding)未授予 helm.sh/v1 API 组的权限。

修复方案
为当前用户添加最小权限 RoleBinding:

# helm-release-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: helm-release-reader
  namespace: harbor-prod
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: helm-release-reader-role
subjects:
- kind: User
  name: "your-username@domain.com"  # 替换为你的 kubeconfig 用户名
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: helm-release-reader-role
  namespace: harbor-prod
rules:
- apiGroups: ["helm.sh"]
  resources: ["releases"]
  verbs: ["get", "list", "watch"]

kubectl apply -f helm-release-reader.yaml 后, helm list -n harbor-prod 即可恢复显示。

5.2 故障现象: helm install 卡在 STATUS: pending-install ,Pod 始终不 Ready

根因定位过程

  1. kubectl describe pod -n harbor-prod 查看事件(Events):常见错误如 FailedScheduling: 0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/control-plane: } that the pod didn't tolerate. —— 这意味着你的 Harbor Pod 被调度到了 control-plane 节点,但该节点有污点(taint)阻止普通 Pod 运行;
  2. 检查 Pod 的 tolerations 字段: kubectl get pod my-harbor-harbor-core-xxx -n harbor-prod -o yaml | grep -A 5 tolerations 。如果输出为空,说明 Chart 未定义容忍度;
  3. 查看节点污点: kubectl describe node node1 | grep Taints ,确认污点为 node-role.kubernetes.io/control-plane:NoSchedule

修复方案
values.yaml 中显式添加 tolerations:

harborCore:
  tolerations:
    - key: "node-role.kubernetes.io/control-plane"
      operator: "Exists"
      effect: "NoSchedule"

或者更优解:在 values.yaml 中设置 nodeSelector ,强制调度到 worker 节点:

nodeSelector:
  node-role.kubernetes.io/worker: ""

5.3 故障现象: helm upgrade 后,新版本 Pod 启动失败,旧版本被驱逐,服务中断

根因定位过程

  1. kubectl get events -n harbor-prod --sort-by=.lastTimestamp ,查找 Warning BackOff 事件;
  2. kubectl logs -n harbor-prod deploy/my-harbor-harbor-core --previous ,查看上一个崩溃容器的日志;
  3. 最常见原因是 livenessProbe 失败:新版本 Harbor 启动慢(加载数据库 schema),但 livenessProbe 的 initialDelaySeconds: 30 不够,导致探针在启动完成前就判定失败,反复重启。

修复方案
values.yaml 中延长探针等待时间:

harborCore:
  livenessProbe:
    initialDelaySeconds: 120  # 从 30 秒延长至 120 秒
    periodSeconds: 30
  readinessProbe:
    initialDelaySeconds: 60   # readiness 同样延长

5.4 故障现象: helm rollback 失败,提示 Error: release my-harbor has no previous release

根因定位过程

  1. helm history my-harbor -n harbor-prod ,确认历史记录是否为空;
  2. 检查 Helm 3 的 Release 保留策略:默认只保留最近 10 次 Release。如果之前执行过 10 次 upgrade,第 1 次的 Release 记录已被自动清理;
  3. kubectl get secrets -n harbor-prod | grep my-harbor ,确认是否存在 sh.helm.release.v1.my-harbor.v1 v10 的 Secret。如果最大编号是 v10 ,而你想 rollback 到 v5 ,但 v5 Secret 已被 GC,就会失败。

修复方案
永久性增加保留数量(在 values.yaml 中):

# 仅适用于 Helm 3.12+,通过 Helm 自身配置
# 但更通用的做法是:在 CI/CD 中,每次 upgrade 前先 `helm get values my-harbor -n harbor-prod > values-v$(date +%s).yaml`
# 手动备份 values,rollback 时 `helm upgrade --reuse-values --values values-v1678901234.yaml`

最后分享一个小技巧:当遇到无法解释的 Helm 错误时,用 --debug --dry-run 组合拳。 helm install ... --debug --dry-run 会输出 Helm 渲染后的完整 YAML 到终端,而不实际提交到集群。你可以复制这段 YAML,用 kubectl apply -f - --dry-run=client -o yaml 再次验证,快速区分问题是出在 Helm 模板渲染阶段,还是 Kubernetes API Server 接收阶段。这个技巧帮我节省了超过 200 小时的无效排查时间。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐