Traefik 实战:用自动服务发现托管 Docker 与 K8s 流量

在容器与 Kubernetes 时代,Traefik 作为云原生反向代理与边缘路由器,最大的卖点就是自动服务发现:你不再手写几十行 upstream 配置,只要给容器或 Pod 打标签,路由就自动生成。相比传统 Nginx 需要手动维护 conf、Caddy 偏向简单站点,Traefik 把”配置即代码”做到了极致,特别适合频繁扩缩容的微服务场景。本文从零跑通 Docker 模式,再延伸到 K8s IngressRoute 与生产检查清单。

一、为什么选 Traefik:与传统网关的对比

反向代理不是新东西,Nginx、Caddy、Kong 都能做,但 Traefik 的差异化在于”动态”二字。下面这张表帮你快速判断它是否适合你的场景。

维度TraefikNginxCaddy
服务发现原生(Docker/K8s/Consul)需手动/模板有限
配置方式标签/CRD 声明式静态 confCaddyfile
HTTPS 自动化内置 ACME需 certbot内置
Dashboard开箱即用第三方无
适用规模动态微服务通用高性能轻量站点

如果你已经在用 Nginx 反向代理 做负载均衡,可以把 Traefik 放在内网服务网格边缘,两者并不冲突。关于 Caddy 的玩法可参考 Caddy 实战。

选型上有一个经验法则:静态站点、需要极致性能调优的七层规则,Nginx 仍是王者;想用一行 Caddyfile 起一个带 HTTPS 的小站,Caddy 最省事;而当后端是十几个会随时扩缩容的容器服务、你不想每次发版都去改网关配置,Traefik 的服务发现优势就彻底释放了。很多团队最终是”Traefik 做南北向动态入口 + Nginx 做入口前的 WAF/限频前置”,各取所长。

二、Docker 模式快速上手

最经典的入门方式是用 docker-compose 同时拉起 Traefik 和一个 whoami 测试服务。注意 Traefik 必须挂载宿主机的 docker.sock 才能监听容器事件。

