我如何等待docker容器启动并运行?

时间:2014-01-17 10:07:47

标签: docker

在容器内运行服务时,让我们说mongodb,命令

docker run -d myimage

将立即退出,并返回容器ID。 在我的CI脚本中,我在运行mongo容器后立即运行客户端来测试mongodb连接。 问题是:客户端无法连接,因为服务尚未启动。 除了在我的脚本中添加一个大sleep 10之外,我没有看到任何等待容器启动和运行的选项。

Docker有一个命令wait,在这种情况下不起作用,因为容器不存在。 这是码头工人的限制吗? 感谢

14 个答案:

答案 0 :(得分:32)

similar issue中为docker 1.12评论

  

The convention are as follow - MinOccur = 0 --> the element can be abscent in input , and can be present MinOccur = 1 --> the element must be there in input (but if you use it, then your java generated member will be of list type - list of ENUM for Int ) If you don't write MinOccur in attributes - then it makes the element mandatory , ( then you java generated member will be of simply ENUM for int ) MaxOccur = 1 --> minimum one element can be there in input (but if you use it, then your java generated member will be of list type - list of ENUM for Int ) MaxOccur = unbound --> only one element can be there in input (if you use it, then your java generated member will be of list type - list of ENUM for Int ) <xs:complexType name="wsData"> <xs:sequence> <xs:element name="month" type="xmlMonthType" minOccurs="1" nillable="false" /> <xs:element name="userLogin" type="xs:string" minOccurs="0" /> </xs:sequence> </xs:complexType> <xs:simpleType name="xmlMonthType"> <xs:restriction base="xs:int"> <xs:enumeration value="1"/> <xs:enumeration value="2"/> <xs:enumeration value="3"/> <!-- ... months 4 ~9 ... --> <xs:enumeration value="10"/> <xs:enumeration value="11"/> <xs:enumeration value="12"/> </xs:restriction> </xs:simpleType> 支持在docker/docker#23218上游合并 - 这可以被认为是在订单开始下一个容器之前确定容器是否健康

docker 1.12rc3 (2016-07-14)

以来可以使用

docker-compose is in the process支持等待特定条件的功能。

  

它使用HEALTHCHECK(因此我不必重建docker交互)并为此添加了一堆配置命令。请在此处查看:https://github.com/dansteen/controlled-compose

您可以在Dockerfile中使用它,如下所示:

libcompose

官方文档:https://docs.docker.com/engine/reference/builder/#/healthcheck

答案 1 :(得分:30)

找到这个简单的解决方案,一直在寻找更好的东西,但没有运气......

until [ "`/usr/bin/docker inspect -f {{.State.Running}} CONTAINERNAME`"=="true" ]; do
    sleep 0.1;
done;

或者如果您想等到容器报告为健康(假设您有健康检查)

until [ "`/usr/bin/docker inspect -f {{.State.Health.Status}} CONTAINERNAME`"=="healthy" ]; do
    sleep 0.1;
done;

答案 2 :(得分:27)

如果您不想公开端口,如果您计划链接容器并且可能正在运行多个实例进行测试,那么我发现这是在一行中执行此操作的好方法:)此示例基于等待ElasticSearch准备就绪:

docker inspect --format '{{ .NetworkSettings.IPAddress }}:9200' elasticsearch | xargs wget --retry-connrefused --tries=5 -q --wait=3 --spider

这需要wget可用,这是Ubuntu的标准配置。它将在尝试之间重试5次,3秒,即使连接被拒绝,也不会下载任何内容。

答案 3 :(得分:23)

如果您启动的容器化服务不一定能很好地响应curl或wget请求(这很可能适用于许多服务),那么您可以使用nc代替。

这是来自主机脚本的片段,它启动Postgres容器并在继续之前等待它可用:

POSTGRES_CONTAINER=`docker run -d --name postgres postgres:9.3`
# Wait for the postgres port to be available
until nc -z $(sudo docker inspect --format='{{.NetworkSettings.IPAddress}}' $POSTGRES_CONTAINER) 5432
do
    echo "waiting for postgres container..."
    sleep 0.5
done

编辑 - 此示例不要求您对正在测试的端口进行EXPOSE,因为它访问Docker为容器分配的“私有”IP地址。 然而这仅在docker主机守护程序正在侦听环回(127.x.x.x)时才有效。如果(例如)您在Mac上运行boot2docker VM,则无法使用此方法,因为您无法从Mac shell路由到容器的“私有”IP地址。

答案 4 :(得分:15)

假设您知道MongoDB服务器的主机+端口(或者因为您使用了-link,或者因为您使用-e注入了它们),您只需使用curl即可检查MongoDB服务器是否正在运行并接受连接。

以下代码段将尝试每秒连接,直到成功:

#!/bin/sh
while ! curl http://$DB_PORT_27017_TCP_ADDR:$DB_PORT_27017_TCP_PORT/
do
  echo "$(date) - still trying"
  sleep 1
done
echo "$(date) - connected successfully"

答案 5 :(得分:9)

我最终得到了类似的东西:

#!/bin/bash

