跳转至

Helm 使用手册 —— 专为本次 Traefik 部署

适用对象:不熟悉 Helm 的使用者 适用环境:traefik_deploy/ 这套交付物 + 目标集群(K8s v1.36.4) 命名空间:Traefik 部署在 server(2026-09-18 由 traefik 迁移而来) 本机 Helm 版本:v3.16.3(命令按 Helm 3 语法书写,v4 差异见文末)


0. 先记住三件事

  1. Helm 只是"模板渲染器 + 版本记录器"。它不常驻集群,也不会偷偷改东西;你敲什么命令,它就把渲染结果提交给 Kubernetes API。
  2. 只有"改 Traefik 自身"才需要 Helm。加/改路由(IngressRoute、Middleware)用 kubectl apply 就够了,跟 Helm 无关。
  3. Helm 的变更只有两步:改 values.yaml → helm upgrade。回滚是 helm rollback。
# 后续所有命令都假设你在这个目录(每个新终端执行一次)
cd /home/rain/Documents/k8s_ins/traefik_deploy

1. 三个核心概念(对应本次的实体)

概念 含义 本次对应的实体
Chart 打包好的应用模板目录(含默认值) chart/traefik-41.6.0.tgz(可解包版在 chart/traefik/)
Release Chart 在集群里的一次"安装实例",名字+命名空间唯一 release 名 traefik,命名空间 traefik
Values 覆盖 Chart 默认值的参数 values.yaml(你的常改文件)

覆盖关系一句话:values.yaml 里的值 > Chart 默认值,没写的键就用默认值。

查看 Chart 的全部默认值:

helm show values chart/traefik-41.6.0.tgz | less      # 与 docs/chart-41.6.0-default-values.yaml 同内容

2. 本次部署的构成(哪些东西归 Helm 管)

Helm release: traefik (ns=server)
├── 由 Helm chart 生成(helm 管)
│   ├── Deployment traefik            ← 单副本,固定 k8s-master-01
│   ├── Service traefik (ClusterIP)
│   ├── IngressClass traefik (default)
│   ├── ServiceAccount / ClusterRole / ClusterRoleBinding
│   └── IngressRoute traefik-dashboard ← Dashboard 的路由
├── 由 kubectl 单独创建(不归 Helm 管)
│   ├── CRD(10 个 traefik.io 组)      ← 手工装,见 SOP 第 5 章步骤 4
│   ├── Secret traefik-selfsigned-tls   ← 自签证书
│   ├── Secret traefik-dashboard-auth   ← Dashboard 口令
│   └── Middleware dashboard-auth
└── 业务后续自建(不归 Helm 管)
    └── 各命名空间的 IngressRoute / Middleware / Ingress

记住这条边界:helm uninstall 只删第一组,CRD、Secret、Middleware 和业务路由都会留下。


3. 只读命令速查(先学会看,再学会改)

# 本命名空间有哪些 release
helm list -n server
# 所有命名空间
helm list -A

# release 的详细状态(含 NOTES、资源清单摘要)
helm status traefik -n server

# 变更历史(每次 upgrade/rollback 一条,回滚靠它)
helm history traefik -n server

# 当前生效的、你提供的 values(不含 chart 默认值)—— 建议定期存一份做对比
helm get values traefik -n server
helm get values traefik -n server > docs/values-applied-$(date +%Y%m%d).yaml

# 你提供的 values + chart 默认值合并后的完整结果(排查"这个值到底是多少")
helm get values traefik -n server --all

# 当前实际提交给集群的所有 YAML(最重要的排错入口)
helm get manifest traefik -n server | less

# 看某类资源是怎么渲染出来的,例如容器启动参数
helm get manifest traefik -n server | grep -A3 'entryPoints'

4. 标准变更流程(四步,任何改动都走这个)

# ① 改配置
vim values.yaml

# ② 本地预览:渲染出完整 YAML,不碰集群。先看 diff 再决定是否应用
helm template traefik chart/traefik-41.6.0.tgz -n server -f values.yaml --skip-crds > /tmp/after.yaml
helm get manifest traefik -n server > /tmp/before.yaml
diff /tmp/before.yaml /tmp/after.yaml        # 只应出现你打算改的部分

实测经验:在没改 values 的情况下,这个 diff 应该完全一致(最多一个空行差异)。所以"diff 里冒出多余内容"本身就是信号——说明有别的因素影响到渲染结果,先查清楚再应用。

# ③ 应用(--wait 表示等 Pod 就绪再返回)
helm upgrade traefik chart/traefik-41.6.0.tgz -n server -f values.yaml \
  --skip-crds --wait --timeout 4m

# ④ 验证
kubectl -n server get pods -o wide
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.31.10/

