首页
/ 在 Docker Swarm 中部署 Traefik v3 代理:完整配置指南(HTTP/HTTPS 入口、Dashboard 鉴权与可观测性)

在 Docker Swarm 中部署 Traefik v3 代理:完整配置指南(HTTP/HTTPS 入口、Dashboard 鉴权与可观测性)

2026-09-07 11:46:55作者:何将鹤

本指南以官方 Swarm 教程为主体,逐步讲解如何把 Traefik v3 作为 Swarm Service 通过 docker stack deploy 部署到 Docker Swarm 集群:启用 Swarm Provider 完成服务发现、暴露 web/websecure 两个入口点、强制 HTTP→HTTPS 跳转、用 basic-auth 保护 Dashboard、以自签名证书终结 TLS,并部署 whoami 演示服务验证全链路。读完你将从零搭建一套可用于本地多节点 Swarm 的、带 HTTPS 与可观测性能力的反向代理栈,并掌握后续扩展 Let's Encrypt、Prometheus 指标、OTel 链路追踪和访问日志的配置方法。

该指南的结构与单机 Docker 教程保持一致,可对照阅读;其核心差异在于:Swarm 模式下配置发现由 Swarm Provider(而非 Docker Provider)完成,服务标签需要写在 deploy.labels 中,端口发布必须使用长语法,且服务发现的对象从"容器"变为"服务"。

准备工作(Prerequisites)

开始之前,请确认环境满足以下条件:

  • Docker Engine 已初始化 Swarm 模式docker swarm init 或已加入一个现有 Swarm 集群);
  • docker compose 命令可用(仅用于校验 compose 文件);
  • 主机上安装了 openssl(生成自签名证书);
  • 主机上安装了 htpasswd(生成 basic-auth 口令哈希,通常随 apache2-utils / httpd-tools 提供)。

本教程的典型目标环境是本地多节点开发 Swarm:没有可信 CA,因此使用 *.swarm.localhost 的自签名证书即可满足验证需求。生产环境请改用受信任 CA 签发的证书,或启用 Let's Encrypt(见后文"扩展配置")。

第一步:生成自签名证书

要让 Traefik 在本地提供 HTTPS 服务,首先需要一份证书。生产环境应使用受信任 CA 签发的证书,而对于多节点开发 Swarm,用 openssl 快速生成一张自签名证书即可:

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

参数说明:

  • -x509:直接输出自签名 X.509 证书而非 CSR;
  • -nodes:私钥不加密(便于容器内直接读取);
  • -days 365:证书有效期一年;
  • -newkey rsa:2048:同时生成 2048 位 RSA 私钥;
  • -subj "/CN=*.swarm.localhost":主题通用名为通配符域名,覆盖后面用到的 dashboard.swarm.localhostwhoami.swarm.localhost

生成的 certs/local.crtcerts/local.key 将以只读方式挂载进 Traefik 容器(见 compose 文件中的 volumes),并由动态配置文件 dynamic/tls.yaml 引用。

第二步:生成 Dashboard 的 basic-auth 凭证

Traefik 的 basic-auth 中间件会校验一组"用户名:口令哈希"。使用 htpasswd 生成 admin 用户的口令,并用 sed$ 转义为 $$(Compose / 环境变量的取值语法需要双重转义):

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

复制命令的完整输出(形如 admin:$$apr1$$…),稍后粘贴到中间件的 label 中。

安全提示:口令哈希直接以明文形式存放在 service label 中。这对本地开发没问题,但任何能访问 Docker API 的人都可以用 docker service inspect 查看到它。生产环境请改用更安全的密钥存储方式(如 Docker Secrets + 文件提供者加载),本仓库的 Swarm provider 参考文档中也强调了标签方式的能力边界。

第三步:编写动态 TLS 配置与 docker-compose-swarm.yaml

Swarm 使用 docker stack deploy 发布服务,compose 文件可以任意命名(本文沿用原教程的 docker-compose-swarm.yaml)。

首先在项目目录下创建名为 dynamic 的文件夹并添加 tls.yaml,用于承载动态 TLS 配置(证书文件的声明属于动态配置,Swarm Provider 无法通过标签描述静态入口点,因此以文件方式挂载):

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

在同一目录创建 docker-compose-swarm.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 路由网格(跨节点负载均衡)。
        # 按你的负载均衡策略选择;若外部已有 LB,'host' 模式通常更简单。
        mode: host
      - target: 443 # 容器端口(Traefik websecure 入口点)
        published: 443 # 主机端口
        protocol: tcp
        mode: host

    volumes:
      # 挂载 Docker socket 供 Swarm provider 使用
      # 必须在 manager 节点上运行,才能通过 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"

      # 提供者

      # 启用 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 与 Dashboard
      - "--api.dashboard=true" # 启用 Dashboard
      - "--api.insecure=false" # 显式关闭非安全 API 模式

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

    deploy:
      mode: replicated
      replicas: 1
      placement:

      # 放置约束限制 Traefik 任务可以运行的节点。
      # 通常放在 manager 节点上,以便通过 socket 访问 Swarm API。
        constraints:
          - node.role == manager

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

        # Dashboard 路由器
        - "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-auth 中间件
        - "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

