使用 Docker Swarm 配置 Traefik 自动发现路由

由于自己的个人站点规模较小,所以没有使用 k8s 管理集群,而是使用了 Docker 自带的 Swarm 容器编排服务。

本文记录了在配置 Docker Swarm 自动发现路由时遇到的一些问题,以及摸索出来的可用实践。

1 部署 Traefik Stack

将 Traefik 服务部署在 manager 节点上,配置文件如下:

version: "3.8"

services:
  traefik:
    image: traefik:2.5
    command:
      - "--api.dashboard=true"
      - "--providers.docker.swarmMode=true"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.docker.network=overnet"
      - "--entrypoints.http.address=:80"
      - "--entrypoints.https.address=:443"
      - "--entrypoints.aria2.address=:1080"
      - "--certificatesresolvers.le.acme.httpchallenge=true"
      - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=http"
      - "--certificatesresolvers.le.acme.email=i.inf@outlook.com"
      - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
      - "--accesslog"
      - "--log"
    ports:
      - 80:80
      - 443:443
    volumes:
      - traefik-certificates:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - overnet
    deploy:
      placement:
        constraints:
          - node.role == manager
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.http2https.rule=HostRegexp(`{any:.+}`)"
        - "traefik.http.routers.http2https.entrypoints=http"
        - "traefik.http.routers.http2https.middlewares=https-redirect"
        - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https"
        - "traefik.http.middlewares.https-redirect.redirectscheme.permanent=true"
        # dashboard 配置
        - "traefik.http.routers.api.rule=Host(`gateway.don.red`)"
        - "traefik.http.routers.api.entrypoints=https"
        - "traefik.http.routers.api.tls.certresolver=le"
        # 获取 dashboard 提供器
        # @ 后面变量表示提供者, 像之前的 hello-world 实际上省略了 @docker
        - "traefik.http.routers.api.service=api@internal"
        # 基本验证中间件
        - "traefik.http.routers.api.middlewares=api-auth"
        # 配置用户名密码,密码使用 openssl passwd -apr1 $PASSWORD 生成
        # 注意将 $ 变为 $$
        - "traefik.http.middlewares.api-auth.basicauth.users=iinfinity:$$apr1$$0D6e5rhj$$7xOqEiRRQ8JdID9FQDR1O0"
        # 最最关键的一步,创建一个 noop 虚服务的 loadbalancer,port 随便选,不然上面的 label 配置不会生效
        - "traefik.http.services.noop.loadbalancer.server.port=9999"

volumes:
  traefik-certificates:

networks:
  overnet:
    external: true

2 部署测试 Stack

标记了 labels 的容器可以被 Traefik 发现并路由。

version: "3.8"

services:
  hello:
    image: tutum/hello-world:latest
    networks:
      - overnet
    deploy:
      mode: replicated
      replicas: 2
      placement:
        constraints:
          - node.role != manager
          - node.labels.database != true
      restart_policy:
        condition: on-failure
        delay: 30s
        max_attempts: 3
        window: 30s
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.hello.rule=Host(`test.don.red`)"
        - "traefik.http.routers.hello.entrypoints=https"
        - "traefik.http.routers.hello.tls.certresolver=le"
        - "traefik.http.services.hello.loadbalancer.server.port=80"

networks:
  overnet:
    external: true

中间件举例

该服务部署于 https://775.ink,是一个简单的短网址服务。
  1. 首先使用 traefik.http.routers.tinyurl-angular.middlewares=tinyurl-redirect 指定中间件
  2. 然后配置中间件 traefik.http.middlewares.tinyurl-redirect.redirectregex.regex=^https://775.ink/(.{12})
labels:
  - "traefik.enable=true"
  - "traefik.http.routers.tinyurl-angular.rule=Host(`775.ink`)"
  - "traefik.http.routers.tinyurl-angular.entrypoints=https"
  - "traefik.http.routers.tinyurl-angular.tls.certresolver=le"
  - "traefik.http.services.tinyurl-angular.loadbalancer.server.port=80"
  - "traefik.http.routers.tinyurl-angular.middlewares=tinyurl-redirect"
  - "traefik.http.middlewares.tinyurl-redirect.redirectregex.regex=^https://775.ink/(.{12})"
  - "traefik.http.middlewares.tinyurl-redirect.redirectregex.replacement=https://api.775.ink/link/$${1}"
IInfinity

IInfinity

大道虽简,知易行难。
CN