我正在尝试将 traefik 与 docker swarm 一起使用,但在服务更新期间遇到了麻烦。我运行 stack deploy
或 service 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 在容器准备好接收请求之前或在它们被停止时命中容器。
您可以使用运行状况检查配置容器,并使用如下所示的 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/