Ruby on rails 如何让nginx等待上游服务在Docker Swarm中启动?

Ruby on rails 如何让nginx等待上游服务在Docker Swarm中启动?,ruby-on-rails,nginx,docker-swarm-mode,Ruby On Rails,Nginx,Docker Swarm Mode,我在docker swarm中部署了一个nginx代理服务和一个rails应用程序服务。nginx取决于我的docker compose文件中的应用程序 我的nginx.conf文件将流量定向到我的上游应用程序服务(在端口3000上公开),如下所示(仅显示上游部分) 我的docker compose文件如下所示: version: '3.1' services: app: image: my/rails-app:latest networks: - proxy

我在docker swarm中部署了一个nginx代理服务和一个rails应用程序服务。nginx取决于我的docker compose文件中的应用程序

我的nginx.conf文件将流量定向到我的上游应用程序服务(在端口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
我的主机设置为swarm manager

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

然而,即使我的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地址


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

我已经找到了一种方法,这就是使用Dockerfile或docker compose文件的HEALTHCHECK部分

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

docker stack deploy -c docker-compose.yml mystack
swarm模式下的Docker只会在服务任务无法正常启动或由于其他原因失败时重新启动服务任务。因此,依赖选项并不是很有用

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

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模式下工作的行为“黑客”在一起。

依赖于选项不等待容器准备就绪,只等待容器运行

还有两个选择

  • 从Compose v2.1开始,可以包括healthcheck in depend_on选项
  • 您可以使用诸如或之类的外部工具执行相同的操作
  • 您可以使用此图像:


    它支持
    $UPSTREAM\u SERVER
    $TIMEOUT
    参数(作为环境变量)。

    您还可以使用
    部署
    部分中的
    重启
    选项。然后nginx容器将在rails应用程序关闭时重新启动。顺便问一下,你为什么要勾选
    http://localhost/healthcheck
    url非
    http://app/healthcheck
    ?将
    http://app/healthcheck
    healthcheck是否正确?我还没有尝试过这个url——但按照我的理解,如果我使用,那么我就是通过nginx容器点击我的Rails应用程序——这就是我要检查的连接。因此,使用localhost版本可能更健壮一些。作为重启选项(我不确定这将如何解决问题),您能解释一下吗?>使用localhost版本可能会更健壮一些。我不同意这一点。虽然它可以工作,但这意味着在正确设置所有容器之前,几个容器将处于退出状态。我希望有一个解决方案可以确保nginx在代理准备好之前不会启动,但我想除了使用
    等待它
    或它的兄弟姐妹之外,没有其他解决方案。如果您有多个服务,那么这将无法真正起作用,而且在部署时不允许在本地和远程使用这些服务
    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