两个必须带的参数及原因:

  • -n server:不加就会落到 default 命名空间,等于另起一个 release。
  • --skip-crds:CRD 已由 kubectl 手工安装(只装了 10 个 traefik.io 组,跳过 chart 自带的 15 个 Hub CRD)。不加这个参数,首次安装路径会把 Hub CRD 也一起装进来。

5. 场景一:加一个入口端口

5.1 加 HTTP 端口(例如把管理后台放到 8081)

编辑 values.yaml,在 ports: 下新增一段:

ports:
  # ...原有的 web / websecure 保持不动...
  admin:
    port: 8081            # 容器内端口
    hostPort: 8081        # 宿主机端口(对外就访问这个)
    expose:
      default: false      # 不加入 Service(走 hostPort 即可,这个端口只在本机测试)
    exposedPort: 8081
    protocol: TCP

端口名(admin)只是标识符。一个 entrypoint 同时可承载 HTTP 与 TCP 路由:写 IngressRoute 就是 HTTP,写 IngressRouteTCP 就是 TCP,不需要在 values 里声明协议类型。

应用并验证:

helm upgrade traefik chart/traefik-41.6.0.tgz -n server -f values.yaml --skip-crds --wait --timeout 4m

# 确认 entrypoint 已生成
kubectl -n server get deploy traefik -o jsonpath='{.spec.template.spec.containers[0].args}' \
  | tr ',' '\n' | grep entryPoints

# 确认端口已映射
kubectl -n server get deploy traefik -o jsonpath='{.spec.template.spec.containers[0].ports}' | tr '}' '\n'

5.2 加 TCP 端口(例如恢复 MySQL 代理 3306)

TCP 端口不要写 http: 段,chart 会自动生成 --entryPoints.mysql.address=:3306/tcp:

ports:
  mysql:
    port: 3306
    hostPort: 3306
    expose:
      default: false
    exposedPort: 3306
    protocol: TCP

UDP 端口(例如 DNS)把 protocol 改成 UDP;容器内端口与宿主端口保持一致(如都用 53),避免同号 TCP/UDP 两条规则指向不同容器端口。

TCP/UDP 的路由不能用 IngressRoute,要用 IngressRouteTCP / IngressRouteUDP:

apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
  name: mysql-tcp
  namespace: my-ns
spec:
  entryPoints:
    - mysql                    # 对应 values 里新增的端口名
  routes:
    - match: HostSNI(`*`)      # 非 TLS 的纯 TCP 用通配即可
      services:
        - name: mysql-svc
          port: 3306

提示:每加一个端口都会让 Pod 重建(启动参数变了),入口会中断数秒(原因见第 11 章第 1 条)。


6. 场景二:改路由(不碰 Helm)

这是你日常最频繁的改动,全程与 Helm 无关:

# 写一个 IngressRoute 文件后直接应用
kubectl apply -f my-app-ingressroute.yaml

# 删掉
kubectl delete -f my-app-ingressroute.yaml

# 看 Traefik 是否已加载路由(Traefik 是热加载,不重启)
kubectl -n server logs deploy/traefik --tail=20

一个可直接照抄的模板:

apiVersion: traefik.io/v1alpha1        # 注意:v3 已移除 traefik.containo.us
kind: IngressRoute
metadata:
  name: my-app
  namespace: my-ns                     # 建在业务自己的命名空间
spec:
  entryPoints:
    - websecure                        # 需要 HTTPS 就用 websecure
  routes:
    - match: Host(`app.rainchen.top`)
      kind: Rule
      services:
        - name: my-svc                 # 同命名空间内的 Service 名
          port: 80
  tls: {}                              # 留空即使用默认自签证书(tlsStore default)

跨命名空间引用 Service 默认被禁止;如确需,才在 values 里打开 providers.kubernetesCRD.allowCrossNamespace: true。


7. 场景三:升级 / 降级 Traefik 版本

# ① 拉取新 chart(官方源不可达时用 OCI)
helm pull oci://ghcr.io/traefik/helm/traefik --version 41.7.0 -d chart/

# ② 改 values.yaml 里的镜像 tag(chart 的 appVersion 才是权威值,可用下面命令核对)
helm show chart chart/traefik-41.7.0.tgz | grep -E 'version|appVersion'

# ③ 同步 CRD(大版本升级时才需要,本次 CRD 由 kubectl 手工管理)
for f in chart/traefik/crds/traefik.io_*.yaml; do kubectl apply -f "$f"; done

# ④ 升级
helm upgrade traefik chart/traefik-41.7.0.tgz -n server -f values.yaml \
  --skip-crds --wait --timeout 4m

