docker - 服务更新期间带有 traefik 和 docker swarm 的网关错误

标签 docker deployment load-balancing docker-swarm traefik

我正在尝试将 traefik 与 docker swarm 一起使用,但在服务更新期间遇到了麻烦。我运行 stack deployservice update服务停止了几秒钟

如何重现:

1 - 创建一个 Dockerfile:

FROM jwilder/whoami
RUN echo $(date) > daniel.txt

2 - 构建 2 个演示图像:
$ docker build -t whoami:01 .
$ docker build -t whoami:02 .

3 - 创建一个 docker-compose.yml:
version: '3.5'

services:
  app:
    image: whoami:01
    ports:
      - 81:8000
    deploy:
      replicas: 2
      restart_policy:
        condition: on-failure
      update_config:
        parallelism: 1
        failure_action: rollback
      labels:
        - traefik.enable=true
        - traefik.backend=app
        - traefik.frontend.rule=Host:localhost
        - traefik.port=8000
        - traefik.docker.network=web
    networks:
      - web

  reverse-proxy:
    image: traefik
    command: 
      - "--api"
      - "--docker"
      - "--docker.swarmMode"
      - "--docker.domain=localhost"
      - "--docker.watch"
      - "--docker.exposedbydefault=false"
      - "--docker.network=web"
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
      update_config:
        parallelism: 1
        failure_action: rollback
      placement:
        constraints:
          - node.role == manager
    networks:
      - web
    ports:
      - 80:80
      - 8080:8080
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

networks:
  web:
    external: true

4 - 部署堆栈:
$ docker stack deploy -c docker-compose.yml stack_name

5 - curl 以获得服务响应:
$ while true ; do sleep .1; curl localhost; done

您应该看到如下内容:
I'm adc1473258e9
I'm bc82ea92b560
I'm adc1473258e9
I'm bc82ea92b560

这意味着负载平衡正在工作

6 - 更新服务
$ docker service update --image whoami:02 got_app

traefik 回复 Bad Gateway什么时候应该是零停机时间。

如何解决?

最佳答案

网关错误意味着 traefik 被配置为转发请求,但它无法访问它配置为使用的 ip 和端口上的容器。导致这种情况的常见问题是:

  • traefik 和不同 docker 网络上的服务
  • 服务存在于多个网络中,traefik 选择了错误的
  • 用于连接容器的端口错误(使用容器端口并确保它正在监听所有接口(interface),即 0.0.0.0)


  • 从评论来看,这仅在部署期间发生,这意味着 traefik 在容器准备好接收请求之前或在它们被停止时命中容器。

    您可以使用运行状况检查配置容器,并使用如下所示的 Dockerfile 通过 swarm 模式的 VIP 发送请求:
    FROM jwilder/whoami
    RUN echo $(date) >/build-date.txt
    HEALTHCHECK --start-period=30s --retries=1 CMD wget -O - -q http://localhost:8000
    

    然后在 docker-compose.yml 中:
      labels:
        - traefik.enable=true
        - traefik.backend=app
        - traefik.backend.loadbalancer.swarm=true
        ...
    

    我还将使用以下选项配置 traefik 服务:
      - "--retry.attempts=2"
      - "--forwardingTimeouts.dialTimeout=1s"
    

    但是,traefik 将保持连接打开,并且 VIP 将继续通过同一连接将所有请求发送到同一后端容器。你可以做的是让 traefik 自己执行健康检查:
      labels:
        - traefik.enable=true
        - traefik.backend=app
        - traefik.backend.healthcheck.path=/
        ...
    

    我仍然会将健康检查留在容器本身上,以便 Docker 在停止另一个容器之前让容器有时间启动。并在 traefik 服务上保留重试选项,以便对停止容器的任何请求,或者只是健康检查未检测到的请求,都有机会重试。

    这是我在环境中使用的生成的 compose 文件:
    version: '3.5'
    
    services:
      app:
        image: test-whoami:1
        ports:
          - 6081:8000
        deploy:
          replicas: 2
          restart_policy:
            condition: on-failure
          update_config:
            parallelism: 1
            failure_action: rollback
          labels:
            - traefik.enable=true
            - traefik.backend=app
            - traefik.backend.healthcheck.path=/
            - traefik.frontend.rule=Path:/
            - traefik.port=8000
            - traefik.docker.network=test_web
        networks:
          - web
    
      reverse-proxy:
        image: traefik
        command:
          - "--api"
          - "--retry.attempts=2"
          - "--forwardingTimeouts.dialTimeout=1s"
          - "--docker"
          - "--docker.swarmMode"
          - "--docker.domain=localhost"
          - "--docker.watch"
          - "--docker.exposedbydefault=false"
          - "--docker.network=test_web"
        deploy:
          replicas: 1
          restart_policy:
            condition: on-failure
          update_config:
            parallelism: 1
            failure_action: rollback
          placement:
            constraints:
              - node.role == manager
        networks:
          - web
        ports:
          - 6080:80
          - 6880:8080
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
    
    networks:
      web:
    

    Dockerfile 如上所述。图像名称、端口、网络名称等已更改,以避免与我的环境中的其他内容发生冲突。

    关于docker - 服务更新期间带有 traefik 和 docker swarm 的网关错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55715155/

    相关文章:

    postgresql - Docker 如何向正在运行的容器添加卷?

    docker - 无法在 Linux 上将 Docker 与 pymongo 连接

    docker - 无法停止或终止 Docker 镜像

    deployment - 如何使用 Jenkins 将更新部署到 OpenShift Mono 应用程序?

    windows - 适用于 Windows 程序员的最佳 "official"脚本语言

    java - 是否可以在 JBoss AS 7 中部署分解的 war 文件(解压缩的 war )

    amazon-ec2 - Memcached 无法与 AWS Classic Load Balancer 一起使用

    grails - 如何在Grails应用中控制哪个服务器消耗RabbitMQ队列

    kubernetes - kube-router IPVS-最少连接算法,是否在同一节点或不同节点的 Pod 之间进行负载平衡?

    docker-compose 用于分离模式