跳到正文
Træfɪk

从 Ingress NGINX Controller 迁移到 Traefik

如何以零停机方式从 Ingress NGINX Controller 迁移到 Traefik。


Ingress NGINX Controller 退役

Kubernetes Ingress NGINX Controller 项目已宣布于 2026年3月退役。此后:

  • 不再发布新版本或更新
  • 不再提供安全补丁
  • 不再修复缺陷

更多信息请参阅 Kubernetes 官方博客公告。

迁移后的结果

完成迁移后,现有 Ingress 资源无需修改就能由 Traefik 提供服务。Traefik Kubernetes Ingress NGINX 提供者会自动将 NGINX 注解转换为 Traefik 配置:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp
  annotations:
    # These NGINX annotations are automatically translated by Traefik
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://example.com"
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "route"
spec:
  ingressClassName: nginx  # ← Traefik will watch this class
  rules:
    - host: myapp.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: whoami
                port:
                  number: 80
apiVersion: apps/v1
kind: Deployment
metadata:
  name: whoami
spec:
  replicas: 2
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
        - name: whoami
          image: traefik/whoami
          ports:
            - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: whoami
spec:
  selector:
    app: whoami
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

完整的注解支持列表和行为差异,请参阅 Ingress NGINX 路由配置文档。

Traefik 版本要求

Kubernetes Ingress NGINX 提供者要求 Traefik v3.6.2 或更新版本。


前置条件

开始迁移前,确保具备:

  • Kubernetes 集群中正在运行的现有 Ingress NGINX Controller
  • 已配置 kubectl 的 Kubernetes 集群访问能力
  • 集群支持多个 LoadBalancer 服务同时监听 80/443 端口
  • Helm
  • 可创建 RBAC 资源的集群管理员权限
  • 关键配置备份,包括 Ingress 资源、ConfigMap 和 Secret

备份建议

# Export all Ingress resources
kubectl get ingress --all-namespaces -o yaml > ingress-backup.yaml

# Export NGINX ConfigMaps
kubectl get configmap --all-namespaces -l app.kubernetes.io/name=ingress-nginx -o yaml > nginx-configmaps.yaml

迁移策略概览

本迁移通过让 Traefik 与 NGINX 并行运行实现零停机。两个控制器同时为相同的 Ingress 资源提供服务,因此可以逐步切换流量,再移除 NGINX。

Current:     DNS → LoadBalancer → NGINX → Your Services

Migration:   DNS → LoadBalancer → NGINX  → Your Services
                 → LoadBalancer → Traefik → Your Services

Final:       DNS → LoadBalancer → Traefik → Your Services

迁移流程:

  • 步骤 0:检查 ingress-nginx ConfigMap,将集群级默认值转换为 Traefik 配置
  • 步骤 1:在 NGINX 旁部署 Traefik
  • 步骤 2:验证 Traefik 正确处理流量
  • 步骤 3:逐步将流量从 NGINX 切换至 Traefik
  • 步骤 4:从 DNS 移除 NGINX,保留 IngressClass,然后卸载

步骤 0:迁移全局 ConfigMap 设置

安装 Traefik 前,检查当前 ingress-nginx ConfigMap 中设置的全局默认值。 在 ingress-nginx 中,控制器 ConfigMap 是集群级配置层。 在 Traefik 中,相同行为分布在以下位置:

  • providers.kubernetesIngressNGINX 静态配置,提供 ingress-nginx 兼容性默认值
  • 入口点,控制 HTTP 到 HTTPS 重定向、PROXY 协议等监听器行为
  • 动态 tls.options 和 HTTP 中间件,控制 TLS 策略、HSTS 及其他 HTTP 头行为
  • Traefik 访问日志配置,记录请求日志

先导出现有 ConfigMap,并检查自定义过的键:

kubectl get configmap --all-namespaces -l app.kubernetes.io/name=ingress-nginx,app.kubernetes.io/component=controller -o yaml

无论安装 ingress-nginx 时使用什么命名空间或发布名称,该标签选择器都可以定位控制器 ConfigMap。

复制数值前先转换 NGINX 单位

部分 ingress-nginx ConfigMap 键使用 16k、1m 或 30s 等 NGINX 格式的值。 Traefik 中对应的 providers.kubernetesIngressNGINX 选项要求:

  • 消息体大小和缓冲设置使用原始字节数
  • proxyConnectTimeout 和 proxyNextUpstreamTimeout 使用整数秒
  • proxyRequestBuffering 和 proxyBuffering 使用布尔值

