如何使用 traefik 路由到一个 docker 群服务暴露两个端口?

How to route with traefik to one docker swarm service exposing two ports?

RabbitMq 在端口 15672 提供管理 GUI,客户端在端口 5672 连接到消息代理

我的环境:
docker群服务器版本:19.03.5
图片:"traefik:v2.0.2"
图片:rabbitmq:management-高山

我可以在 https://mq.mydom.comexample 浏览 Rabbit MQ 管理页面 下面是我的 compose.yml for docker stack deploy

的一部分
  mq:
    deploy:
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.mq-service.rule=Host(`mq.mydom.comexample`)"
        - "traefik.http.services.mq-service.loadbalancer.server.port=15672"
        - "traefik.http.routers.mq-service.entrypoints=websecure"
        - "traefik.http.routers.mq-service.tls.certresolver=mytlschallenge"

现在我也想在同一服务中连接到 RabbitMq 消息代理 但我不明白 traefik 语法。尝试变体没有成功。 以下是其中一种变体,可能会显示我希望实现的目标:

  mq:
    deploy:
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.mq-service.rule=Host(`mq.mydom.comexample`)"
        - "traefik.http.services.mq-service.loadbalancer.server.port=15672"
        - "traefik.http.routers.mq-service.entrypoints=websecure"
        - "traefik.http.routers.mq-service.tls.certresolver=mytlschallenge"
        # so far same as above

        - "traefik.http.routers.mq-connect.rule=Host(`mq-connect.mydom.comexample`)"
        - "traefik.http.services.mq-connect.loadbalancer.server.port=5672"

正在浏览 https://mq.mydom.comexamplehttps://mq-connect.mydom.comexample 两者都响应 404 页面未找到

远程登录 mq.mydom.comexample 443
telnet mq-connect.mydom.comexample 443
两者都连接:转义字符是'^]'。

如何告诉 traefik 路由我想要什么?

