【问题标题】:How to route with traefik to one docker swarm service exposing two ports?如何使用 traefik 路由到一个暴露两个端口的 docker swarm 服务?
【发布时间】:2020-04-23 16:24:12
【问题描述】:

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

我的环境:
docker swarm 服务器版本:19.03.5
图片:“traefik:v2.0.2”
图片:rabbitmq:management-alpine

我可以在https://mq.mydom.comexample浏览Rabbit MQ管理页面 将以下内容作为我的 compose.yml 的一部分用于 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 page not found

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

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

【问题讨论】:

  • 看起来您缺少 mq-connect 定义的入口点。 - "traefik.http.routers.mq-connect.entrypoints=websecure"
  • 感谢您的提示。我添加了该入口点,但结果没有什么不同。

标签: docker routing rabbitmq docker-swarm traefik


【解决方案1】:

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

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

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

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

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

【讨论】:

    【解决方案2】:

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

    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:
    

    【讨论】:

      【解决方案3】:

      我对 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"
      

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

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

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

      【讨论】:

      • 是的,与此等效的配置会到达正确端口的容器。但我仍然无法从客户端连接到 RabbitMq 消息代理。我相信这是因为 traefik 需要 http 协议,但 RabbitMQ 使用自己的协议,他们称之为“amqp”(高级消息队列协议)。我怎样才能让 treafik 意识到这一点?响应是 'Timeout::Error (IO timeout when reading 7 bytes)' 和 msg="'500 Internal Server Error' 由:net/http: HTTP/1.x 传输连接中断:格式错误的 HTTP 响应 \"AMQP\ \x00\\x00\\t\\x01\""
      • 我添加了一个 tcp 路由器的示例来处理 AMQP 路由。
      • @pat 是否可以使用 TLS 设置 HostSNI 而不是 * 但在 Traefik 级别终止连接?即,您是否必须启用 TLS 直通?我不清楚为什么 TLS 连接不能在 Traefik 终止。非常感谢您的帮助!
      猜你喜欢
      • 2019-06-04
      • 2019-06-22
      • 2020-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多