ConfigMap 到 Traefik 的映射

ingress-nginx ConfigMap 键 Traefik 对应项
(提供者选项)
说明
proxy-connect-timeout proxyConnectTimeout 使用整数秒。
proxy-request-buffering proxyRequestBuffering 将 on / off 转换为 true / false。ingress-nginx 默认启用请求缓冲,Traefik 则默认为 false。
client-body-buffer-size clientBodyBufferSize 将 16k 等值转换为字节。
proxy-buffering proxyBuffering 将 on / off 转换为 true / false。
proxy-body-size proxyBodySize 将 1m 等值转换为字节。
proxy-buffer-size proxyBufferSize 将 8k 等值转换为字节。
proxy-buffers-number proxyBuffersNumber 保留整数值。
proxy-next-upstream proxyNextUpstream 使用空格分隔的重试条件列表,例如 error timeout http_502。
proxy-next-upstream-timeout proxyNextUpstreamTimeout 使用整数秒。
proxy-next-upstream-tries proxyNextUpstreamTries 保留整数值。
custom-http-errors customHTTPErrors 如需全局错误页面服务,还应配置 providers.kubernetesIngressNGINX.defaultBackendService。
global-allowed-response-headers globalAllowedResponseHeaders nginx.ingress.kubernetes.io/custom-headers 注解生效所必需。
allow-cross-namespace-resources allowCrossNamespaceResources 迁移后的 Ingress 需要引用其他命名空间中受支持的资源时使用。
strict-validate-path-type strictValidatePathType Traefik v3.7 中此选项默认为 true。
ssl-redirect / force-ssl-redirect nginx.ingress.kubernetes.io/ssl-redirect 和 nginx.ingress.kubernetes.io/force-ssl-redirect 注解,或集群级入口点重定向 存在注解时,Traefik 会转换它们。如需全局默认值,在 web 入口点上配置 HTTP 到 HTTPS 重定向;如果需要显式选择入口点,则设置 providers.kubernetesIngressNGINX.httpEntryPoint / httpsEntryPoint。
ssl-protocols / ssl-ciphers TLS 选项 通过入口点 TLS 选项全局应用,或通过 traefik.ingress.kubernetes.io/router.tls.options 按 Ingress 应用。
hsts, hsts-max-age, hsts-include-subdomains, hsts-preload Headers 中间件 使用 stsSeconds、stsIncludeSubdomains、stsPreload 和 forceSTSHeader。将中间件附加到入口点,即可作为集群级默认值。
use-proxy-protocol 入口点 proxyProtocol 配置 在位于 PROXY 协议负载均衡器之后的每个入口点上配置。
access-log-path accessLog.filePath 静态配置。
log-format-upstream accessLog.format 使用 Traefik 内置的 common、genericCLF 或 json 格式。自定义 NGINX 日志格式字符串没有一一对应项。

没有直接对应项的 ConfigMap 键

部分 ingress-nginx ConfigMap 键专属于 NGINX,在迁移时可以移除,因为 Traefik 不暴露原始 NGINX 内部配置。 常见例子包括:

  • worker-processes、worker-cpu-affinity 和 Lua 共享字典设置等工作进程调优项
  • main-snippet、http-snippet、server-snippet、location-snippet 和 stream-snippet 等片段类键
  • 超出 Traefik 内置访问日志格式的自定义 NGINX 日志模板

遇到这类键时,应转换它们想达到的目的,而不是逐字复制指令。

参考页面


步骤 1:在 NGINX 旁安装 Traefik

安装 Ingress NGINX Controller

如果尚未安装 Ingress NGINX Controller,可以按以下步骤全新安装:

安装 Ingress NGINX Controller

helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx --create-namespace

启用 Kubernetes Ingress NGINX 提供者并安装 Traefik。两个控制器将同时为相同的 Ingress 资源提供服务。

先阅读状态竞态说明

两个控制器共同管理相同 Ingress 时,会争用 status.loadBalancer.ingress[] 字段。安装前,先阅读步骤 3 中的 Ingress 状态竞态,决定采用哪种缓解方式:关闭 Traefik 的 publishService,或使用过渡 IngressClass。

添加 Traefik Helm 仓库

helm repo add traefik https://traefik.github.io/charts
helm repo update

安装 Traefik

helm upgrade --install traefik traefik/traefik \
  --namespace traefik --create-namespace \
  --set providers.kubernetesIngressNGINX.enabled=true

也可以通过 values 文件进行更多配置:

...
providers:
  kubernetesIngressNGINX:
    enabled: true
 ...