关键点提醒:

  • <PASTE_HASH_HERE> 替换为第二步生成的转义哈希;
  • Swarm 对端口必须使用长语法target/published/protocol/mode),短语法会被忽略;mode: host 直接绑定节点 IP,mode: ingress 则走 Swarm 路由网格做跨节点分发;
  • 标签必须放在 deploy.labelsservices.traefik.labels(容器标签)在 Swarm 模式下不会被读取——这是与单机 Docker 教程最大的差异,参考实现见 pkg/provider/docker/pswarm.go
  • --providers.swarm.network=traefik_traefik_proxy 中的前缀:以 docker stack deploy traefik 发布且网络在 compose 内声明时,Swarm 会为网络加上栈名前缀,traefik_proxy 即变为 traefik_traefik_proxy;若网络是预先手动创建的外部网络,则保持原名(两种方式见下节);Traefik 需要明确它应通过哪个 overlay 网络解析服务 IP,跨节点请求才能正确转发;
  • dashboard 中间件引用写作 dashboard-auth@swarm@swarm 后缀显式声明中间件来源提供者是 Swarm Provider(动态元素名带 provider 限定符);
  • Dashboard 路由将请求转发给内置服务 api@internal(Traefik 自身 API,默认监听 8080),随后的 service 提示端口 8080 只是帮助明确负载均衡指向的端口。

第四步:发布 Stack

先创建一次 overlay 网络(若尚不存在),然后发布栈:

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

Swarm 会依据放置约束把服务调度到 manager 节点,并在节点上绑定 80/443 端口。docker stack services traefikdocker service ps traefik_traefik 可以观察服务的滚动调度与运行状态;若此前已手动创建了同名网络,栈会直接复用该外部网络。

第五步:访问 Dashboard

在浏览器打开 https://dashboard.swarm.localhost/,浏览器会提示证书不受信任(自签名证书,点选继续即可),随后页面要求输入你在 htpasswd 步骤中配置的 basic-auth 凭据(用户名 admin、密码 P@ssw0rd)。成功登录后即可看到路由、服务、中间件与入口点的实时概览:

Traefik Swarm Dashboard

若该页面正常展示,说明证书加载、TLS 终结、Swarm Provider 服务发现、basic-auth 中间件与 api@internal 转发整条链路都已打通。Dashboard 前端源码位于本仓库 webui,通过内置 HTTP API(api@internal,默认 :8080)取数渲染。

第六步:测试 whoami 应用

使用 curl 向 HTTPS 入口发起请求(-k 表示忽略自签名证书校验):

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

whoami 服务会原样回显收到的请求与头部信息:

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

注意 X-Forwarded-Proto: httpsX-Forwarded-Port: 443:这些是 Traefik 在 TLS 终结后附加到上游请求的转发头(由 forwarded headers 机制注入),证明请求确实经过了 websecure 入口点的 HTTPS 处理。

再用 HTTP 入口请求同一域名,验证重定向:

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

Moved Permanently

HTTP 请求被 301 永久重定向到 HTTPS,说明 HTTP→HTTPS 跳转配置生效。也可以在浏览器直接访问 https://whoami.swarm.localhost 查看服务回显的 JSON 数据:

Whoami JSON dump

Swarm Provider 的底层实现与配置项

