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

Gra*_*vis 74 mongodb docker

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

docker run -d myimage
Run Code Online (Sandbox Code Playgroud)

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

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

sup*_*ero 43

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

until [ "`/usr/bin/docker inspect -f {{.State.Running}} CONTAINERNAME`"=="true" ]; do
    sleep 0.1;
done;
Run Code Online (Sandbox Code Playgroud)

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

until [ "`/usr/bin/docker inspect -f {{.State.Health.Status}} CONTAINERNAME`"=="healthy" ]; do
    sleep 0.1;
done;
Run Code Online (Sandbox Code Playgroud)

  • 一个使用while循环的衬里,而不是```while [“`docker inspect -f {{.State.Health.Status}} $ container_id`”!=“”健康“]; 睡2 完成``` (2认同)
  • 在我的 shell 中,我必须使用这样的空格... CONTAINERNAME`" == "healthy" (2认同)

Von*_*onC 38

正如在docker 1.12 的类似问题中所评论的那样

HEALTHCHECK根据docker/docker#23218将支持合并到上游- 可以考虑在开始下一个容器之前确定容器是否健康

这是自docker 1.12rc3(2016-07-14)以来可用的

docker-compose正在支持等待特定条件的功能.

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

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

HEALTHCHECK --interval=5m --timeout=3s \
  CMD curl -f http://localhost/ || exit 1
Run Code Online (Sandbox Code Playgroud)

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


小智 30

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

docker inspect --format '{{ .NetworkSettings.IPAddress }}:9200' elasticsearch | xargs wget --retry-connrefused --tries=5 -q --wait=3 --spider
Run Code Online (Sandbox Code Playgroud)

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


Mar*_*ood 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
Run Code Online (Sandbox Code Playgroud)

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


jpe*_*zzo 16

假设您知道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"
Run Code Online (Sandbox Code Playgroud)

  • 但是你需要绑定主机上的端口:( (2认同)

Gra*_*vis 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
Run Code Online (Sandbox Code Playgroud)


Ell*_*eal 8

扔掉我自己的解决方案:

我正在使用docker网络,因此Mark的netcat技巧对我不起作用(无法从主机网络访问),而且Erik的想法对于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...
Run Code Online (Sandbox Code Playgroud)


Fab*_*lin 6

如果您想等待打开的端口,可以使用这个简单的脚本:

until </dev/tcp/localhost/32022; do sleep 1; done
Run Code Online (Sandbox Code Playgroud)

等待端口 32022 能够连接。