helm upgrade --install traefik traefik/traefik \
  --namespace traefik --create-namespace \
  --values traefik-values.yaml

确认两个控制器均在运行

# Check NGINX pods
kubectl get pods -n ingress-nginx

# Check Traefik pods
kubectl get pods -n traefik

# Check both services have LoadBalancer IPs
kubectl get svc -n ingress-nginx ingress-nginx-controller
kubectl get svc -n traefik traefik

此时 NGINX 和 Traefik 都已运行,能够为相同 Ingress 资源提供服务。但由于 DNS 仍指向 NGINX LoadBalancer,流量仍只经过 NGINX。


步骤 2:验证 Traefik 正确处理流量

将 Traefik 加入 DNS 前,先确认它能够正确服务现有 Ingress 资源。

通过 Traefik 的 LoadBalancer IP 测试

获取 Traefik 的 LoadBalancer IP,并使用 --resolve 测试,无需修改 DNS:

# Get LoadBalancer IPs
NGINX_IP=$(kubectl get svc -n ingress-nginx ingress-nginx-controller -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}')
TRAEFIK_IP=$(kubectl get svc -n traefik traefik -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}')
echo -e "Nginx IP: $NGINX_IP\nTraefik IP: $TRAEFIK_IP"

# Test HTTP for both
FQDN=myapp.example.com
# Observe HTTPS redirections:
curl --connect-to "${FQDN}:80:${NGINX_IP}:80" "http://${FQDN}" -D -
curl --connect-to "${FQDN}:80:${TRAEFIK_IP}:80" "http://${FQDN}" -D - # note X-Forwarded-Server which should be traefik

# Test HTTPS
curl --connect-to "${FQDN}:443:${NGINX_IP}:443" "https://${FQDN}"
curl --connect-to "${FQDN}:443:${TRAEFIK_IP}:443" "https://${FQDN}"

迁移期间的 TLS 证书

NGINX 和 Traefik 都必须提供有效 TLS 证书,HTTPS 测试才能通过。由于在这个验证阶段 Traefik 尚未公开暴露,Let's Encrypt HTTP 挑战无法工作。

迁移期间可以采用以下 TLS 证书方案:

  • 通过 tls.secretName 使用现有证书:如果使用 cert-manager 或其他外部工具,spec.tls 引用的现有 TLS Secret 可同时供两个控制器使用。
  • Let's Encrypt DNS 挑战:配置 Traefik 的 ACME DNS 挑战,无需公开暴露服务即可获取证书。

避免使用 curl -k(跳过证书验证),因为它会掩盖 TLS 配置问题,导致迁移后才暴露故障。

确认 Ingress 发现

检查 Traefik 日志,确认已发现现有 Ingress 资源:

kubectl logs -n traefik deployment/traefik | grep -i "ingress"

步骤 3:将流量切换到 Traefik

确认两个控制器均在运行且验证通过后,逐步将流量从 NGINX 切换到 Traefik。

方案 A:基于 DNS 的迁移

将 Traefik LoadBalancer IP 与 NGINX 地址一起加入 DNS 记录,让两个控制器都可以接收流量。

获取 LoadBalancer 地址:

# NGINX LoadBalancer
echo $(kubectl get svc -n ingress-nginx ingress-nginx-controller -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}')

# Traefik LoadBalancer
echo $(kubectl get svc -n traefik traefik -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}')

逐步迁移 DNS:

  1. 将 Traefik 加入 DNS:把 Traefik LoadBalancer IP 加入 DNS 记录,此时两个 IP 通过轮询接收流量。
  2. 监控:观察两个控制器上的流量模式。
  3. 从 DNS 移除 NGINX:确认无误后,移除 NGINX LoadBalancer IP。
  4. 等待 DNS 传播:留出时间让 DNS 缓存过期。
  5. 卸载 NGINX:进入步骤 4。

DNS TTL 可能不被遵守

有些 ISP 为降低流量成本会忽略 DNS TTL,让缓存记录保留得更久。从 DNS 移除 NGINX 后,至少继续运行 NGINX 24–48 小时再卸载,避免仍使用过期 DNS 缓存的用户流量中断。

并行运行期间的 Ingress 状态竞态

当两个控制器管理相同 Ingress 资源(相同的 ingressClassName: nginx)时,它们都会尝试把 LoadBalancer 地址写入各自管理的每个 Ingress 的 status.loadBalancer.ingress[]。两边在密集协调循环中不断相互覆盖,日志却不报错,只在两侧反复出现 Updated ingress status 信息。

