【问题标题】:Bash script command to wait until docker-compose process has finished before moving onBash 脚本命令要等到 docker-compose 进程完成后再继续
【发布时间】:2019-12-22 04:38:00
【问题描述】:

我们有一个安装程序的 bash 脚本,其中包括运行 docker-compose 文件。其中一项服务 RabbitMQ 需要一些时间来加载,我需要一个命令来等待它加载,然后再加载其他服务。我们使用的是sleep 命令,但我们的客户使用不同的笔记本电脑,因此加载某些笔记本电脑的时间比其他笔记本电脑要长。有没有办法在不使用sleep 命令的情况下将其保留到完成加载服务然后继续下一个服务?我在下面包含了脚本的一部分。谢谢!

# Execute applications
cd /opt/program
docker-compose up -d
echo "waiting for message queue..."
sleep 15

echo "starting ingest manager"

cd /opt/program/scripts
chmod +x start-manager.sh
./start-manager.sh &

【问题讨论】:

    标签: linux bash docker docker-compose


    【解决方案1】:

    docker-compose up -d 命令在后台以“分离模式”运行,但我猜您的设置至少公开了一个 Web 服务…… 如果是,您可以依靠wait-for-it 等工具精确地等待该服务准备就绪。

    首先,下载并检查此脚本:

    https://github.com/vishnubob/wait-for-it/raw/master/wait-for-it.sh

    接下来,假设您的 docker-compose.yml 设置在 localhost:9090 公开了一个 Web 服务:

    version: 3
    services:
      frontend:
        image: user/image
        ports:
          - '9090:8080'
    

    您可以重构您的 Bash 脚本(例如命名为 run.sh),如下所示:

    #!/bin/bash
    
    # retrieve and remember the directory where is stored this script
    srcdir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )
    # we assume the script "wait-for-it.sh" is also in this directory
    
    # Execute applications
    cd /opt/program
    docker-compose up -d
    
    # Change the working directory now
    cd /opt/program/scripts
    chmod +x start-manager.sh
    
    echo "waiting for message queue..."
    "$srcdir/wait-for-it.sh" -h localhost -p 9090 -s -t 0 -- ./start-manager.sh
    

    有关更多详细信息,请参阅一些在线文档。可通过https://github.com/vishnubob/wait-for-it#readme获得

    【讨论】:

      【解决方案2】:

      首先,您需要在 docker-compose.yaml 中确定 rabbitmq 容器的具体名称,方法是添加:

      version: "3"
      
      services:
              web:
                      image: rabbitmq:latest
                      container_name: rabbitmq
      

      到服务块

      脚本会是这样的:

      #!/bin/bash
      cd /opt/program
      docker-compose up -d
      echo "waiting for message queue..."
      
      rabbitmq_status() { 
              docker exec -it rabbitmq rabbitmqctl status
      }
      
      rabbitmq_status
      
      if [ $? -eq 0 ]
      then
              echo "starting ingest manager"
              cd /opt/program/scripts
              chmod +x start-manager.sh
              ./start-manager.sh &
      else
              echo "rabbitmq container is not running"
      fi
      

      在rabbitmq容器启动并运行之前不会进入下一步。

      【讨论】:

      • 使用docker-compose exec $service而不是docker exec你不需要依赖在docker-compose.yml中设置的静态容器
      【解决方案3】:

      如其他答案中所述,您必须对容器进行特定于应用程序的准备情况检查。就我个人而言,我更喜欢将这些检查/脚本与容器图像一起提供,例如通过将wait-for-it.sh(参见ErikMD's answer)或类似脚本添加到图像并在运行的容器中执行它们,例如与docker exec(由Ahmed Arafa's answer提议)。

      这比在主机上运行检查有一些优势:

      • 您可以为容器映像提供所有必需的脚本和依赖项
      • 您不需要对主机做任何假设(例如,通过 api 端点进行测试时:wget/curl 是否在主机上可用,甚至是 bash/shell?是 @987654330 @/docker-compose 命令在与 docker 守护进程相同的主机上执行,即你能通过localhost 到达容器吗?)
      • 您不必为了检查容器状态而向外界公开任何端口/端点
      • 您可以为不同版本的图像提供不同的检查脚本,而无需修改启动脚本

      因此,要将此方法应用于您的示例,只需添加一个脚本 - 例如is_ready.sh - 到图像,在容器中使用docker-compose exec 执行它并根据它的退出状态采取行动:

      # Execute applications
      cd /opt/program
      docker-compose up -d
      echo "waiting for message queue..."
      
      while ! docker-compose exec rabbitmq /is_ready.sh; do sleep 1; done
      
      echo "starting ingest manager"
      
      cd /opt/program/scripts
      chmod +x start-manager.sh
      ./start-manager.sh &
      

      is_ready.sh 可能如下所示:

      #!/bin/bash
      
      rabbitmqctl status
      

      沿着这条路走得更远,您可以利用dockerdocker-compose 的原生健康检查功能。有了这些docker,就会自动执行定义好的健康检查脚本/命令,并在容器状态中指示当前的健康状况。

      合并到您的脚本中可能如下所示:

      # Execute applications
      cd /opt/program
      docker-compose up -d
      echo "waiting for message queue..."
      
      is_healthy() {
          service="$1"
          container_id="$(docker-compose ps -q "$service")"
          health_status="$(docker inspect -f "{{.State.Health.Status}}" "$container_id")"
      
          if [ "$health_status" = "healthy" ]; then
              return 0
          else
              return 1
          fi
      }
      
      while ! is_healthy rabbitmq; do sleep 1; done
      
      echo "starting ingest manager"
      
      cd /opt/program/scripts
      chmod +x start-manager.sh
      ./start-manager.sh &
      

      使用docker-compose.yml 中定义的健康检查

      ...
      services:
        rabbitmq:
          ...
          healtcheck:
            test: rabbitmqctl status      
      

      对于更复杂的运行状况检查,您还可以向图像添加更长的脚本并执行它。

      【讨论】:

      • 谢谢!这实际上有效,除了rabbitmqctl状态,我使用rabbitmqctl等待超时,并且rabbit正在运行以获取pid。非常感谢您的帮助!
      猜你喜欢
      • 2014-12-17
      • 2012-02-07
      • 1970-01-01
      • 2013-04-25
      • 2019-11-01
      • 2016-06-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多