使用 Traefik v3 作为 Docker 统一网关并自动配置 SSL

1,383 阅读4分钟

在Docker环境中,我们需要手动管理每个应用暴露的端口,特别是使用 Docker Swarm 集群时应用几十上百个,维护暴露端口变得十分困难,因此我们可以通过 Traefik 作为统一网关,自动服务发现和负载均衡,顺带解决 SSL申请问题

一、安装 Traefik

1. 创建专用网络

在单机 Docker 环境中

docker network create traefik

在 Docker Swarm 集群环境中

docker network create -d overlay traefik

2. 准备DNS服务商的KEY

先拥有一个域名,并配置 dns 例如 *.traefik.example.com 映射到你的服务器 IP。

同时准备服务商相关的 API KEY,其实使用tsl或http轮训也是可以,但稳定性不佳且容易触发免费证书商的频率限制,所以推荐直接配置 API KEY 更好。

本文以 Cloudflare 为例,其他服务商例如阿里云或 DNSPod,请自行查看文档 traefik/https/acme/#providers,找到对应的 Provider Code 和所需的环境变量

3. 启动 Traefik

  1. 创建证书缓存目录例如 /root/apps/traefik/cert,可自行更改任意位置,替换下方的yml即可
  2. 修改
version: '3.8'
services:
  reverse-proxy:
    image: traefik:v3.2
    restart: always
    environment:
      # 自行替换为 Provider Code 所需的环境变量
      - CF_API_EMAIL=seepine@example.com
      - CF_DNS_API_TOKEN=yourDnsApiToken
    command:
      - --api.insecure=true
      - --providers.docker
      - --providers.docker.exposedByDefault=false
      - --providers.docker.network=traefik
      # 若非 docker swarm 这三行可去掉
      - --providers.swarm.endpoint=unix:///var/run/docker.sock
      - --providers.swarm.exposedByDefault=false
      - --providers.swarm.network=traefik
      
      # 暴露端口
      - --entrypoints.web.address=:80          # 暴露http
      - --entrypoints.websecure.address=:443   # 暴露https
      - --entryPoints.tcp.address=:18080       # 暴露tcp
      - --entryPoints.udp.address=:18080/udp   # 暴露udp

      # ssl 相关
      - --certificatesresolvers.myresolver.acme.dnschallenge=true
      - --certificatesresolvers.myresolver.acme.dnsChallenge.provider=cloudflare # 修改为自己的 Provider Code
      - --certificatesresolvers.myresolver.acme.email=admin@example.com
      - --certificatesresolvers.myresolver.acme.storage=/cert/acme.json
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /root/apps/traefik/cert:/cert
    networks:
      - traefik

networks:
  traefik:
    external: true

4. 访问面板

云服务器安全组放行 80/443/8080 端口,此时访问 http://你的公网ip:8080 进入 Traefik 面板说明启动成功。

此面板开放是不安全的,后续调试完记得修改 - --api.insecure=false 和去除所有 8080 端口暴露

二、部署应用

1. 部署客户端

此处以 Traefik 官方示例 whoami 来演示,实际生产中自行替换为自己的应用即可。

version: "3"
services:
  whoami:
    image: traefik/whoami
    # docker_start - 若是单机 docker compose,使用此部分配置
    labels:
      - traefik.enable=true
      - traefik.http.routers.whoami.rule=Host(`whoami.traefik.example.com`) # 域名可自行修改为自己的
      - traefik.http.services.whoami.loadbalancer.server.port=80            # 端口不配也会自动扫描,但建议自行配置为实际的,因此处镜像是whoami,默认端口为80端口
      - traefik.http.routers.whoami.tls.certresolver=myresolver
    # docker_end

    # docker_swarm_start -- 若是 docker swarm 集群,使用此部分配置
    deploy:
      labels:
        - traefik.enable=true
        - traefik.http.routers.whoami.rule=Host(`whoami.traefik.example.com`)
        - traefik.http.services.whoami.loadbalancer.server.port=80
        - traefik.http.routers.whoami.tls.certresolver=myresolver
      mode: replicated
      replicas: 3          # 此处部署3个实例测试负载均衡
    # docker_swarm_end

    networks:
      - traefik

networks:
  traefik:
    external: true

2. 验证

查看 Traefik 面板可以看到应用

router.png

访问域名可以访问到信息

whoami.png

3. 注意A:每个应用的名称需要不同

即下方标签中的 <your_app_name> 需要全局唯一,实际中自行决断即可。

      - traefik.http.routers.<your_app_name>.rule=Host(`whoami.traefik.example.com`) # 域名可自行修改为自己的
      - traefik.http.services.<your_app_name>.loadbalancer.server.port=80            # 端口可自行修改为实际的,此处镜像是whoami,端口为80端口
      - traefik.http.routers.<your_app_name>.tls.certresolver=myresolver