路由本身不受影响,两个控制器在并行期间都能正确处理流量。但持续变化的状态字段会影响所有监听者:

  • ExternalDNS 可能在两个 LoadBalancer IP 之间反复切换 DNS 记录。
  • 观察 Ingress 状态的 kube-state-metrics、监控仪表盘和告警规则。
  • ArgoCD 或 Flux 等 GitOps 工具会为每个受影响的 Ingress 持续报告配置漂移。
  • 根据 Ingress 状态字段执行协调的自定义 Operator。

推荐缓解方式(方案 1):并行期间关闭 Traefik 状态发布

  1. 安装 Traefik 时关闭 publishService:

    # traefik-values.yaml
    providers:
      kubernetesIngressNginx:
        enabled: true
        publishService:
          enabled: false  # Disable to prevent status updates

    Traefik 继续正常服务 Ingress,只是不再写状态字段,由 NGINX 成为唯一写入者。

  2. 测试 Traefik,使用端口转发或独立测试主机名。

  3. 通过 NGINX 切换 DNS(仅适用于 ExternalDNS 用户)。配置 NGINX 发布 Traefik 服务地址,让 ExternalDNS 将流量指向 Traefik:

    # nginx-values.yaml
    controller:
      publishService:
        pathOverride: "traefik/traefik"  # Points to Traefik's service
  4. 确认流量经过 Traefik。此时仍可通过移除 pathOverride 回滚。

  5. 启用 Traefik 的 publishService,并卸载 NGINX。

替代缓解方式(方案 2):使用过渡 IngressClass

为正在迁移的 NGINX 设置独立 IngressClass,例如 nginx-migration,让两个控制器永远不同时拥有同一 Ingress。这也是 SUSE 为 RKE2 迁移记录的方法,参见 SUSE:从 Ingress NGINX 迁移到 Traefik。它能完全避免争用 status.loadBalancer.ingress[],代价是需要一次短暂的流量切换步骤,而不是逐步调整 DNS。

方案 B:使用外部负载均衡器分配加权流量

如需更精确地控制流量分配,可以在两个 Kubernetes LoadBalancer 前放置外部负载均衡器,例如 Traefik、Cloudflare、AWS ALB 或专用负载均衡器。

基础设施前置条件

本方案假设基础设施中已经有外部负载均衡器,或愿意在迁移开始前搭建。添加外部负载均衡器属于重要基础设施变更,应与入口控制器迁移分开规划和测试。

配置步骤:

  1. 创建指向 NGINX Kubernetes LoadBalancer 的外部负载均衡器。
  2. 更新 DNS,使其指向外部负载均衡器。
  3. 将 Traefik Kubernetes LoadBalancer 以较低权重(例如 10%)加入外部负载均衡器。
  4. 逐渐增加 Traefik 权重,同时降低 NGINX 权重。
  5. NGINX 不再接收流量后,将其卸载。

权重调整示例:

阶段 NGINX 权重 Traefik 权重 持续时间
初始 100% 0% -
开始 90% 10% 1 小时
增加 50% 50% 2 小时
接近完成 10% 90% 4 小时
最终 0% 100% -

外部负载均衡器选项

  • Cloudflare Load Balancing:带健康检查的流量调度。
  • AWS Global Accelerator:在端点之间进行加权路由。
  • Google Cloud Load Balancing:流量分配。
  • Traefik / HAProxy / NGINX(外部部署):支持加权后端的自托管方案。
  • ……

保留 LoadBalancer IP

如果希望 Traefik 最终使用与 NGINX 相同的 LoadBalancer IP,以简化 DNS 管理,可以在迁移后转移 IP。由于 Traefik 已经使用自己的 LoadBalancer 运行,这一过程可以实现零停机。

零停机 IP 转移流程:

  1. Traefik 已使用自己的 LoadBalancer IP 运行(来自步骤 1)。
  2. 将 Traefik LoadBalancer IP 加入 DNS,此时流量同时到达 NGINX 和 Traefik。
  3. 从 DNS 移除 NGINX IP,等待传播。
  4. 删除 NGINX LoadBalancer 服务以释放 IP。
  5. 升级 Traefik,申请已释放的 IP。
  6. 新 IP 生效后,可选地从 DNS 移除 Traefik 的旧 IP。

这样在 IP 转移期间,流量始终能够到达 Traefik。

获取当前 NGINX LoadBalancer IP:

kubectl get svc -n ingress-nginx ingress-nginx-controller -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}'
AWS(使用弹性 IP 的 Network Load Balancer)

