如何让nginx等待我的上游服务在Docker Swarm中启动?

时间:2017-02-13 11:10:09

标签: ruby-on-rails nginx docker-swarm-mode

我将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文件中有 depends 部分 - 应用服务可能不是完全(?)在nginx服务启动时准备就绪,所以当上游服务配置部分尝试DNS解析“app: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启动时它还无法正确解析我的swarm服务app:3000 - 而是试图通过流量到IP地址....

BTW - 如果我重新启动我的虚拟机也会出现同样的情况 - 当docker(在群集模式下)再次启动服务时 - 我最终会遇到同样的问题。重新启动nginx容器可以解决问题。

3 个答案:

答案 0 :(得分:6)

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

首先,在使用

部署堆栈时,似乎并未真正使用 depends_on 选项
docker stack deploy -c docker-compose.yml mystack

群集模式下的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解析。

因此,通过这种方式,我将“丢失的” depends_on 行为“整合”在一起,可以在swarm模式下工作。

答案 1 :(得分:1)

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

还有两个选项。

  1. 从Compose v2.1开始,可以在depends_on选项中包含healthcheck。 https://docs.docker.com/compose/compose-file/compose-file-v2/#dependson
  2. 您可以使用dockerizewait-for-it等外部工具执行相同操作。

答案 2 :(得分:0)

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

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