4. 注意B:多个端口暴露

version: "3"
services:
  whoami:
    image: traefik/whoami
    labels:
      - traefik.enable=true
      - traefik.http.routers.whoami.rule=Host(`whoami.traefik.example.com`)
      - traefik.http.services.whoami.loadbalancer.server.port=8080
      - traefik.http.routers.whoami.tls.certresolver=myresolver
      # app_name 和域名端口改为不同即可
      - traefik.http.routers.whoami_b.rule=Host(`whoami_b.traefik.example.com`)
      - traefik.http.services.whoami_b.loadbalancer.server.port=8090
      - traefik.http.routers.whoami_b.tls.certresolver=myresolver

三、进阶

1. 通配符

生产环境建议使用通配符证书解决 SSL 问题,可以有效避免域名过多 Let's Encrypt 证书申请速率被限制。

version: "3"
services:
  whoami:
    image: traefik/whoami
    labels:
      - traefik.enable=true
      - traefik.http.routers.whoami.rule=Host(`whoami.traefik.example.com`)
      - traefik.http.services.whoami.loadbalancer.server.port=80
      - traefik.http.routers.whoami.tls.certresolver=myresolver
      - traefik.http.routers.whoami.tls.domains[0].main=*.traefik.example.com # 添加此行即可

2. 速率限制

可查看文档 traefik/middlewares/http/ratelimit

当超出限制会返回 429 Too Many Requests

version: "3"
services:
  whoami:
    image: traefik/whoami
    # docker_start - 若是单机 docker compose,使用此部分配置
    labels:
      - traefik.enable=true
      # 定义名为 whoami-route 的路由
      - traefik.http.routers.whoami-route.rule=Host(`whoami.traefik.example.com`)
      # ...
      
      # step.1 定义名为 whoami-mw 的中间件
      - traefik.http.middlewares.whoami-mw.ratelimit.average=100       # 表示每秒钟平均处理100个请求
      - traefik.http.middlewares.whoami-mw.ratelimit.burst=150         # 表示每秒钟突发处理150个请求
      - traefik.http.middlewares.whoami-mw.ratelimit.period=10s        # 表示基准单位10秒,也可改为1m即一分钟等等,不填默认1秒
      
      # step.2 将 whoami-mw 中间价应用到 whoami-route 路由上
      - traefik.http.routers.whoami-route.middlewares=whoami-mw

3. 请求体限制

可查看文档 traefik/middlewares/http/buffering

version: "3"
services:
  whoami:
    image: traefik/whoami
    # docker_start - 若是单机 docker compose,使用此部分配置
    labels:
      - traefik.enable=true
      # 定义名为 whoami-route 的路由
      - traefik.http.routers.whoami-route.rule=Host(`whoami.traefik.example.com`)
      # ...
      
      # step.1 定义名为 whoami-bf-mw 的中间件
      - traefik.http.middlewares.whoami-bf-mw.buffering.maxRequestBodyBytes=2000000 # 设置最大请求体2MB 即 2*1024*1024
      - traefik.http.middlewares.whoami-bf-mw.buffering.memRequestBodyBytes=1048576 # 设置内存中缓存的请求体1M,多余的请求体会使用磁盘缓存,避免traefik占据过多内存

      # step.2 将 whoami-bf-mw 中间价应用到 whoami-route 路由上
      - traefik.http.routers.whoami-route.middlewares=whoami-bf-mw    # 若有多个插件可用逗号隔开,例如 =whoami-mw,whoami-bf-mw

4. 重定向https

可查看文档 traefik/middlewares/http/redirectscheme

version: "3"
services:
  whoami:
    image: traefik/whoami
    # docker_start - 若是单机 docker compose,使用此部分配置
    labels:
      - traefik.enable=true
      # 定义名为 whoami-route 的路由
      - traefik.http.routers.whoami-route.rule=Host(`whoami.traefik.example.com`)
      # ...
      
      # step.1 定义名为 whoami-rd-mw 的中间件
      - traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https
      - traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true
      - traefik.http.middlewares.test-redirectscheme.redirectscheme.port=443        # 默认443,若你的ssl非443端口,此配置很有用

      # step.2 将 whoami-rd-mw 中间价应用到 whoami-route 路由上
      - traefik.http.routers.whoami-route.middlewares=whoami-rd-mw

5. UDP路由

version: "3"
services:
  whoami:
    image: traefik/whoami
    # docker_start - 若是单机 docker compose,使用此部分配置
    labels:
      - traefik.enable=true
        
      - traefik.udp.routers.derper-udp.entrypoints=udp
      - traefik.udp.routers.derper-udp.service=derper-udp
      - traefik.udp.services.derper-udp.loadbalancer.server.port=3478  # 指向容器内udp端

博客内容遵循:署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议

本文永久链接是:seepine.com/docker/trae…