在服务更新期间,使用traefik和docker swarm的网关很糟糕

问题描述 投票:1回答:1

我正在尝试使用带有docker swarm的traefik,但我在服务更新期间遇到了麻烦。我运行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应该是零停机时间。

怎么解决?

docker deployment load-balancing docker-swarm traefik
1个回答
0
投票

糟糕的网关意味着traefik被配置为转发请求,但它无法到达其配置使用的ip和端口上的容器。导致此问题的常见问题是:

  • traefik和不同码头网络上的服务
  • 服务存在于多个网络中,而traefik选择了错误的服务
  • 错误的端口用于连接到容器(使用容器端口并确保它在所有接口上监听,也就是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服务上保留重试选项,因此对停止容器的任何请求,或者只有健康检查未检测到的容器,都有机会尝试再次尝试。


这是我在我的环境中使用的结果撰写文件:

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如上所述。更改了映像名称,端口,网络名称等,以避免与我的环境中的其他内容冲突。

© www.soinside.com 2019 - 2024. All rights reserved.