在容器内运行服务时,让我们说mongodb,命令
docker run -d myimage
将立即退出,并返回容器ID。
在我的CI脚本中,我在运行mongo容器后立即运行客户端来测试mongodb连接。
问题是:客户端无法连接,因为服务尚未启动。
除了在我的脚本中添加一个大sleep 10
之外,我没有看到任何等待容器启动和运行的选项。
Docker有一个命令wait
,在这种情况下不起作用,因为容器不存在。
这是码头工人的限制吗?
感谢
答案 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-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,可以查看my docker synchronization POC。我在其他问题中结合了一些想法(感谢你 - 赞成)。
基本思想是组合中的每个容器都公开诊断服务。调用此服务会检查容器中是否打开了所需的端口集,并返回容器的整体状态(根据POC进行WARMUP / RUNNING)。每个容器还有一个实用程序,用于在启动时检查依赖服务是否已启动并正在运行。只有这样容器才会启动。
在示例docker-compose环境中,有两个服务 server1 和 server2 以及 client 服务等待两个服务器启动然后向他们发送请求并退出。
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