AWS 不支持为 Classic Load Balancer 使用静态 IP,应改用带弹性 IP 的 Network Load Balancer(NLB)。这要求集群中已安装 AWS Load Balancer Controller。

预先分配弹性 IP,每个可用区一个:

aws ec2 allocate-address --domain vpc --region <your-region>
# Note the AllocationId (eipalloc-xxx) for each EIP

更新 traefik-values.yaml:

service:
  type: LoadBalancer
  loadBalancerClass: service.k8s.aws/nlb  # Requires AWS Load Balancer Controller
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "external"
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
    service.beta.kubernetes.io/aws-load-balancer-eip-allocations: "eipalloc-xxx,eipalloc-yyy"

更多详情请参阅 AWS Load Balancer Controller 注解文档。

Azure

Azure 支持为 Load Balancer 使用静态公网 IP。

确定现有公网 IP:

az network public-ip list --resource-group <your-resource-group> \
  --query "[?ipAddress=='<your-ip>'].name" -o tsv

更新 traefik-values.yaml:

service:
  type: LoadBalancer
  annotations:
    # Only needed if the public IP is in a different resource group than the AKS cluster
    service.beta.kubernetes.io/azure-load-balancer-resource-group: "<public-ip-resource-group>"
  spec:
    loadBalancerIP: "<your-existing-ip>"

更多详情请参阅 Azure AKS 静态 IP 文档。

GCP

GCP 通过保留区域 IP 地址支持静态 IP。

保留或确定现有 IP:

# List existing static IPs
gcloud compute addresses list

# Or reserve a new regional static IP (must be in the same region as your GKE cluster)
gcloud compute addresses create traefik-ip --region <your-cluster-region>

更新 traefik-values.yaml:

service:
  type: LoadBalancer
  spec:
    loadBalancerIP: "<your-static-ip>"

更多详情请参阅 GKE LoadBalancer Service 参数文档。

OVHcloud

OVHcloud Public Load Balancer 支持静态 IP;它基于 Openstack Octavia,为 LoadBalancer 服务分配浮动 IP。这要求集群安装 Openstack Cloud Controller Manager。如果使用 OVHcloud Managed Kubernetes Service(MKS),Openstack Cloud Controller Manager 已由平台安装和管理。

从 NGINX 迁移到 Traefik 时,如需保留现有浮动 IP:

确定现有公网 IP:

NGINX_IP=$(kubectl get svc -n ingress-nginx ingress-nginx-controller \
  -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}')

echo "NGINX IP: $NGINX_IP"

编辑现有 NGINX LoadBalancer 服务,确保删除负载均衡服务时不释放浮动 IP:

kubectl annotate svc my-lb-svc loadbalancer.openstack.org/keep-floatingip=true

keep-floatingip 注解可防止删除或修改服务时释放浮动 IP。

删除 NGINX LoadBalancer 服务,释放浮动 IP 的服务绑定

更新 traefik-values.yaml:

service:
  type: LoadBalancer
  spec:
    loadBalancerIP: "<your-existing-floating-ip>"

更多信息请参阅 OVHcloud MKS Public Load Balancer 注解文档。

其他云提供商
  • DigitalOcean: 支持通过浮动 IP 设置 loadBalancerIP。
  • Linode: 支持指定 loadBalancerIP。
  • 裸机(MetalLB): 使用 IP 地址池。

转移 IP:

DNS 已指向 Traefik,且 values 已配置目标 IP 后:

# Ensure Traefik is already receiving traffic via its current LoadBalancer
kubectl get svc -n traefik traefik

# Delete NGINX LoadBalancer service to release the IP
kubectl delete svc -n ingress-nginx ingress-nginx-controller

# Upgrade Traefik to claim the released IP
helm upgrade traefik traefik/traefik \
  --namespace traefik \
  --values traefik-values.yaml

# Verify Traefik now has the old NGINX IP
kubectl get svc -n traefik traefik

Helm 升级期间零停机

Helm 升级只重启 Traefik Pod,不重启 LoadBalancer 服务。Traefik 默认采用 RollingUpdate 部署策略,因此新 Pod 会先启动,旧 Pod 再终止。如需进一步保障,可配置高可用:

# In traefik-values.yaml
deployment:
  replicas: 2

# Spread pods across nodes to survive node failures
affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchLabels:
            app.kubernetes.io/name: traefik
            app.kubernetes.io/instance: traefik
        topologyKey: kubernetes.io/hostname

