You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何实现Traefik级联部署:跨Docker子网路由独立服务

这个架构我之前帮朋友搭建过,核心就是解决Docker网络互通+Traefik跨实例路由的问题,分几步就能搞定:

1. 先搞定Docker网络互通(最关键的一步)

每个Docker Compose默认会创建孤立的内部网络,所以要让traefik_main能访问到traefik_atraefik_b,最简单的方式是创建一个共享的外部网络,让三个Compose都加入这个网络。

创建共享网络

先在主机上手动创建一个外部网络:

docker network create traefik_shared

给每个Compose配置加入共享网络

traefik_main的docker-compose.yml片段:

networks:
  traefik_shared:
    external: true  # 指定这是外部创建的网络
  traefik_main_internal:  # 这个是traefik_main自己的内部服务网络,和共享网络隔离
    driver: bridge

services:
  traefik-main:
    image: traefik:v2.10
    # 其他配置...
    networks:
      - traefik_shared
      - traefik_main_internal

traefik_a的docker-compose.yml片段(traefik_b同理):

networks:
  traefik_shared:
    external: true
  traefik_a_internal:  # 自己的内部服务网络,比如service1.a.com就在这个网络里
    driver: bridge

services:
  traefik-a:
    image: traefik:v2.10
    # 其他配置...
    networks:
      - traefik_shared
      - traefik_a_internal

这样三个Traefik实例就处于同一个共享网络里,Docker的内置DNS会自动解析服务名(比如traefik-atraefik-b)到对应容器的IP,不用手动写IP。

2. 配置traefik_a和traefik_b的入口

traefik_atraefik_b不需要暴露端口到主机(除非你要绕过traefik_main直接访问),只要在共享网络里开放它们的Web入口端口(默认是80)就行。比如traefik-a的启动命令可以这样写:

services:
  traefik-a:
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"  # 在容器内监听80端口,共享网络里能访问
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    # 不要加ports字段暴露到主机,保持内部访问即可
3. 配置traefik_main的路由规则

接下来要让traefik_main根据域名后缀把请求转发到对应的子Traefik实例,推荐用File Provider来配置动态路由,比Docker Provider更清晰。

给traefik_main添加File Provider配置

首先在traefik_main的配置目录下创建dynamic_conf.yml

http:
  routers:
    # 匹配所有*.a.com的域名,转发到traefik-a
    route-to-a:
      rule: "HostRegexp(`{subdomain:[a-z0-9-]+}.a.com`)"
      entryPoints:
        - web  # 对应traefik_main的入口点
      service: traefik-a-service

    # 匹配所有*.b.com的域名,转发到traefik-b
    route-to-b:
      rule: "HostRegexp(`{subdomain:[a-z0-9-]+}.b.com`)"
      entryPoints:
        - web
      service: traefik-b-service

  services:
    traefik-a-service:
      loadBalancer:
        servers:
          - url: "http://traefik-a:80"  # 用共享网络里的服务名访问traefik-a的80端口

    traefik-b-service:
      loadBalancer:
        servers:
          - url: "http://traefik-b:80"

然后在traefik_main的启动命令里加载这个动态配置:

services:
  traefik-main:
    command:
      - "--api.insecure=true"  # 调试用,生产环境一定要关掉
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--providers.file.directory=/etc/traefik/dynamic"  # 指定动态配置目录
    volumes:
      - ./dynamic:/etc/traefik/dynamic  # 挂载刚才创建的dynamic_conf.yml目录
      - /var/run/docker.sock:/var/run/docker.sock:ro
4. 验证配置

启动三个Compose后:

  1. 访问service1.a.comtraefik_main会把请求转发到traefik-a,再由traefik-a路由到对应的service1服务。
  2. 可以用docker exec traefik-main-container curl http://traefik-a:80测试连通性,看能不能正常访问traefik-a的入口。
额外注意事项
  • 生产环境一定要开启HTTPS,traefik_main可以统一管理所有域名的TLS证书,子Traefik实例只要处理HTTP请求就行。
  • 如果用Traefik v3,配置语法略有差异,但核心的网络互通和路由转发逻辑完全一致。
  • 要是不想用共享网络,也可以把traefik_atraefik_b的网络设置为external: truetraefik_main直接连接,但共享网络的方式更干净。

内容的提问来源于stack exchange,提问作者Thomas

火山引擎 最新活动