attempt=0
while [ $attempt -le 59 ]; do
    attempt=$(( $attempt + 1 ))
    echo "Waiting for server to be up (attempt: $attempt)..."
    result=$(docker logs mongo)
    if grep -q 'waiting for connections on port 27017' <<< $result ; then
      echo "Mongodb is up!"
      break
    fi
    sleep 2
done

答案 6 :(得分:8)

在那里投掷我自己的解决方案:

我正在使用泊坞网络,因此Mark's netcat trick对我不起作用(无法从主机网络访问),Erik's idea不适用于postgres容器(容器标记为尽管postgres尚无法连接,但仍在运行。所以我只是试图通过循环中的短暂容器连接到postgres:

#!/bin/bash

docker network create my-network
docker run -d \
    --name postgres \
    --net my-network \
    -e POSTGRES_USER=myuser \
    postgres

# wait for the database to come up
until docker run --rm --net my-network postgres psql -h postgres -U myuser; do
    echo "Waiting for postgres container..."
    sleep 0.5
done

# do stuff with the database...

答案 7 :(得分:2)

我不得不重新解决这个问题并提出了一个想法。在做这项任务的研究时,我来到这里,所以我想我会与这篇文章的未来访客分享我的解决方案。

基于Docker-compose的解决方案

如果您使用的是docker-compose,可以查看my docker synchronization POC。我在其他问题中结合了一些想法(感谢你 - 赞成)。

基本思想是组合中的每个容器都公开诊断服务。调用此服务会检查容器中是否打开了所需的端口集,并返回容器的整体状态(根据POC进行WARMUP / RUNNING)。每个容器还有一个实用程序,用于在启动时检查依赖服务是否已启动并正在运行。只有这样容器才会启动。

在示例docker-compose环境中,有两个服务 server1 server2 以及 client 服务等待两个服务器启动然后向他们发送请求并退出。

摘自POC

wait_for_server.sh

#!/bin/bash

server_host=$1
sleep_seconds=5

while true; do
    echo -n "Checking $server_host status... "

    output=$(echo "" | nc $server_host 7070)

    if [ "$output" == "RUNNING" ]
    then
        echo "$server_host is running and ready to process requests."
        break
    fi

    echo "$server_host is warming up. Trying again in $sleep_seconds seconds..."
    sleep $sleep_seconds
done

等待多个容器:

trap 'kill $(jobs -p)' EXIT

for server in $DEPENDS_ON
do
    /assets/wait_for_server.sh $server &
    wait $!
done

诊断服务基本实现( checkports.sh ):

#!/bin/bash

for port in $SERVER_PORT; do
    nc -z localhost $port;

    rc=$?

    if [[ $rc != 0 ]]; then
        echo "WARMUP";
        exit;
    fi
done

echo "RUNNING";

将诊断服务连接到端口:

nc -v -lk -p 7070 -e /assets/checkports.sh

答案 8 :(得分:1)

test/test_runner

#!/usr/bin/env ruby

$stdout.sync = true

def wait_ready(port)
  until (`netstat -ant | grep #{port}`; $?.success?) do
    sleep 1
    print '.'
  end
end

print 'Running supervisord'
system '/usr/bin/supervisord'

wait_ready(3000)

puts "It's ready :)"

$ docker run -v /tmp/mnt:/mnt myimage ruby mnt/test/test_runner

我正在测试端口是否正在侦听。 在这种情况下,我测试从容器内部运行,但也可以从外部判断mongodb是否准备就绪。

$ docker run -p 37017:27017 -d myimage

检查端口37017是否正在侦听主机容器。

答案 9 :(得分:0)

您可以使用wait-for-it,“一个纯粹的bash脚本,它将等待主机和TCP端口的可用性。它可用于同步相互依赖的服务的启动,例如链接的docker容器。因为它是纯粹的bash脚本,所以它没有任何外部依赖“。

但是,您应该尝试设计服务以避免服务之间的这种相互依赖性。您的服务可以尝试重新连接到数据库吗?如果它不能连接到数据库并让容器协调器(例如Docker Swarm)为你做容器,你可以让你的容器死掉吗?

答案 10 :(得分:0)

Docker-compose解决方案

在docker-compose之后,我不知道docker容器的名称,所以我使用

docker inspect -f {{.State.Running}} $(docker-compose ps -q <CONTAINER_NAME>)

并像这里https://stackoverflow.com/a/33520390/7438079一样检查true

答案 11 :(得分:0)

对于mongoDB docker实例,我们做到了,并且像一个超级按钮一样工作:

#!/usr/bin/env bash

until docker exec -i ${MONGO_IMAGE_NAME} mongo -u ${MONGO_INITDB_ROOT_USERNAME} -p ${MONGO_INITDB_ROOT_PASSWORD}<<EOF
exit
EOF
do
    echo "Waiting for Mongo to start..."
    sleep 0.5
done

答案 12 :(得分:0)

为了验证 PostgreSQL MySQL (当前)Docker容器是否已启动并正在运行(特别是用于Flyway等迁移工具),可以使用等待二进制文件:https://github.com/ArcanjoQueiroz/wait-for

答案 13 :(得分:0)

这是我最终得到的结果,与之前的答案类似,只是更简洁一些,

until [[ $(docker logs $db_container_name) == *"waiting for connections on port 27017"* ]]
do
  echo "waiting on mongo to boot..."
  sleep 1
done
相关问题