我对 Traefik V2 做了更多的研究。多个端点的解决方案是明确命名您的服务。 这是一个例子:

  whoami:
    image: "containous/whoami"
    container_name: "simple-service"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.docker`)"
      - "traefik.http.routers.whoami.entrypoints=web"
      - "traefik.http.routers.whoami.service=whoami"
      - "traefik.http.services.whoami.loadbalancer.server.port=80"
      - "traefik.http.routers.altwhoami.rule=Host(`alt.docker`)"
      - "traefik.http.routers.altwhoami.entrypoints=web"
      - "traefik.http.routers.altwhoami.service=altwhoami"
      - "traefik.http.services.altwhoami.loadbalancer.server.port=80"

因此,为了修复您的 traefik 实现,您需要添加 traefik.http.routers.whoami.service=service-name 标签。

希望对您有所帮助。

编辑:

为了通过 traefik 路由 AMQP,您需要一个 TCP 路由器。我为 rabbitmq 创建了一个小的工作示例:

version: "3.3"
services:
  traefik:
    image: "traefik"
    container_name: "traefik"
    command:
      - "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.rabbitmq.address=:5672"
    ports:
      - "80:80"
      - "8080:8080"
      - "5672:5672"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

  rabbitmq:
    image: "rabbitmq:management-alpine"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.rabbitmq.rule=Host(`rabbitmq.docker`)"
      - "traefik.http.routers.rabbitmq.entrypoints=web"
      - "traefik.http.routers.rabbitmq.service=rabbitmq"
      - "traefik.http.services.rabbitmq.loadbalancer.server.port=15672"

      - "traefik.tcp.routers.ingress.rule=HostSNI(`*`)"
      #- "traefik.tcp.routers.ingress.rule=HostSNI(`ingress.docker`)"
      - "traefik.tcp.routers.ingress.entrypoints=rabbitmq"
      #- "traefik.tcp.routers.ingress.tls=true"
      #- "traefik.tcp.routers.ingress.tls.passthrough=true"
      - "traefik.tcp.services.ingress.loadbalancer.server.port=5672"

这会将端口 5672 上的 TCP 流量通过 traefik 路由到您的容器(确保相应地调整您的 traefik 配置)。

您可能会注意到相当开放的 HostSNI(*) 规则。如果您想将此规则限制为单个 host/domain,则必须在 rabbitmq 中启用 TLS support 以便 traefik 正确过滤这些请求。

查看有关将 traefik 转换为支持 tls 的信息的注释行。您可以让 traefik 处理 TLS 或直接将其传递给 rabbitmq。

总而言之,这对我有用(非常感谢)。

version: "3.7"

  traefik:
    image: "traefik:v2.0.2"
    command:
      - "--api.insecure=true"
      - "--providers.docker.swarmMode=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.rabbitmq.address=:5672"
      - "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
     # testing: Letsencrypt would close us out for 24hrs if too many bad requests are made!
     #- "--certificatesresolvers.mytlschallenge.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
      - "--certificatesresolvers.mytlschallenge.acme.email=postmaster@mydomain"
      - "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
      - "--log=true"
      - "--log.filepath=/var/log/traefik.log"
    ports:
      # https
      - "443:443"
      # traefik dash
      - "8080:8080"
      # rabbit mq message broker
      - "5672:5672"
    volumes:
      - "./letsencrypt:/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

  mq:
    hostname: xyz_mq
    image: rabbitmq:3.8.2-alpine
    environment:
      - RABBITMQ_DEFAULT_VHOST=prod_vhost
      - RABBITMQ_DEFAULT_USER=prod_user
      - RABBITMQ_DEFAULT_PASS=abcdef123
    deploy:
      labels:
        - "traefik.enable=true"

        # web browser access to RabbitMq management GUI
        - "traefik.http.routers.mq.rule=Host(`mq.mydomain`)"
        - "traefik.http.services.mq.loadbalancer.server.port=15672"
        - "traefik.http.routers.mq.entrypoints=websecure"
        - "traefik.http.routers.mq.tls.certresolver=mytlschallenge"
        - "traefik.http.routers.mq.service=mq"

        # AMQPS - SSL terminated by traefik
        - "traefik.tcp.routers.mq-connect.rule=HostSNI(`mq-connect.mydomain`)"
        - "traefik.tcp.services.mq-connect.loadbalancer.server.port=5672"
        - "traefik.tcp.routers.mq-connect.entrypoints=rabbitmq"
        - "traefik.tcp.routers.mq-connect.tls.certresolver=mytlschallenge"
        - "traefik.tcp.routers.mq-connect.service=mq-connect"
    volumes:
      - rabbitmq:/var/lib/rabbitmq
      - ./rabbitmq_plugins:/etc/rabbitmq/enabled_plugins
    stop_grace_period: 5m

volumes:
  rabbitmq:

我在尝试让 RabbitMQ 落后于 Traefik 运行 时偶然发现了这个答案。在为在我的 EC2 实例上获得 运行 这些解决方案而奋斗了几天之后,我终于意识到这些示例(它们完美运行)与我在云上 运行 部署它们的方式之间的唯一区别是docker 资源限制(我总是将其应用于云服务)。

我不知道最小约束是什么(或者这些约束如何严重干扰 RabbitMQ),但我可以说这些资源限制会导致问题并会创建一个 semi-functional RMQ 实例(我经常可以连接到它,但无法成功地从中提取任务)。我认为这是因为我搞砸了一些 Traefik 路由,但这是此处提到的 docker 资源限制。希望这能让其他人头疼!

resources:
  limits:
    cpus: "0.25"
    memory: 128M

Rabbit's Production Checklist 看来至少需要 256MB 的内存。将此限制提高到 256MB 并没有解决问题,但仔细阅读本文档可能会发现导致创建不稳定实例的资源限制。

Rabbit's Docker Hub Page 看来,由于 Rabbit 明确跟踪和管理内存使用情况,因此需要了解 cgroup-imposed 限制。有问题!您必须让 Rabbit 知道任何 docker 强加给内存的资源限制。