为了用好这套配置,有必要理解 Swarm Provider 的工作原理。从源码看,Traefik 的 Swarm Provider 与 Docker Provider 共用同一实现目录 pkg/provider/docker,其中 pswarm.go 声明了 SwarmProvider

  • provider 注册名固定为 swarm(源码中的 SwarmName = "swarm");
  • SetDefaults()pkg/provider/docker/pswarm.go)给出的默认值为:watch=trueexposedByDefault=trueendpoint=unix:///var/run/docker.sockrefreshSeconds=15s、默认规则模板 Host(\{{ normalize .Name }}`)`——这正是官方参考文档 Swarm Provider 参考 中默认值的来源;
  • 启动后通过 listServices 枚举 Swarm 服务,再用 builder.build 把服务标签翻译成动态配置;watch=true 时以 15 秒间隔轮询服务列表(Swarm 事件机制受限,见源码注释对 docker/docker#23827 的说明),并把新的动态配置推送给 Traefik 动态配置通道。

由于 默认暴露所有服务,原教程刻意设置 exposedbydefault=false 并配合 traefik.enable=true 显式开关,这是生产环境的推荐姿势。

常用配置项的默认值与说明可归纳如下(完整表格见 providers/swarm.md):

字段 默认值 作用
providers.swarm.endpoint unix:///var/run/docker.sock Docker/Swarm API 端点,也支持 ssh:// 远程端点
providers.swarm.watch true 是否轮询监听 Swarm 服务变化
providers.swarm.exposedByDefault true 默认是否暴露所有服务(建议显式设为 false
providers.swarm.network "" 连接所有服务的默认 overlay 网络,可被 traefik.swarm.network 标签按服务覆盖
providers.swarm.refreshSeconds 15s Swarm 模式的轮询间隔
providers.swarm.defaultRule Host(\{{ normalize .Name }}`)` 未通过标签指定规则时的默认路由规则模板
providers.swarm.constraints "" 依据服务标签过滤的约束表达式
providers.swarm.useBindPortIP false 使用绑定端口的 IP/Port 而非容器内部网络地址

标签的命名空间也遵循统一约定:路由 traefik.http.routers.<name>.*、中间件 traefik.http.middlewares.<name>.*、服务 traefik.http.services.<name>.*。Swarm 模式下如果某个服务只有一个且路由器未显式指定 service,该服务会自动分配给该路由器。

更多关键配置方向

基础栈已可用,下面补充几条最常见的高频扩展配置。所有示例都沿用 compose 文件的 command 参数或服务 deploy.labels 写法。

证书自动管理(Let's Encrypt / ACME)

要让 websecure 入口点自动签发可信的 HTTPS 证书,启用 Let's Encrypt(ACME)证书解析器:

command:
  # ...
  - "--certificatesresolvers.le.acme.email=you@example.com"
  - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
  - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
  - "--entrypoints.websecure.http.tls.certresolver=le"

这里定义了一个名为 le 的证书解析器:email 用于注册 ACME 账户,storage 指向 /letsencrypt/acme.json(存放已签发证书),httpchallenge.entrypoint=web 使用 HTTP-01 质询方式验证域名,最后把 websecure 入口点的证书解析器指定为 le

在 Swarm 中启用 ACME 有两点必须注意(参考文档 certificate-resolvers/overviewacme):

  • /letsencrypt 路径必须放在共享卷或 NFS 上,让所有节点都能读取证书(Traefik 副本分布在多节点时,证书存储必须全局一致);
  • 记得在 docker-compose-swarm.yamltraefik 服务中挂载 /letsencrypt 卷,例如 - letsencrypt:/letsencrypt

质询方式与各家 DNS 提供商的详细配置请查阅上述参考文档。

Prometheus 指标

Traefik 内部指标可暴露给 Prometheus 抓取。基础栈中已开启 --metrics.prometheus=true,这里给出进一步定制:

command:
  # 若使用独立指标入口点,先定义它:
  - "--entrypoints.metrics.address=:8082"

  - "--metrics.prometheus=true"

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

  # 为路由/服务附加标签到指标(会提高基数)
  - "--metrics.prometheus.addrouterslabels=true"

指标端点默认位于 traefik 入口点(即内部 API 端口 8080),也可用专用入口点在独立的 :8082 上暴露 /metrics,从而与业务流量隔离。全部选项见 observability/metrics.md;Traefik 自带的 Grafana 仪表盘模板位于本仓库 contrib/grafana,可直接导入使用。

分布式追踪(OpenTelemetry / OTel)

可以开启分布式追踪来跟踪请求在 Traefik 中的处理路径:

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

前提是 Swarm 中存在一个 Traefik 可访问的 OTel Collector,并监听上述 gRPC 端点。完整的端点与协议配置见 observability/tracing.md;仓库中 integration/fixtures/tracing/otel-collector-config.yaml 提供了一份可参考的 Collector 配置样例。

访问日志

Traefik 可以把进入的每个请求记录成访问日志,便于排障与分析:

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

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

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

format 支持默认(CLF)与 json 两种格式;filters.statuscodes 只保留指定状态码范围(如 400-599)的记录,用于聚焦错误请求。字段定义与过滤规则详见 logs-and-access-logs.md

验证与排障思路

  • 端口未绑定 / 无法访问:确认 Traefik 任务确实调度到了 node.role == manager 的节点,且该节点上 80/443 未被占用;
  • 路由 404:检查目标服务的 traefik.enable=truedeploy.labels 是否书写正确,并确认 traefik.http.services.<name>.loadbalancer.server.port 指向了真实容器端口;
  • 标签不生效:Swarm 模式只读取 deploy.labels;容器级 labels 不会参与服务发现;
  • 基础认证失败:确认已用 sed -e 's/\$/\$\$/g' 转义哈希,并且中间件名与路由器引用一致(dashboard-auth@swarm);
  • 跨节点转发失败:确认 --providers.swarm.network 指向的 overlay 网络名正确(栈内声明的网络会带栈名前缀),且该网络对相关服务均 attachable

结论

至此,你已经在 Docker Swarm 上运行起一套完整可用的 Traefik v3:HTTPS 与 HTTP→HTTPS 自动跳转、basic-auth 保护的 Dashboard、自签名证书 TLS 终结、whoami 演示服务,以及日志与 Prometheus 指标等基础可观测能力。随着 Swarm 规模增长,你可以在此基础上叠加 Let's Encrypt 自动证书、更多中间件(限流、重试、鉴权等)或运行多副本 Traefik;关于更复杂的生产部署考虑,还可参考仓库内的企业级部署讨论 traefik-for-business-applications。对应源码与示例均可在当前仓库中找到,便于对照深入学习。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.74 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.63 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
518
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389