首页
/ Traefik on Docker Swarm 基础实战:使用服务标签暴露 HTTP 服务、路径路由与自签名 TLS 全流程

Traefik on Docker Swarm 基础实战:使用服务标签暴露 HTTP 服务、路径路由与自签名 TLS 全流程

2026-09-07 18:36:39作者:董斯意

导读

本文以 Traefik 官方文档 docs/content/expose/swarm/basic.md 为主线,完整演示如何在 Docker Swarm 集群中通过 Traefik Proxy 暴露后端服务:先用 traefik/whoami 打通首条 HTTP 路由并验证请求流转,再基于 URL 路径实现不同服务间的分流,最后用自签名证书为服务启用 HTTPS。读完本文,你将掌握 Swarm 模式下“以服务(service)为单位、以 deploy.labels 为载体”的 Traefik 配置方式,并能独立搭建一套可本地联调的多服务 Swarm 网关。相关源码与参考文档可继续深入 swarm provider 参考Docker Swarm 部署指南 与本系列进阶篇 Traefik on Docker Swarm 进阶指南

前置条件

在开始之前,请确保环境满足:

  • 已初始化 Docker Swarm 集群(docker swarm init);
  • 具备基本的 Docker Swarm 概念(服务、任务、overlay 网络);
  • 已按 Traefik Docker Swarm 部署指南 将 Traefik 部署为 Swarm 服务,且静态配置中已定义 web(:80)与 websecure(:443)两个 entrypoint。

Swarm 模式与 Docker 模式的配置差异(建议先理解)

Traefik 通过 provider 发现后端并读取其路由配置。需要特别注意的是:在 Swarm 模式下,Traefik 读取的是“服务”上的标签,而不是单个容器上的标签。因此,使用 compose 文件部署时,标签必须写在服务的 deploy.labels 段中,而不能写在普通的 labels 段(那是给容器用的)。

从源码看,Traefik 的 Swarm 集成实现在 pkg/provider/docker/pswarm.go,其与共享标签逻辑共用 pkg/provider/docker/shared_labels.go 中的标签解码函数,分别识别 traefik.enabletraefik.docker.*traefik.swarm.* 前缀的标签,其中 traefik.docker.* 在 Swarm provider 下已标记为废弃,应改用 traefik.swarm.*。这也解释了为何本文与部署指南中的标签都形如 traefik.enable=truetraefik.http.routers.whoami.rule=...——前者是总开关,后者属于 traefik.http.* 动态路由命名空间,与具体 provider 无关。

此外,Swarm API 只暴露在 manager 节点上,Traefik 通常应通过 deploy.placement.constraints 限定运行在 manager 节点,并以只读方式挂载 /var/run/docker.sock,具体做法见 部署指南

暴露第一个 HTTP 服务

我们使用 traefik/whoami 作为演示后端。它会将收到的 HTTP 请求原样回显(主机名、IP、请求头等),非常适合验证 Traefik 的路由结果。

如果你还没有 compose 文件,请新建 docker-compose.yml;如果已有(例如部署指南中创建的 docker-compose-swarm.yaml),则在其基础上补充服务:

services:
  whoami:
    image: traefik/whoami
    networks:
      - traefik_proxy
    deploy:
      replicas: 3
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.whoami.rule=Host(`whoami.swarm.localhost`)"
        - "traefik.http.routers.whoami.entrypoints=web,websecure"

这里每一条标签的作用:

标签 含义
traefik.enable=true 显式允许该服务被 Traefik 发现。建议在 Traefik 静态配置中同时设置 exposedbydefault=false,让“只有打了 traefik.enable=true 的服务”才会被纳入路由,见 exposedByDefault 说明
traefik.http.routers.whoami.rule=Host(\whoami.swarm.localhost`)` 定义路由器 whoami 的匹配规则:仅当请求 Host 为 whoami.swarm.localhost 时命中
traefik.http.routers.whoami.entrypoints=web,websecure 将该路由器挂到已定义的 HTTP(web) 与 HTTPS(websecure) 两个入口点上

其中 rule 中反引号包裹的是 Traefik 规则表达式(与 Go template、正则均无关),Host(...) 是内建匹配函数之一。Swarm 模式下服务可多副本(这里 replicas: 3),Traefik 会自动把该服务的多个任务放入同一个负载均衡集合中分发流量。

部署栈:

docker stack deploy -c docker-compose.yml traefik

若使用的是部署指南中的 docker-compose-swarm.yaml,执行 docker stack deploy -c docker-compose-swarm.yaml traefik,并把本文示例合入对应文件。首次部署前确保 overlay 网络 traefik_proxy 已创建(docker network create --driver overlay --attachable traefik_proxy),并且 Traefik 服务与业务服务都挂在该网络上,Traefik 才能解析到各服务的地址。

关于“路由器没有显式绑定 service”这一点:当 Swarm 中该服务只对应一个服务(即 Traefik 为该服务自动生成的服务)且路由器未指定 service 时,Traefik 会把唯一的服务自动关联到该路由器,规则细节参见 service-by-label 说明。如果希望显式且可控,可在标签中补充 traefik.http.services.whoami.loadbalancer.server.port=80(Swarm provider 不提供端口自动探测,明确端口是官方推荐做法,见 Port Detection)。

验证服务是否可达

服务暴露后即可通过 whoami.swarm.localhost 访问。由于本地没有对应 DNS 解析,直接让 curl 携带 Host 头打到 localhost 即可:

curl -H "Host: whoami.swarm.localhost" http://localhost/

正常响应类似:

Hostname: whoami.1.7c8f7tr56q3p949rscxrkp80e
IP: 127.0.0.1
IP: ::1
IP: 10.0.1.8
IP: fe80::215:5dff:fe00:c9e
RemoteAddr: 10.0.1.2:45098
GET / HTTP/1.1
Host: whoami.swarm.localhost
User-Agent: curl/7.68.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 10.0.1.1
X-Forwarded-Host: whoami.swarm.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 5789f594e7d5
X-Real-Ip: 10.0.1.1

这份回显正是“Traefik 已成功把请求路由到 whoami 后端”的直接证据:

  • Hostname 形如 whoami.1.<task-id>,说明请求落到了 Swarm 中的某个 whoami 任务(副本);
  • X-Forwarded-For / X-Real-Ip 表明 Traefik 在转发前按约定补充了代理头;
  • X-Forwarded-Proto: http 说明请求确实经由 HTTP entrypoint 进入(后续启用 TLS 后可对比看到 https);
  • 多次请求应看到不同 Hostname(不同副本被轮询),直观感受 Swarm 的负载均衡。

添加基于路径的路由规则

单个 Host 只能服务一个入口,实际部署常需要把同一域名下的流量按 URL 路径分发到不同后端,典型场景包括:API 版本化、前后端分离、微服务按路径拆分等。Traefik 通过 PathPrefix / Path / PathRegexp 等匹配函数支持这一能力,完整语法参见 规则文档中的 Path、PathPrefix 与 PathRegexp 一节

继续编辑 docker-compose.yml,追加一个带路径规则的服务:

# ...

# New service
  whoami-api:
    image: traefik/whoami
    networks:
      - traefik_proxy
    environment:
      - WHOAMI_NAME=API Service
    deploy:
      replicas: 2
      labels:
        - "traefik.enable=true"
        # Path-based routing
        - "traefik.http.routers.whoami-api.rule=Host(`whoami.swarm.localhost`) && PathPrefix(`/api`)"
        - "traefik.http.routers.whoami-api.entrypoints=web,websecure"
        - "traefik.http.routers.whoami-api.service=whoami-api-svc"
        - "traefik.http.services.whoami-api-svc.loadbalancer.server.port=80"

各标签要点:

  • 路由规则升级为复合规则:Host(\whoami.swarm.localhost`) && PathPrefix(`/api`),即“域名匹配且路径以 /api` 开头”两个条件同时满足才命中;
  • traefik.http.routers.whoami-api.service=whoami-api-svc 显式把路由器绑定到一个自定义命名的 service;
  • traefik.http.services.whoami-api-svc.loadbalancer.server.port=80 声明后端端口。这里为 whoami-api 显式声明 service 与端口,与首例依赖“自动关联”的方式互补,也演示了命名必须两端一致的规则;
  • 通过环境变量 WHOAMI_NAME=API Service 给该后端打上业务标识,whoami 会把它回显在响应里,便于区分后端来自哪个服务。

应用变更(Swarm 会对既有服务做滚动更新,而不是重建整个栈):

docker stack deploy -c docker-compose.yml traefik

测试路径路由是否生效

# Root path should go to the main whoami service
curl -H "Host: whoami.swarm.localhost" http://localhost/

# /api path should go to the whoami-api service
curl -H "Host: whoami.swarm.localhost" http://localhost/api

访问 /api 时,响应中应能看到与 WHOAMI_NAME=API Service 相关的环境变量信息(API Service 字样),以此确认请求确实被分发到了 whoami-api,路径路由生效。

补充说明路由优先级:当 Host(...) 规则相同而 Path 规则不同时,Traefik 会按规则长度自动计算优先级(Path 规则更长、更具体则优先),因此 /api 前缀请求会命中 whoami-api,其余路径回落到 whoami,具体计算规则见 Priority Calculation

启用 TLS(自签名证书)

加密是网关的基本能力。本文先介绍面向本地开发的自签名证书方案,下一进阶篇再介绍 Let's Encrypt 自动化签发。

生成自签名证书与动态配置文件

首先生成有效期一年的自签名证书(覆盖 *.swarm.localhost 通配域名):

mkdir -p certs

# key + cert (valid for one year)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout certs/local.key -out certs/local.crt \
  -subj "/CN=*.swarm.localhost"

然后生成一段动态配置(File provider),告诉 Traefik 证书文件存放位置。这里把证书路径写为容器内的 /certificates/

# dynamic config that tells Traefik where the cert lives
cat > certs/tls.yml <<'EOF'
tls:
  certificates:
    - certFile: /certificates/local.crt
      keyFile:  /certificates/local.key
EOF

Swarm 中多个节点都要能读到证书文件,比较干净的做法是使用 Docker config(Swarm 会把它作为只读文件分发给相应节点),而非依赖每个节点本地都存在 certs/ 目录:

docker config create swarm-cert.crt certs/local.crt
docker config create swarm-cert.key certs/local.key
docker config create swarm-tls.yml certs/tls.yml

修改 Traefik 服务与 compose 根配置

让 Traefik 把上面创建的 config 挂载为文件,并开启 File provider 动态目录。在 docker-compose.yml 中做两处修改:

① Traefik 服务的 command 段追加(开启 websecure entrypoint 的 TLS,并声明动态配置文件目录):

command:
  # ... existing commands ...
  - "--entryPoints.websecure.address=:443"
  - "--entryPoints.websecure.http.tls=true"
  - "--providers.file.directory=/etc/traefik/dynamic"

说明:--providers.file.directory 让 Traefik 监听该目录下的动态配置文件(支持 .yml/.yaml/.toml)。部署指南中的 Traefik 服务使用的是 .yaml 后缀,因此这里命名为 tls.yml 亦会被识别。若部署指南已通过 --providers.file.filename=/dynamic/tls.yaml 挂载了证书动态配置,则该段可与之等价,不必重复。

② compose 根层级声明 configs 来源

configs:
  swarm-cert.crt:
    file: ./certs/local.crt
  swarm-cert.key:
    file: ./certs/local.key
  swarm-tls.yml:
    file: ./certs/tls.yml

③ Traefik 服务的 configs 段把来源映射为容器内目标路径(对应动态配置中写明的 /certificates/ 路径):

configs:
  - source: swarm-cert.crt
    target: /certificates/local.crt
  - source: swarm-cert.key
    target: /certificates/local.key
  - source: swarm-tls.yml
    target: /etc/traefik/dynamic/tls.yml

综合来看,你的 Traefik 服务应同时具备:只读的 Docker socket 挂载、web/websecure 两个 entrypoint、上文的 configs 映射,以及 manager 节点调度约束(可参考 部署指南中的完整清单)。

重新部署并验证 HTTPS

docker stack deploy -c docker-compose.yml traefik

部署完成后,浏览器访问 https://whoami.swarm.localhost/ 即可看到 whoami 的回显。因为是自签名证书,浏览器会弹出安全警告,本地联调时接受该警告即可;用 curl 验证时可加 -k 跳过证书校验:

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

对比 HTTP 与 HTTPS 两个入口,观察回显中 X-Forwarded-Protohttp 变为 https,即证明请求确实经由 TLS 终止后转发到后端。

小结与下一步

至此你已完成 Swarm 下 Traefik 的三项基础能力:

  1. 服务发现与暴露:通过 deploy.labels 让 Swarm 中的服务被 Traefik 识别并按 Host 规则路由;
  2. 基于路径的路由:用 && PathPrefix(...) 复合规则把同一域名流量分流到不同后端;
  3. TLS 加密:以自签名证书 + File provider 动态配置 + Docker config 分发,为本地 Swarm 提供 HTTPS 能力。

在此基础上,建议继续研读 Traefik on Docker Swarm 进阶指南,那里将展开:通过中间件(Middleware)注入安全响应头与 IP 白名单访问控制、用 Let's Encrypt 自动化签发与管理证书、为有状态应用配置会话粘滞(sticky sessions)、基于认证的父子路由器多层路由,以及在服务层统一应用中间件等生产级话题。若需查阅 Swarm provider 的全部配置项(轮询间隔、constraints、defaultRule、TLS 连接 Docker 等),可直接对照 Swarm provider 官方参考文档

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

项目优选

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