【问题标题】:What is the alternative to condition form of depends_on in docker-compose Version 3?在 docker-compose 版本 3 中,depends_on 的条件形式的替代方案是什么?
【发布时间】:2017-12-08 08:57:19
【问题描述】:

docker-compose 2.1 提供了一个很好的功能来指定conditiondepends_on。当前的 docker-compose 文档状态:

版本 3 不再支持depends_on 的条件形式。

不幸的是,documentation 没有解释为什么 condition 表单被删除,并且缺乏关于如何使用 V3 更高版本实现该行为的任何具体建议。

【问题讨论】:

  • 伯纳德接受的答案在 2022 年不再成立。量子的答案现在是正确的 - 你还能改变它吗?

标签: docker docker-compose


【解决方案1】:

在 compose 中指定容器依赖项已经有所不同。它们仅在启动时有效,并且在运行时重新启动依赖容器时不起作用。相反,每个容器都应该包括在连接断开时重试重新连接到依赖服务的机制。许多用于连接数据库或 REST API 服务的库都具有可配置的内置重试。我会调查的。无论如何,生产代码都需要它。

【讨论】:

    【解决方案2】:

    1.27.0 开始,2.x 和 3.x 与 COMPOSE_SPEC 架构合并。

    version 现在是可选的。因此,您可以像以前一样删除它并指定condition

    services:
      web:
        build: .
        depends_on:
          redis:
            condition: service_healthy
      redis:
        image: redis
        healthcheck:
          test: ["CMD", "redis-cli", "ping"]
          interval: 1s
          timeout: 3s
          retries: 30
    

    【讨论】:

    • 它不适用于 docker-compose 1.29 和 docker stack deploy
    • 删除 version 字段可能会彻底改变 IDE 语法高亮处理 depends_on 长语法的方式,从红色出血变为正常。
    【解决方案3】:

    有一些外部工具可以让您模仿这种行为。例如,使用dockerize 工具,您可以用dockerize -wait 包装您的CMDENTRYPOINT,这将阻止您的应用程序在指定的服务准备好之前运行。

    如果您的 docker-compose 文件曾经看起来像这样:

    version: '2.1'
    services:
      kafka:
        image: spotify/kafka
        healthcheck:
          test: nc -z localhost 9092
      webapp:
         image: foo/bar # your image
         healthcheck:
           test: curl -f http://localhost:8080
      tests:
         image: bar/foo # your image
         command: YOUR_TEST_COMMAND
         depends_on:
           kafka:
             condition: service_healthy
           webapp:
             condition: service_healthy
    

    那么你可以在你的v3 compose 文件中使用dockerize,如下所示:

    version: '3.0'
    services:
      kafka:
        image: spotify/kafka
      webapp:
         image: foo/bar # your image
      tests:
         image: bar/foo # your image
         command: dockerize -wait tcp://kafka:9092 -wait web://webapp:8080 YOUR_TEST_COMMAND
    

    【讨论】:

      【解决方案4】:

      只是想在通过 docker-compose 运行 postgres 和应用程序时添加我的解决方案,我需要应用程序在开始之前等待 init sql 脚本完成。

      dockerize 似乎在等待 db 端口可用(端口 5432),这是 depends_on 的等价物,可在 docker 3 中使用:

      version: '3'
      
      services:
        app:
          container_name: back-end
          depends_on:
            - postgres
        postgres:
          image: postgres:10-alpine
          container_name: postgres
          ports:
            - "5432:5432"
          volumes:
            - ./docker-init:/docker-entrypoint-initdb.d/
      

      问题:

      如果您有一个大型初始化脚本,则应用程序将在该脚本完成之前启动,因为 depends_on 只等待数据库端口。

      虽然我同意解决方案应该在应用程序逻辑中实现,但我们遇到的问题仅适用于我们想要运行测试并使用测试数据预填充数据库时,因此在代码之外实现解决方案更有意义因为我倾向于不喜欢引入代码“让测试工作”

      解决方案:

      在 postgres 容器上实施健康检查。 对我来说,这意味着检查 pid 1 的命令是 postgres,因为它会在 init db 脚本运行时在 pid 1 上运行不同的命令

      在应用程序端编写一个脚本,等待postgres 变为healthy。脚本如下所示:

      #!/bin/bash
      function check {
        STATUS=\`curl -s --unix-socket /var/run/docker.sock http:/v1.24/containers/postgres/json | python -c 'import sys, json; print json.load('sys.stdin')["State"]["Health"]["Status"]'\`
      
        if [ "$STATUS" = "healthy" ]; then
          return 0
        fi
        return 1
      }
      
      until check; do
        echo "Waiting for postgres to be ready"
        sleep 5
      done
      
      echo "Postgres ready"
      

      然后 docker-compose 应该挂载脚本的目录,这样我们就不会为应用程序编辑 Dockerfile,如果我们使用自定义 postgres 映像,这样我们就可以继续为您的应用程序使用 docker 文件已发布图片。

      我们还覆盖了应用程序的 docker 文件中定义的入口点,以便我们可以在应用程序启动之前运行等待脚本

      version: '3'
      
      services:
        app:
          container_name: back-end
          entrypoint: ["/bin/sh","-c","/opt/app/wait/wait-for-postgres.sh && <YOUR_APP_START_SCRIPT>"]
          depends_on:
            - postgres
          volumes:
            - //var/run/docker.sock:/var/run/docker.sock
            - ./docker-scripts/wait-for-postgres:/opt/app/wait
        postgres:
          image: postgres:10-alpine
          container_name: postgres
          ports:
            - "5432:5432"
          volumes:
            - ./docker-init:/docker-entrypoint-initdb.d/
            - ./docker-scripts/postgres-healthcheck:/var/lib
          healthcheck:
            test: /var/lib/healthcheck.sh
            interval: 5s
            timeout: 5s
            retries: 10
      

      【讨论】:

      • 投反对票,因为使 docker 套接字可访问会降低安全性。
      【解决方案5】:

      如果在尝试访问可能未处于就绪状态的容器时收到连接错误,请考虑故意退出容器化应用程序,而不是依赖另一个容器来启动。这种策略与容器的适当重启策略一起使用将重启应用程序容器,直到连接可用或满足不同的条件。

      或者,如果您希望等待特定的时间,可以使用一些不错的实用程序,例如 wait-for-it。这是一个很好的 example 在 mssql 容器中使用 wait-for-it

      【讨论】:

        【解决方案6】:

        我到达这个页面是因为一个容器不会等待依赖的那个,我必须运行docker system prune 才能让它工作。有一个orphaned container 错误提示我运行prune

        【讨论】:

          猜你喜欢
          • 2014-01-01
          • 2020-08-04
          • 1970-01-01
          • 2021-04-18
          • 2020-05-09
          • 1970-01-01
          • 2021-11-13
          • 2018-12-01
          • 1970-01-01
          相关资源
          最近更新 更多