# ⑤ 出问题立刻回滚到上一版
helm rollback traefik -n server          # 不带版本号 = 回退到上一个 revision
helm history traefik -n server           # 确认 rollback 记录

8. 场景四:改副本数 / 换调度节点

deployment:
  kind: Deployment
  replicas: 1                  # 改副本数

nodeSelector:
  kubernetes.io/hostname: k8s-node-01     # 换到 worker 节点(记得同步调整 tolerations)
tolerations: []                            # worker 无污点,可留空数组

⚠️ 不要随便把 replicas 改成 2:当前 nodeSelector 锁定了单节点,而 80/443 是 hostPort,同一节点上第二个 Pod 抢不到端口会永久 Pending(第 11 章第 1 条)。要横向扩容,得先去掉 nodeSelector 并改用多节点方案(DaemonSet + hostNetwork)。


9. 场景五:换命名空间(Helm 不支持直接改)

原因:release 的命名空间是安装时写死的,helm upgrade 无法迁移;且 Secret、Middleware 都是命名空间级资源,必须跟着走。

OLD_NS=server                    # Traefik 当前所在命名空间
NEW_NS=<目标命名空间>            # 目标命名空间,按需修改

# ① 备份当前 values(重要)
helm get values traefik -n "$OLD_NS" > docs/values-before-ns-move.yaml

# ② 卸载旧 release(只删 Helm 管的资源,不动 CRD 与业务路由)
helm uninstall traefik -n "$OLD_NS"

# ③ 在新命名空间重建命名空间级资源
kubectl create namespace "$NEW_NS" --dry-run=client -o yaml | kubectl apply -f -

kubectl -n "$NEW_NS" create secret tls traefik-selfsigned-tls \
  --cert=certs/tls.crt --key=certs/tls.key \
  --dry-run=client -o yaml | kubectl apply -f -

PASS="$(awk -F': ' '/口令/{print $2}' secrets/dashboard-basic-auth.txt)"
HASH="$(openssl passwd -apr1 "$PASS")"
kubectl -n "$NEW_NS" create secret generic traefik-dashboard-auth \
  --from-literal=users="admin:${HASH}" --dry-run=client -o yaml | kubectl apply -f -

# ④ 用新命名空间重新安装(--create-namespace 可省略,上一步已建)
helm upgrade --install traefik chart/traefik-41.6.0.tgz -n "$NEW_NS" -f values.yaml \
  --skip-crds --wait --timeout 4m

⚠️ 两处容易漏:

  1. manifests/10-dashboard-auth.yaml 里的 metadata.namespace 必须改成新命名空间后再 kubectl apply,否则 Dashboard 会 404(找不到中间件)。
  2. 旧命名空间若确认无其他资源,再决定是否删除:kubectl delete namespace "$OLD_NS"。

10. 场景六:回滚与卸载

# 回滚(不带版本号 = 回退一格;也可指定 helm rollback traefik 3 -n server)
helm rollback traefik -n server
kubectl -n server get pods              # 确认 Pod 已重建

# 卸载:删掉 Deployment/Service/IngressClass/RBAC/IngressRoute
helm uninstall traefik -n server

# 卸载后残留清理(按需,注意顺序与风险)
kubectl delete -f manifests/10-dashboard-auth.yaml     # Dashboard 中间件
kubectl delete secret -n server traefik-selfsigned-tls traefik-dashboard-auth
kubectl delete namespace server                        # 【高危】删命名空间会带走里面所有对象
# 【高危】删 CRD 会级联删除集群内所有 IngressRoute 等自定义资源,务必先备份:
kubectl get ingressroutes,middlewares,ingressroutetcps,ingressrouteudps,tlsstores -A -o yaml > /tmp/traefik-cr-backup.yaml
kubectl get crd -o name | grep 'traefik\.io' | xargs -r kubectl delete

11. 本次部署踩过的坑(照抄官方默认值会中招)

坑 1:hostPort + 单副本 → 滚动更新死锁

现象:helm upgrade --wait 卡住直到超时,Error: UPGRADE FAILED: context deadline exceeded,新 Pod 一直是 Pending:

0/4 nodes are available: 1 node(s) didn't have free ports for the requested pod ports,
3 node(s) didn't match Pod's node affinity/selector.

原因:chart 默认 maxUnavailable: 0 / maxSurge: 1,意味着"先起新 Pod、就绪后再删旧 Pod"。但新 Pod 在旧 Pod 释放宿主 80/443 之前无法被调度,两边互等。

已修复(values.yaml 中,勿改回):

updateStrategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 1     # 先停旧,再起新
    maxSurge: 0

代价是升级瞬间入口中断约 5–15 秒,这是单副本 + hostPort 的固有取舍。