# Ensure at least one pod is always available during disruptions
podDisruptionBudget:
  enabled: true
  minAvailable: 1

多副本分布在不同节点,并配合 PodDisruptionBudget 后,升级和节点维护期间始终至少有一个 Pod 运行。


步骤 4:卸载 Ingress NGINX Controller

NGINX 不再接收流量后,将其从集群移除。卸载前,必须确保保留 nginx IngressClass,Traefik 需要它继续发现现有 Ingress。

保留 IngressClass

通过 Helm 安装 NGINX 的情况

添加 helm.sh/resource-policy: keep 注解,通知 Helm 保留 IngressClass:

# Add the required annotation
helm upgrade ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx \
  --reuse-values \
  --set-json 'controller.ingressClassResource.annotations={"helm.sh/resource-policy": "keep"}'
# Check that the annotation is really here
kubectl describe ingressclass nginx

--reuse-values 参数至关重要,它会保留全部现有 NGINX 配置。不使用此参数,Helm 会将所有配置重置为默认值,可能破坏现有部署。

kubectl annotate/patch/edit 不起作用

通过 kubectl annotate、kubectl patch 或 kubectl edit 添加注解,并不能让 Helm 保留 IngressClass。Helm 内部存储发布状态,检查的是内部清单中的注解,而不是集群实时状态。只有 helm upgrade 会更新 Helm 内部状态。

通过 GitOps(ArgoCD、Flux)安装 NGINX 的情况

确保 nginx IngressClass 在 Git 仓库中定义为独立资源,与 NGINX Helm 发布分离:

# ingressclass.yaml
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
spec:
  controller: k8s.io/ingress-nginx
手动安装 NGINX 的情况

将 IngressClass 创建为独立资源:

kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
spec:
  controller: k8s.io/ingress-nginx
EOF

删除 NGINX 准入 Webhook

应删除准入 Webhook,避免 NGINX 移除后修改 Ingress 时出现问题:

kubectl delete validatingwebhookconfiguration ingress-nginx-admission
kubectl delete mutatingwebhookconfiguration ingress-nginx-admission --ignore-not-found

卸载 NGINX

helm uninstall ingress-nginx -n ingress-nginx

如果已添加 helm.sh/resource-policy: keep 注解,应看到:

These resources were kept due to the resource policy:
[IngressClass] nginx

release "ingress-nginx" uninstalled

确认 IngressClass 存在

kubectl get ingressclass nginx

如果 IngressClass 意外被删除,可以使用保留 IngressClass一节中的命令重新创建。

清理 NGINX 命名空间

kubectl delete namespace ingress-nginx

迁移完成

恭喜,你已经以零停机方式从 Ingress NGINX Controller 迁移到 Traefik。现有 ingressClassName: nginx 的 Ingress 继续工作,现在由 Traefik 提供服务。


故障排查

Traefik 提供仪表盘,可帮助了解运行情况。 参阅专门文档启用仪表盘。

Traefik 未发现 Ingress
# Verify IngressClass exists
kubectl get ingressclass nginx

# Check Traefik provider configuration
kubectl logs -n traefik deployment/traefik | grep -i "nginx\|ingress"

# Verify Ingress has correct ingressClassName
kubectl get ingress <name> -o yaml | grep ingressClassName
注解未按预期工作

一些 NGINX 注解在 Traefik 中存在行为差异,详见限制文档。

TLS 证书无法工作

现有 TLS 配置可以继续用于 Traefik:

  • spec.tls 条目原样保留;Traefik 使用引用的 Secret 终止 TLS。
  • TLS Secret 必须保留在与 Ingress 相同的命名空间中。
  • NGINX 的 ssl-redirect / force-ssl-redirect 注解仍会被遵守。
    # Verify TLS secret exists in the same namespace as Ingress
kubectl get secrets -n <namespace>

    # Check secret format
kubectl get secret <tls-secret-name> -n <namespace> -o yaml
未分配 LoadBalancer IP
  # Check service status
  kubectl describe svc -n traefik traefik

  # Check for events
  kubectl get events -n traefik --sort-by='.lastTimestamp'

后续步骤

进一步了解 Traefik:

增强部署:


反馈与支持

如果迁移中遇到问题,或对本指南有改进建议:

欢迎为本迁移指南贡献改进。开始前请阅读贡献指南。


版权所有 © 头文件软件工作室

文档由 HeadFile Studio 翻译。

Traefik v3.7 中文快照 · 原文版权归 Traefik Labs 及贡献者所有 · MIT 许可证