13

我将一个 nginx 代理服务和一个 rails 应用程序服务部署到一个 docker swarm 中。nginx 依赖于我的 docker-compose 文件中的应用程序。

我的 nginx.conf 文件将流量定向到我的上游应用程序服务(暴露在端口 3000),就像这样(仅显示上游部分)。

upstream puma {
  server app:3000;
}

我的 docker-compose 文件如下所示:

version: '3.1'

services:

  app:
    image: my/rails-app:latest
    networks:
      - proxy

  web:
    image: my/nginx:1.11.9-alpine
    command: /bin/sh -c "nginx -g 'daemon off;'"
    ports:
      - "80:80"
    depends_on:
      - app
    networks:
      - proxy


networks:

  proxy:
    external: true

我的主机设置为群管理器。

这一切都很好 - 没有问题。

但是,即使我的 docker-compose 文件中有一个依赖部分 - 到 nginx 服务启动时,应用程序服务可能还没有完全(?)准备好,所以当上游服务配置部分尝试 DNS 解析“应用程序: 3000",似乎没有完全找到它。因此,当我访问我的网站时,我在我的 nginx 日志中发现以下错误消息:

2017/02/13 10:46:07 [error] 8#8: *6 connect() failed (111: Connection refused) while connecting to upstream, client: 10.255.0.3, server: www.mysite.com, request: "GET / HTTP/1.1", upstream: "http://127.0.53.53:3000/", host: "preprod.local"

如果我杀死正在运行 nginx 服务的 docker 容器,然后 swarm 稍后重新安排它并返回,如果我然后访问相同的 URL,它就可以完全正常工作,并且请求成功地向上传递到 app:3000。

我怎样才能防止这种情况发生 - 启动时间有点过时并且在 nginx 启动时它还无法正确解析我的名为 app:3000 的群服务 - 相反它正试图将流量传递到一个IP地址....

顺便说一句 - 如果我重新启动我的虚拟机也会发生同样的情况 - 当 docker(在 swarm 模式下)再次启动服务时 - 我可能会遇到同样的问题。重启 nginx 容器即可解决问题。

4

3 回答 3

7

我已经找到了一种方法来做到这一点 - 这是使用 Dockerfile 或 docker-compose 文件的HEALTHCHECK部分。

首先,似乎在部署堆栈时并没有真正使用depends_on选项

docker stack deploy -c docker-compose.yml mystack

如果服务任务无法正常启动或由于其他原因失败,则处于 swarm 模式的 Docker 只会重新启动服务任务。因此,depends_on选项并没有那么有用。

所以这最终是我的解决方案,到目前为止效果很好:

version: '3.1'

services:

  app:
    image: my/rails-app:latest
    networks:
      - proxy

  web:
    image: my/nginx:1.11.9-alpine
    command: /bin/sh -c "nginx -g 'daemon off;'"
    ports:
      - "80:80"
    networks:
      - proxy
    healthcheck:
        test: ["CMD", "wget", "-qO-", "http://localhost/healthcheck"]
        interval: 5s
        timeout: 3s
        retries: 3

networks:

  proxy:
    external: true

所以我所做的是,我尝试从 nginx 服务器访问我的 Rails 应用程序上的路由 - 我创建了一个名为 /healthcheck 的路由,它返回的状态代码为 200。

因此,当我尝试访问它时,结果是失败(应用服务器尚未准备好)- nginx 将重新启动。希望当它再次启动时,应用服务器将可用,并且上游 app:3000 指令将进行正确的 DNS 解析。

因此,通过这种方式,我将可以在 swarm 模式下工作的(缺失的)depends_on行为“破解”在一起。

于 2017-02-13T13:18:15.280 回答
4

depends_on选项不等待容器准备好,直到它运行。https://docs.docker.com/compose/startup-order/

还有两个选择。

  1. 从 Compose v2.1 开始,可以在 depends_on 选项中包含健康检查。https://docs.docker.com/compose/compose-file/compose-file-v2/#dependson
  2. 您可以使用dockerizewait-for-it 等外部工具执行相同操作。
于 2017-05-02T20:01:34.210 回答
0

您可以使用此图像:https ://hub.docker.com/r/atomgraph/nginx

它支持$UPSTREAM_SERVER$TIMEOUT参数(作为环境变量)。

于 2019-11-06T22:29:10.320 回答