为什么 Traefik 在后端网络上发现容器 IP 地址?

Why Traefik discovers container IP address on backend network?

使用 Traefik basic example 和 2 项服务:traefik 本身和 traefik/whoami,我将这两项服务分配给名为 web 的网络,后者分配给 backend网络也是如此。

但是,Traefik 发现 traefik/whoami 服务的 backend IP 地址,无法通过 web 网络进行联系,导致“网关超时”

为了强制 Traefik 使用 web 网络,我也添加了 --providers.docker.network=webtraefik.docker.network=web,但它仍然发现 backend IP 地址。

如何让 Traefik 在正确的网络上发现服务 IP 地址?

这是我要开始工作的 docker-compose.yml 文件。

version: "3.8"

services:

  traefik:
    image: "traefik:v2.3"
    command:
      - --log.level=DEBUG
      - --api.insecure=true
      - --api.dashboard=true
      - --api.debug=true
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --providers.docker.network=web
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    networks:
      - web

  whoami:
    image: "traefik/whoami"
    labels:
      - traefik.enable=true
      - traefik.http.routers.whoami.rule=Host(`whoami.localhost`)
      - traefik.http.routers.whoami.entrypoints=web
      - traefik.docker.network=web
    networks:
      - web
      - backend

networks:
  web:
  backend:

PS! 当您从服务中删除 backend 网络时,它工作正常!

网络名称存在一个小问题。由于您 运行 在撰写文件中并且不引用外部网络,因此网络名称是在当前 compose project 的范围内创建的。启动时,您可能会看到一些消息说

Creating network "traefik2-test_web" with the default driver
Creating network "traefik2-test_backend" with the default driver

(假设您 运行 所在的文件夹名为 traefik2-test)这意味着创建的 docker 网络以项目名称为前缀,例如允许为独立实例旋转撰写文件两次。

您可能还会在日志中看到一些错误,表明未找到名为 web 的已配置网络 - 因此它回退到随机选择一个网络。

traefik_1  | time="2020-10-29T14:24:25Z" level=warning msg="Could not find network named 'web' for container '/traefik2-test_whoami_1'! Maybe you're missing the project's prefix in the label? Defaulting to first available network." providerName=docker container=whoami-traefik2-test-4661d09157cf941b7efd7c8154af5611249866c4bc394c256e225e05db21a784 serviceName=whoami-traefik2-test

所以 traefik 需要网络的全局有效名称,而不关心它是从 compose 项目内部启动的。您可以通过执行

来验证网络名称
docker container inspect XXX_whoami_1

其中 XXX 是您的 docker-compose 项目的名称。

你现在可以做什么?

解决方案 1:修复并通过 env 引用项目名称

相应地构造网络名称,以便参数与 docker-compose 创建的网络的全局唯一名称相匹配。如果您在这个 compose 文件中的所有目标容器都在 web 网络中,您甚至可以省略目标容器上的特殊标签。

    traefik:
      image: "traefik:v2.3"
      command:
        - --log.level=DEBUG
        - --api.insecure=true
        - --api.dashboard=true
        - --api.debug=true
        - --providers.docker=true
        - --providers.docker.exposedbydefault=false
        - --entrypoints.web.address=:80
        - --providers.docker.network=${COMPOSE_PROJECT_NAME}_web
      ports:
        - "80:80"
        - "8080:8080"
      volumes:
        - "/var/run/docker.sock:/var/run/docker.sock:ro"
      networks:
        - web

这需要您为每个命令传递一个 docker 组合项目名称(或相应地设置环境)

COMPOSE_PROJECT_NAME=proj docker-compose up

问题在于您确实需要为每次调用指定该变量。您可以通过在启用该功能的 docker-compose.yml 旁边使用 .env 文件来解决该问题。

COMPOSE_PROJECT_NAME=projfromenv

备选方案:外网参考

但可能有更好的解决方案。第二种选择是通过引用现有网络来使用全球唯一的网络名称。这需要像这样初始设置网络:

docker network create traefik-net

然后在网络部分引用它:

networks:
  web:
    external: true
    name: traefik-net
  backend:

并使用此网络名称(片段)的引用启动 traefik:

- --providers.docker.network=traefik-net

您的目标容器仍然引用本地网络名称 web,该名称现在是对该全局网络的引用。您不需要为 whoami 容器指定 traefik 网络标签,因为您不需要覆盖默认值。

此设置还允许使用容器启动其他 compose 项目,这些容器也应该从此 traefik 实例中公开。所以我会选择第二个选项...