坑 2:service.spec.type 必须是 ClusterIP

集群没有 LoadBalancer 实现(无 MetalLB),chart 默认 type: LoadBalancer 会让 EXTERNAL-IP 永远 <pending>。对外入口靠 hostPort 承担,Service 保持集群内可达即可。

坑 3:release 卡在 pending-upgrade

如果在 --wait 期间强行中断命令(Ctrl-C 或停止终端命令),release 会停在 pending-upgrade,后续操作报 another operation (install/upgrade/rollback) is in progress。

helm history traefik -n server           # 找到 pending 的那个 revision 号,假设是 3
kubectl -n server delete secret sh.helm.release.v1.traefik.v3
helm list -n server -a                   # 确认回到上一个状态后继续操作

坑 4:不要用 --set 做长期配置

--set 只适合临时试一次。它不会被记进 values.yaml,下次谁升级都可能把你的临时值冲掉(--set 与 -f 的优先级:--set > -f,但都低于"不传时的默认值回退"逻辑,容易误判)。

# 临时试一次可以,验证完请落到 values.yaml
helm upgrade traefik chart/traefik-41.6.0.tgz -n server -f values.yaml \
  --set log.level=DEBUG --skip-crds --wait

12. 常见报错速查

报错 原因 处理
another operation (install/upgrade/rollback) is in progress release 卡在 pending 见第 11 章坑 3
UPGRADE FAILED: context deadline exceeded --wait 超时,多为 Pod 起不来 kubectl -n server get events --sort-by=.lastTimestamp \| tail,再看第 11 章坑 1
cannot re-use a name that is still in use 同名 release 已存在于该命名空间 helm list -A 找到它,用 helm upgrade 或先 helm uninstall
values don't meet the specifications of the schema values 键名/类型写错 对照 docs/chart-41.6.0-default-values.yaml(键名大小写敏感,如 accessLog 不是 accessLogs)
no matches for kind "IngressRoute" CRD 未安装 执行 SOP 第 5 章步骤 4 安装 traefik.io 组 CRD
ImagePullBackOff 节点拉不到镜像 在节点上 ctr -n k8s.io images pull docker.io/library/traefik:<tag>
Dashboard 404 中间件不在同一命名空间或缺失 kubectl get middleware -n server,检查 manifests/10-dashboard-auth.yaml 的 namespace

13. 命令速查表(备查)

# —— 只读 ——
helm list -n server                       # release 列表
helm status traefik -n server             # 状态 + NOTES
helm history traefik -n server            # 变更历史
helm get values traefik -n server         # 我的 values
helm get values traefik -n server --all   # 合并后的完整 values
helm get manifest traefik -n server       # 实际提交的 YAML
helm show values chart/traefik-41.6.0.tgz  # chart 默认值
helm show chart chart/traefik-41.6.0.tgz   # chart 元信息(appVersion 即默认镜像版本)

# —— 预览 ——
helm template traefik chart/traefik-41.6.0.tgz -n server -f values.yaml   # 本地渲染
helm upgrade traefik chart/traefik-41.6.0.tgz -n server -f values.yaml \
  --skip-crds --dry-run=server             # 服务端校验,不落库(输出 STATUS 显示 pending-upgrade 属正常的模拟态)

# —— 变更 ——
helm upgrade traefik chart/traefik-41.6.0.tgz -n server -f values.yaml \
  --skip-crds --wait --timeout 4m
helm rollback traefik -n server
helm uninstall traefik -n server

# —— 拉取 chart ——
helm pull oci://ghcr.io/traefik/helm/traefik --version 41.6.0 -d chart/

14. 进一步学习与迁移提示

  • 官方文档:https://helm.sh/docs/(Chart 模板语法、values 合并规则)
  • Traefik chart 的 values 全量说明:解包目录 chart/traefik/README.md 与 chart/traefik/VALUES.md
  • 本机 Helm v3.16.3,而 Helm 3 已于 2026-09-09 发布最后一个功能版本,安全支持到 2027-02-10 结束;当前稳定线是 Helm 4(2025-11 GA)。Helm 4 可直接接管现有 release(存储格式一致),换二进制即可,主要差异:
  • --atomic 改名为 --rollback-on-failure,--force 改名为 --force-replace(旧名仍可用,会有弃用提示)
  • --wait 依赖 kstatus,需要 watch 权限(本集群用 cluster-admin,无影响)
  • post-renderer 由可执行文件改为插件形式(本次未使用,无影响)

来源:/home/rain/Documents/k8s_ins/traefik_deploy/docs/Helm使用手册-Traefik.md | 最后更新:2026-09-18 00:33(由 build/sync.py 同步,请勿在站点侧修改)