Skip to content

在 Docker Swarm 中部署 Traefik 代理

Swarm

本指南提供了使用 docker stack deploy 将 Traefik 代理作为 Swarm 服务 安装和配置的详尽步骤。它遵循与单机 Docker 教程相同的结构,并涵盖:

  • 启用 Swarm Provider
  • 暴露 web(HTTP :80)和 websecure(HTTPS :443)入口点
  • 将所有 HTTP 流量重定向到 HTTPS
  • 使用 Basic 认证保护 Traefik 仪表盘
  • *.swarm.localhost 终止自签名证书的 TLS
  • 部署 whoami 演示服务
  • 启用访问日志和 Prometheus 指标

前置条件

  • 已初始化 Swarm 模式的 Docker Engine(docker swarm init
  • Docker Compose
  • openssl
  • htpasswd

创建自签名证书

在 Traefik 可以在本地提供 HTTPS 之前,它需要一张证书。在生产环境中,你应该使用来自可信 CA 的证书,但对于多节点开发 swarm 来说,一张快速的自签名证书就足够了:

bash
mkdir -p certs
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout certs/local.key -out certs/local.crt \
  -subj "/CN=*.swarm.localhost"

创建 Traefik 仪表盘凭证

生成一个哈希后的用户名/密码对,Traefik 的中间件将对其进行校验:

bash
htpasswd -nb admin "P@ssw0rd" | sed -e 's/\$/\$\$/g'

复制完整输出(例如 admin:$$apr1$$…)——我们将其粘贴到中间件标签中。

创建 docker-compose-swarm.yaml

注意

Swarm 使用 docker stack deploy。compose 文件可以任意命名;我们将使用 docker-compose-swarm.yaml

首先,创建一个名为 dynamic 的目录,并添加 tls.yaml 用于动态 TLS 配置:

yaml
# dynamic/tls.yaml
tls:
  certificates:
    - certFile: /certs/local.crt
      keyFile:  /certs/local.key

在同一目录中,创建 docker-compose-swarm.yaml

yaml
services:
  traefik:
    image: traefik:v3.7

    networks:
    # 连接到 'traefik_proxy' 覆盖网络,用于跨节点的容器间通信
      - traefik_proxy

    ports:
        # 将 Traefik 入口点暴露到 Swarm
        # Swarm 需要长格式端口语法
      - target: 80 # 容器端口(Traefik web 入口点)
        published: 80 # 节点上暴露的主机端口
        protocol: tcp
        # 'host' 模式直接绑定到任务所在节点的 IP
        # 'ingress' 模式使用 Swarm 的 Routing Mesh(在节点间负载均衡)
        # 根据你的负载均衡策略进行选择。如果使用外部 LB,'host' 通常更简单
        mode: host
      - target: 443 # 容器端口(Traefik websecure 入口点)
        published: 443 # 主机端口
        protocol: tcp
        mode: host

    volumes:
      # 挂载 Docker socket 以供 Swarm Provider 使用
      # 必须从管理节点运行以通过 socket 访问 Swarm API
      - /var/run/docker.sock:/var/run/docker.sock:ro   # Swarm API socket
      - ./certs:/certs:ro
      - ./dynamic:/dynamic:ro

    # 通过命令行参数进行 Traefik 静态配置
    command:
      # HTTP 入口点
      - "--entrypoints.web.address=:80"

      # 配置 HTTP 到 HTTPS 重定向
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--entrypoints.web.http.redirections.entrypoint.permanent=true"

      # HTTPS 入口点
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.websecure.http.tls=true"

      # 附加动态 TLS 文件
      - "--providers.file.filename=/dynamic/tls.yaml"

      # Providers
      # 启用 Docker Swarm Provider(而不是 Docker Provider)
      - "--providers.swarm.endpoint=unix:///var/run/docker.sock"

      # 监听 Swarm 服务变化(需要 socket 访问权限)
      - "--providers.swarm.watch=true"

      # 推荐:默认不暴露服务;要求显式标签
      - "--providers.swarm.exposedbydefault=false"

      # 指定 Traefik 用于连接服务的默认网络
      - "--providers.swarm.network=traefik_traefik_proxy"

      # API & 仪表盘
      - "--api.dashboard=true" # 启用仪表盘
      - "--api.insecure=false" # 显式禁用不安全的 API 模式

      # 可观测性
      - "--log.level=INFO" # 设置日志级别,例如 INFO、DEBUG
      - "--accesslog=true" # 启用访问日志
      - "--metrics.prometheus=true"  # 启用 Prometheus

    deploy:
      mode: replicated
      replicas: 1
      placement:

      # Placement 约束限制 Traefik 任务可以运行的位置
      # 在管理节点上运行是常见做法,因为需要通过 socket 访问 Swarm API
        constraints:
          - node.role == manager

      # 通过标签进行 Traefik 动态配置
      # 在 Swarm 中,服务定义上的标签会为该服务配置 Traefik 路由
      labels:
        - "traefik.enable=true"

        # 仪表盘路由器
        - "traefik.http.routers.dashboard.rule=Host(`dashboard.swarm.localhost`)"
        - "traefik.http.routers.dashboard.entrypoints=websecure"
        - "traefik.http.routers.dashboard.service=api@internal"
        - "traefik.http.routers.dashboard.tls=true"

        # Basic 认证中间件
        - "traefik.http.middlewares.dashboard-auth.basicauth.users=<PASTE_HASH_HERE>"
        - "traefik.http.routers.dashboard.middlewares=dashboard-auth@swarm"

        # 服务提示
        - "traefik.http.services.traefik.loadbalancer.server.port=8080"

  # 部署 Whoami 应用
  whoami:
    image: traefik/whoami
    networks:
      - traefik_proxy
    deploy:
      labels:
        # 为 Traefik 启用服务发现
        - "traefik.enable=true"
        # 定义 whoami 路由器规则
        - "traefik.http.routers.whoami.rule=Host(`whoami.swarm.localhost`)"
        # 在 HTTPS 入口点上暴露 whoami
        - "traefik.http.routers.whoami.entrypoints=websecure"
        # 启用 TLS
        - "traefik.http.routers.whoami.tls=true"
        # 向 Traefik 暴露 whoami 端口号
        - traefik.http.services.whoami.loadbalancer.server.port=80

# 定义 Swarm 的覆盖网络
networks:
  traefik_proxy:
    driver: overlay
    attachable: true

ℹ️ 提示

  • &lt;PASTE_HASH_HERE&gt; 替换为上一步中的转义后哈希值。
  • 密码哈希直接存储在服务标签中。这对于本地开发是可以的,但任何有权访问 Docker API 的人都可以使用 docker service inspect 查看它。对于生产环境,请使用更安全的方法来存储密钥。

启动栈

创建一次覆盖网络(如果不存在)并部署:

bash
docker network create --driver overlay --attachable traefik_proxy || true
docker stack deploy -c docker-compose-swarm.yaml traefik

Swarm 将服务调度到管理节点并绑定 80/443 端口。

访问仪表盘

在浏览器中打开 https://dashboard.swarm.localhost/ ——仪表盘应提示你输入配置的 basic-auth 凭证。

测试 whoami 应用

你可以使用 curl 测试该应用:

bash
curl -k https://whoami.swarm.localhost/

返回内容:

Hostname: whoami-76c9859cfc-k7jzs
IP: 127.0.0.1
IP: ::1
IP: 10.42.0.59
IP: fe80::50d7:a2ff:fed5:2530
RemoteAddr: 10.42.0.60:54148
GET / HTTP/1.1
Host: whoami.swarm.localhost
User-Agent: curl/8.7.1
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 10.42.0.1
X-Forwarded-Host: whoami.swarm.localhost
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Forwarded-Server: traefik-644b7c67d9-f2tn9
X-Real-Ip: 10.42.0.1

向 HTTP 入口点发起相同的请求将返回:

bash
curl -k http://whoami.swarm.localhost

Moved Permanently

请求 HTTP 端点会重定向到 HTTPS,确认设置工作正常。

你也可以在浏览器中打开 https://whoami.swarm.localhost 查看服务的 JSON 转储:

其他关键配置领域

除了此初始设置,Traefik 还提供了广泛的配置可能性。以下是使用 Docker Compose command 参数或 labels 的简要介绍和最小示例。详细选项请查阅主文档。

TLS 证书管理(Let's Encrypt)

要使 websecure 入口点自动提供有效的 HTTPS 证书,请启用 Let's Encrypt(ACME)。

yaml
command:
  # ...
  - "[email protected]"
  - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
  - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
  - "--entrypoints.websecure.http.tls.certresolver=le"

这定义了一个名为 le 的解析器,设置了必需的电子邮件和存储路径(在挂载的 /letsencrypt 卷内),并启用了 HTTP challenge。有关 challenge 和 DNS provider 配置的详细信息,请参阅 HTTPS/TLS 文档Let's Encrypt 文档

注意

  • 确保 /letsencrypt 路径位于共享卷或 NFS 上,以便所有节点都可以读取证书。
  • 确保在 docker-compose-swarm.yaml 文件的 traefik 服务中挂载 /letsencrypt 卷。

指标(Prometheus)

你可以暴露 Traefik 的内部指标供 Prometheus 监控。我们在设置中已启用 Prometheus,但可以进一步配置它。

command 添加示例:

yaml
command:
  # 如果使用专用指标入口点,请定义它:
  - "--entrypoints.metrics.address=:8082"

  - "--metrics.prometheus=true"

  # 可选:更改暴露指标的入口点(默认为 'traefik')
  - "--metrics.prometheus.entrypoint=metrics"

  # 为指标添加路由器/服务的标签(可能增加基数)
  - "--metrics.prometheus.addrouterslabels=true"

链路追踪(OTel)

你可以启用分布式追踪来跟踪通过 Traefik 的请求。

yaml
command:
  # ...
  - "--tracing.otel=true"
  - "--tracing.otel.grpcendpoint=otel-collector:4317"

注意:此选项需要 Traefik 可访问的运行中的 OTEL 收集器。请参阅链路追踪文档

访问日志

你可以将 Traefik 配置为记录传入请求以进行调试和分析。

yaml
command:
  # ... 其他 command 参数 ...
  - "--accesslog=true" # 启用到 stdout 的访问日志

  # 可选:更改格式或输出文件(需要卷)
  - "--accesslog.format=json"
  - "--accesslog.filepath=/path/to/access.log"

  # 可选:过滤日志
  - "--accesslog.filters.statuscodes=400-599"

结论

现在你已经在 Docker Swarm 上运行了 Traefik,包含 HTTPS、安全的仪表盘、自动的 HTTP → HTTPS 重定向以及基础的可观测性。随着你的 Swarm 增长,可以扩展此栈以添加 Let's Encrypt、更多中间件或多个 Traefik 副本。


在生产环境使用 Traefik OSS?

如果你在工作中使用 Traefik,可以考虑为其添加企业级 API 网关能力或获取 Traefik OSS 的商业支持。

基于 MIT 协议发布