Helm 使用手册 —— 专为本次 Traefik 部署¶
适用对象:不熟悉 Helm 的使用者 适用环境:
traefik_deploy/这套交付物 + 目标集群(K8s v1.36.4) 命名空间:Traefik 部署在server(2026-09-18 由traefik迁移而来) 本机 Helm 版本:v3.16.3(命令按 Helm 3 语法书写,v4 差异见文末)
0. 先记住三件事¶
- Helm 只是"模板渲染器 + 版本记录器"。它不常驻集群,也不会偷偷改东西;你敲什么命令,它就把渲染结果提交给 Kubernetes API。
- 只有"改 Traefik 自身"才需要 Helm。加/改路由(IngressRoute、Middleware)用
kubectl apply就够了,跟 Helm 无关。 - 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
⚠️ 两处容易漏:
manifests/10-dashboard-auth.yaml里的metadata.namespace必须改成新命名空间后再kubectl apply,否则 Dashboard 会 404(找不到中间件)。- 旧命名空间若确认无其他资源,再决定是否删除:
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同步,请勿在站点侧修改)