version: "3.8"
services:
  traefik:
    image: traefik:v3.1
    command:
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
  whoami:
    image: traefik/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.example.com`)"
      - "traefik.http.services.whoami.loadbalancer.server.port=80"

关键点是 traefik.enable=true 与路由规则。因为我们在启动参数里设了 exposedbydefault=false,只有显式打标签的容器才会被暴露,避免误把内部服务对外网开放。更多 Docker 网络基础见 Docker 网络模式详解。

三、核心概念:EntryPoints / Routers / Services / Middlewares

理解 Traefik 只需记住四个对象:EntryPoints 是监听端口(如 :80/:443);Routers 用规则把请求匹配到服务;Services 是后端真实实例池;Middlewares 是在路由前后加工请求(重定向、限流、鉴权等)。它们通过标签或 YAML 动态绑定。

# 静态配置 traefik.yml(启动期固定)
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
api:
  dashboard: true
providers:
  docker:
    exposedBydefault: false

上面是”静态配置”,在容器启动前就定好;而路由、服务、中间件这些”动态配置”则跟着业务服务走。在 Docker 模式下,你通常不用单独写 YAML,直接给容器打标签即可声明完整的路由链:

labels:
  - "traefik.http.routers.api.rule=Host(`api.example.com`)"
  - "traefik.http.routers.api.service=api-svc"
  - "traefik.http.services.api-svc.loadbalancer.server.port=8080"
  - "traefik.http.routers.api.middlewares=auth-chain"

这里显式把 Router 指向名为 api-svc 的 Service,并挂了一条中间件链 auth-chain。当你用 docker compose up 扩容副本时,Traefik 会自动把新容器加进负载均衡池,缩容则自动摘除——这就是”服务发现”带来的零改配置体验。

四、中间件实战:重定向、压缩与限流

中间件是 Traefik 最好用的能力。下面给 whoami 加三条链:HTTP 强制跳 HTTPS、开启 gzip、并对单个客户端限流。

labels:
  - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https"
  - "traefik.http.middlewares.gzip.compress=true"
  - "traefik.http.middlewares.ratelimit.ratelimit.average=100"
  - "traefik.http.middlewares.ratelimit.ratelimit.burst=50"
  - "traefik.http.routers.whoami.middlewares=https-redirect,gzip,ratelimit"

限流参数 average 是每秒平均请求数,burst 是允许的突发量。这与 Nginx 的漏桶算法思路一致,但声明式写法更直观,也更容易随服务伸缩动态调整。

中间件远不止限流。生产环境强烈建议统一加安全响应头,避免每个服务自己配;涉及内部后台还可以接 forwardauth 做集中鉴权,把鉴权逻辑从业务代码里抽出来。

labels:
  - "traefik.http.middlewares.sec-headers.headers.customresponseheaders.X-Content-Type-Options=nosniff"
  - "traefik.http.middlewares.sec-headers.headers.stsSeconds=31536000"
  - "traefik.http.middlewares.gate.forwardauth.address=http://auth-svc:9000/verify"
  - "traefik.http.middlewares.gate.forwardauth.trustforwardheader=true"

五、HTTPS 自动化:Let’s Encrypt + ACME

Traefik 内置 ACME 客户端,能自动申请并续期证书。生产环境务必用 DNS 挑战(如阿里云 DNS)避免 80 端口被墙。下面配置一个 certresolver。

certificatesResolvers:
  letsencrypt:
    acme:
      email: admin@example.com
      storage: /letsencrypt/acme.json
      dnsChallenge:
        provider: alidns
# 在 whoami 上启用
labels:
  - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
  - "traefik.http.routers.whoami.entrypoints=websecure"

acme.json 必须权限 600,否则 Traefik 会拒绝启动。证书自动续期无需人工干预,比手动对接 Nginx 反向代理 的 certbot 省心得多。

如果一台网关要托管多个域名,可以开 certificatesresolvers.letsencrypt.acme.certificatesixtype=SNI 并按域名分别挂 tls.certresolver;通配符证书(*.example.com)必须用 DNS 挑战,HTTP 挑战无法验证泛域名。证书默认 90 天,Traefik 会在到期前 30 天自动续期,期间服务不中断。

六、Kubernetes Ingress 模式

在 K8s 里 Traefik 通过 CRD(IngressRoute)代替原生 Ingress,能力更强。先装 Helm chart,再用下面资源暴露服务。

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: whoami-route
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`whoami.example.com`)
      kind: Rule
      services:
        - name: whoami
          port: 80
  tls:
    certResolver: letsencrypt

IngressRoute 支持多命名空间、加权路由、TCP/UDP 等原生 Ingress 没有的能力。K8s 基础概念可回顾 K8s 入门:Pod、Deployment、Service。

七、可观测性:Dashboard 与 Metrics

Traefik 自带 Dashboard(默认 8080 端口),实时看到所有路由、服务健康与中间件。生产建议把指标接到 Prometheus,配合 Grafana 看 QPS、TLS 握手耗时与 5xx 比例。

# 静态配置开启 metrics
metrics:
  prometheus:
    addEntryPointsLabels: true
    addServicesLabels: true
    entryPoint: web

监控面板搭建思路与 Prometheus + Grafana 监控实战 一致,把 Traefik 的 /metrics 纳管进同一套告警体系即可。

除了指标,访问日志也建议改成 JSON 格式,方便后续进 Loki 或 ES 做字段检索。下面这段开启带客户端 IP 与耗时字段的 accesslog:

accessLog:
  format: json
  fields:
    headers:
      defaultMode: keep
      names:
        User-Agent: keep
        X-Forwarded-For: keep

八、生产落地检查清单

检查项建议
exposedByDefault设为 false,显式开启
ACME 存储acme.json 权限 600 + 持久卷
Dashboard 暴露加 Basic Auth,勿公网裸开
限流按业务 QPS 设 average/burst
健康检查开启 /ping 并接活探针
日志开 accesslog + JSON 格式

九、常见问题排查

9.1 路由 404 但服务在跑

九成是 exposedbydefault=false 却漏了 traefik.enable=true,或 Host 规则域名与访问域名不一致。打开 Dashboard 的 Routers 页对照最直观。

9.2 证书申请一直 pending

多为 DNS 挑战 API 密钥缺失或 80 端口被防火墙拦。改用 DNS 挑战并确认对应云厂商环境变量已注入容器。

9.3 健康检查一直 502

容器起来了但 Traefik 探活失败,通常是 loadbalancer.server.port 写成了容器映射端口而非容器内监听端口,或 readiness 探针比 Traefik 注册更早。用 docker logs 看 Traefik 是否真的监听到该端口。

9.4 文件描述符耗尽

高并发下偶发 too many open files,需要在宿主机把 Traefik 容器的 ulimit 调高,并在 docker run 里加 --ulimit nofile=65536:65536,否则连接会被悄悄丢弃。

十、灰度发布与权重路由

Traefik 原生支持按权重把流量切到不同服务版本,无需额外网关即可做金丝雀发布。下面把 90% 流量给稳定版、10% 给金丝雀版:

labels:
  - "traefik.http.services.app-svc.weighted.services[0].name=app-v1"
  - "traefik.http.services.app-svc.weighted.services[0].weight=90"
  - "traefik.http.services.app-svc.weighted.services[1].name=app-v2"
  - "traefik.http.services.app-svc.weighted.services[1].weight=10"

配合健康探针与监控,你可以先放 10% 观察错误率,再逐步调高权重到 100%,全程无需停服。这和 Kubernetes 自身的滚动更新互补:K8s 管 Pod 生命周期,Traefik 管南北向流量切分。

十一、结语

Traefik 把”反向代理 + 服务发现 + HTTPS 自动化”收进一套声明式体系,是容器化与 K8s 场景下的首选边缘路由。它不等于取代 Nginx——更常见的架构是 Traefik 做南北向动态路由、Nginx 做七层精细管控。把本文的 Docker 示例跑通,你就拥有了可随服务伸缩自动更新的流量入口。

上一篇 Kafka 再平衡风暴排查:消费组卡顿的根因与解决
下一篇 Astro 实战:内容优先架构打造极速 SEO 站点
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]