[mongodb] Docker 컨테이너가 실행될 때까지 어떻게 기다릴 수 있습니까?

컨테이너 내부에서 서비스를 실행할 때 mongodb, 명령

docker run -d myimage

즉시 종료하고 컨테이너 ID를 반환합니다. 내 CI 스크립트에서 mongo 컨테이너를 실행 한 직후 클라이언트를 실행하여 mongodb 연결을 테스트합니다. 문제는 서비스가 아직 시작되지 않았기 때문에 클라이언트가 연결할 수 없다는 것입니다. sleep 10내 스크립트에 큰 것을 추가하는 것 외에 컨테이너가 실행될 때까지 기다리는 옵션이 없습니다.

Docker에는 wait컨테이너가 없기 때문에이 경우 작동하지 않는 명령 이 있습니다. 도커의 한계입니까?



답변

docker 1.12 에 대한 유사한 문제 에서 언급했듯이

HEALTHCHECK지원은 도커 / 도커에 따라 업스트림으로 병합 됩니다.

docker 1.12rc3 (2016-07-14) 부터 사용할 수 있습니다.

docker-compose프로세스에 특정 조건 기다려야하는 기능을 지원.

그것은 libcompose(그래서 나는 도커 상호 작용을 다시 만들 필요가 없음)이를 위해 많은 구성 명령을 추가합니다. 여기에서 확인하세요 : https://github.com/dansteen/controlled-compose

다음과 같이 Dockerfile에서 사용할 수 있습니다.

HEALTHCHECK --interval=5m --timeout=3s \
  CMD curl -f http://localhost/ || exit 1

공식 문서 : https://docs.docker.com/engine/reference/builder/#/healthcheck


답변

이 간단한 해결책을 찾았고 더 나은 것을 찾고 있었지만 운이 없었습니다 …

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;


답변

컨테이너를 연결할 계획이고 테스트를 위해 여러 인스턴스를 실행할 수있는 경우와 같이 포트를 노출하지 않으려면 이것이 한 줄로 수행하는 좋은 방법이라는 것을 알았습니다. :)이 예제는 다음과 같습니다. ElasticSearch가 준비 될 때까지 기다림을 기준으로합니다.

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

이를 위해서는 Ubuntu에서 표준 인 wget을 사용할 수 있어야합니다. 연결이 거부 되더라도 5 회, 3 초 간격으로 재 시도하고 아무것도 다운로드하지 않습니다.


답변

시작한 컨테이너화 된 서비스가 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

편집 -이 예에서는 컨테이너에 대해 Docker가 할당 한 ‘개인’IP 주소에 액세스하므로 테스트중인 포트를 노출 할 필요가 없습니다. 그러나 이것은 도커 호스트 데몬이 루프백 (127.xxx)을 수신하는 경우에만 작동합니다. 예를 들어 Mac에서 boot2docker VM을 실행하는 경우 Mac 셸에서 컨테이너의 ‘비공개’IP 주소로 라우팅 할 수 없기 때문에이 방법을 사용할 수 없습니다.


답변

MongoDB 서버의 호스트 + 포트를 알고 있다고 가정하면 (을 사용했거나을 -link주입했기 때문에 -e) curlMongoDB 서버가 실행 중이고 연결을 수락하는지 확인하는 데 사용할 수 있습니다 .

다음 스 니펫은 성공할 때까지 매초마다 연결을 시도합니다.

#!/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"


답변

나는 다음과 같은 결과를 얻었습니다.

#!/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


답변

내 자신의 솔루션을 던지고 있습니다.

도커 네트워크를 사용하고 있으므로 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...