Traefik 入口代理部署变更 SOP¶
交付物目录:
traefik_deploy/(相对项目根目录) 执行时间:2026-09-17 02:30–02:38(CST) 执行结果:成功 命名空间注记:本文档首次执行时使用traefik命名空间;2026-09-18 已迁移至server,文中命令与清单均已同步更新,旧命名空间已删除。
1. 背景¶
- 集群为新建 Kubernetes v1.36.4(1 个 control-plane + 3 个 worker,Calico CNI),集群内没有任何入口代理组件(无 Ingress Controller、无 IngressClass、无 LoadBalancer 实现)。
- 旧集群以 Traefik v2.5 承担 HTTP/HTTPS 入口,但:其镜像仓库
harbor.rainchen.com在新环境已不可达;v2.11 线的安全支持已于 2026-09-07 到期;旧配置使用traefik.containo.usCRD 组,该组在 v3 中已被移除。 - 因此需要以当前活跃支持线重建入口代理层。
2. 目标¶
变更完成后应达到的可验证状态:
- Helm release
traefik状态deployed,charttraefik-41.6.0,应用版本 v3.7.13(Traefik 当前唯一处于 Active+Security 支持的 minor 线的最新补丁)。 - Pod
1/1 Running且固定运行在k8s-master-01。 - 对外提供 HTTP/HTTPS 入口:
http://192.168.31.10/返回 404(已接管且无匹配路由),HTTPS 使用自签证书正常完成握手。 - Dashboard 经
https://traefik.rainchen.top/dashboard/访问,未认证返回 401,认证后返回 200。 - 具备
IngressRoute/Ingress/Middleware路由能力,供业务后续按命名空间自行接入。
3. 前置条件¶
| 项目 | 要求 | 本次实测 |
|---|---|---|
| 集群权限 | 具备 cluster-admin 的 kubeconfig | kubernetes-admin@kubernetes,API 192.168.31.8:16443 |
| 执行机工具 | helm / kubectl / openssl / curl | helm v3.16.3、kubectl v1.36.4、OpenSSL 3.0.13 |
| chart 来源 | 执行机可达 chart 仓库 | charts.traefik.io、traefik.github.io 不可达;改用 OCI ghcr.io 拉取 |
| 镜像来源 | 集群节点可达镜像仓库 | 节点可达 docker.io;镜像已预拉:ctr -n k8s.io images pull docker.io/library/traefik:v3.7.13 |
| 端口占用 | k8s-master-01 的 80/443 空闲 |
已核实空闲 |
| 既有资源 | 无同名命名空间 / CRD 残留 | traefik 命名空间与 CRD 均不存在 |
前置检查命令:
kubectl get ns traefik # 预期:NotFound
kubectl get crd | grep traefik.io # 预期:无输出
timeout 10 ssh root@192.168.31.10 "ss -lntp | grep -E ':(80|443)\b'" # 预期:无输出
4. 影响范围¶
- 主机:仅
k8s-master-01(192.168.31.10),占用其宿主机 80/443/389/636/3306(由 CNI portmap 以 iptables DNAT 实现,ss不会显示监听,属正常)。 - 端口追加记录:2026-09-18 为内网 MariaDB 增加
mariadbentryPoint(容器 3306 → 宿主 3306),对应的IngressRouteTCP由ingress_tunnel_deploy工程下发。本次helm upgrade后 release revision 3,因单副本 + hostPort 需"先停旧再起新",公网入口中断约数秒;升级后实测 5 个公网域名(gitlab / prometheus / grafana / traefik / ldapadmin)均正常响应。 - 集群对象:新增命名空间
traefik、10 个traefik.io组 CRD、1 个 Deployment、1 个 Service、1 个 IngressClass(默认类)、2 个 Secret、1 个 Middleware、1 个 Dashboard IngressRoute。
5. 分步操作¶
对应实现文件:
traefik_deploy/values.yaml、traefik_deploy/manifests/10-dashboard-auth.yaml、traefik_deploy/certs/tls-san.cnf以下代码块以实现体为准,仅供阅读、复核与手工复现;幂等与错误处理由 Helm/kubectl 自身保证。
BASE="/home/rain/Documents/k8s_ins/traefik_deploy" # 交付物目录
# —— 步骤 1:获取 chart(官方源不可达时走 OCI)——
cd "$BASE/chart"
helm pull oci://ghcr.io/traefik/helm/traefik --version 41.6.0 -d .
tar -xzf traefik-41.6.0.tgz # 解包作为离线参考
helm show values traefik-41.6.0.tgz > "$BASE/docs/chart-41.6.0-default-values.yaml"
# —— 步骤 2:生成自签证书(内部 CA 签发,有效期 3650 天)——
cd "$BASE/certs"
openssl genrsa -out ca.key 4096 # 内部 CA 私钥
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \
-subj "/C=CN/O=Rainchen Internal/CN=Rainchen Internal CA" -out ca.crt
openssl genrsa -out tls.key 2048 # 服务器私钥
openssl req -new -key tls.key \
-subj "/C=CN/O=Rainchen Internal/CN=traefik.rainchen.top" -out tls.csr
openssl x509 -req -in tls.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out tls.crt -days 3650 -sha256 -extfile tls-san.cnf -extensions v3_req
chmod 600 ca.key tls.key # 私钥仅属主可读
rm -f tls.csr ca.srl
# —— 步骤 3:创建命名空间(幂等写法)——
kubectl create namespace server --dry-run=client -o yaml | kubectl apply -f -
# —— 步骤 4:安装 CRD(只装 traefik.io 组,跳过 chart 中 15 个无用的 Hub CRD)——
for f in "$BASE"/chart/traefik/crds/traefik.io_*.yaml; do
kubectl apply -f "$f"
done
# —— 步骤 5:导入 TLS 自签证书为 Secret ——
kubectl -n server create secret tls traefik-selfsigned-tls \
--cert="$BASE/certs/tls.crt" --key="$BASE/certs/tls.key" \
--dry-run=client -o yaml | kubectl apply -f -
# —— 步骤 6:创建 Dashboard BasicAuth 凭据(口令随机生成,不入版本库)——
openssl rand -base64 30 | tr -dc 'A-Za-z0-9' | cut -c1-20 # 生成 20 位口令
openssl passwd -apr1 "$PASS" # 生成 htpasswd 摘要
kubectl -n server create secret generic traefik-dashboard-auth \
--from-literal=users="admin:${HASH}" --dry-run=client -o yaml | kubectl apply -f -
# 口令落盘于 secrets/dashboard-basic-auth.txt(权限 600),请妥善保管
# —— 步骤 7:应用 Dashboard 认证中间件 ——
kubectl apply -f "$BASE/manifests/10-dashboard-auth.yaml"
# —— 步骤 8:部署 Traefik(【高危】占用 k8s-master-01 宿主机 80/443)——
helm upgrade --install traefik "$BASE/chart/traefik-41.6.0.tgz" \
-n server -f "$BASE/values.yaml" \
--skip-crds --wait --timeout 5m
关键配置要点(详见 traefik_deploy/values.yaml 注释):
- 容器内用非特权端口 8000/8443,宿主端口 80/443 由
hostPort承担; service.spec.type: ClusterIP——集群无 LoadBalancer 实现,保持默认LoadBalancer会一直 Pending;updateStrategy.rollingUpdate.maxUnavailable: 1 / maxSurge: 0——单副本 + hostPort 场景下新 Pod 抢不到宿主端口,必须"先停旧再起新";providers.kubernetesCRD.safeNaming: true、ports.*.http.aliasHeadersStrategy: delete、core.strictTLSOptions: true——按官方建议补齐的安全项。
6. 验证¶
# 1) release 与工作负载
helm list -n server # 预期 STATUS=deployed,CHART=traefik-41.6.0
kubectl -n server get pods -o wide # 预期 1/1 Running,NODE=k8s-master-01
kubectl -n server get deploy traefik # 预期 READY 1/1
# 2) 入口连通性
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.31.10/ # 预期 404
curl -sk -o /dev/null -w '%{http_code}\n' \
--resolve traefik.rainchen.top:443:192.168.31.10 \
https://traefik.rainchen.top/dashboard/ # 预期 401(未带凭据)
curl -sk -o /dev/null -w '%{http_code}\n' -u admin:<口令> \
--resolve traefik.rainchen.top:443:192.168.31.10 \
https://traefik.rainchen.top/dashboard/ # 预期 200
# 3) TLS 证书
openssl s_client -connect 192.168.31.10:443 -servername traefik.rainchen.top </dev/null 2>/dev/null \
| openssl x509 -noout -subject -enddate # 预期 CN=traefik.rainchen.top
# 4) IngressClass
kubectl get ingressclass # 预期 traefik (default)
# 5) 启动日志(应无 ERROR)
kubectl -n server logs deploy/traefik --tail=30 | grep -iE 'err' || echo "无错误"
本次执行实测结果:release traefik revision 3 deployed;Pod traefik-f45b5b784-zdcbw 1/1 Running(k8s-master-01);HTTP 404 / HTTPS 401 / 认证 200;证书 CN=traefik.rainchen.top 有效期至 2036-09-13;IngressClass traefik (default)。
幂等复验:重复执行步骤 8 的 helm upgrade,Deployment generation 保持为 3 不变、Pod 无重启,即资源零变更。
7. 回滚¶
本次为新增组件,未覆盖任何既有配置,回滚风险低。备份物:traefik_deploy/values.yaml、traefik_deploy/certs/(CA 与服务端证书)、traefik_deploy/docs/rendered-manifests.yaml(渲染快照)。
# 方案 A:仅移除 Traefik 本体,保留 CRD 与路由资源定义(推荐)
helm uninstall traefik -n server
kubectl -n server get pods # 预期:无 Pod,80/443 释放
# 方案 B:连命名空间一并清理(【高危】将删除该命名空间内的 Secret 等全部对象)
kubectl delete namespace server
# 方案 C:继续移除 CRD(【高危】会级联删除集群中所有 IngressRoute/Middleware 等自定义资源)
# 执行前必须先备份:
kubectl get ingressroutes,middlewares,ingressroutetcps,tlsstores -A -o yaml > /tmp/traefik-cr-backup.yaml
kubectl get crd -o name | grep 'traefik\.io' | xargs -r kubectl delete
回滚后验证:curl -s -o /dev/null -w '%{http_code}\n' http://192.168.31.10/ 应返回连接失败或非 404;helm list -n server 应无该 release;kubectl -n server get pods 为空。
8. 风险说明¶
| 风险 | 说明 | 缓解措施 |
|---|---|---|
| 入口单点 | 单副本固定在 k8s-master-01,节点宕机即入口中断 |
后续可改 deployment.kind: DaemonSet + hostNetwork 实现多节点入口;或引入 VIP |
| 更新瞬断 | 单副本 + hostPort 必须先停旧 Pod,升级期间入口中断数秒 | 避开业务高峰变更;如需零中断,需先改多副本 + 反亲和 + 非固定端口方案 |
| 调度死锁 | maxUnavailable: 0 会导致新 Pod 抢不到宿主端口而永久 Pending(本次已实际踩到) |
已固定为 maxUnavailable: 1 / maxSurge: 0,勿改回 |
| 占用控制面节点端口 | 80/443 绑定在 control-plane 节点 | 端口已核实空闲;如需解耦可将 nodeSelector 指向 worker 节点 |
| 自签证书不受信 | 客户端需导入 certs/ca.crt,否则浏览器告警 |
内部 CA 已生成,可分发 ca.crt 给内网客户端;后续可换正式 CA 或 ACME |
| 凭据泄露 | Dashboard BasicAuth 口令落盘于 secrets/dashboard-basic-auth.txt |
文件权限 600;口令为随机生成;如泄露执行 kubectl -n server delete secret traefik-dashboard-auth 后重跑步骤 6–7 |
| CRD 生命周期不由 Helm 管理 | 使用 --skip-crds,升级 Traefik 大版本时需手工同步 CRD |
升级前重跑第 5 章步骤 4;删除 CRD 属高危操作,须先备份自定义资源 |
| Helm 3 版本偏旧 | 本机 helm v3.16.3,Helm 3 定于 2027-02-10 终止安全支持 | 后续将 helm 升级至 Helm 4(当前稳定线);chart、release 存储格式均兼容,可直接替换二进制 |
| ``` |
来源:
/home/rain/Documents/k8s_ins/traefik_deploy/SOP.md| 最后更新:2026-09-18 04:42(由build/sync.py同步,请勿在站点侧修改)