Подтвердить что ты не робот

Как я могу ждать, пока контейнер докеров будет запущен и запущен?

При запуске службы внутри контейнера, скажем, mongodb, команда

docker run -d myimage

мгновенно завершит работу и вернет идентификатор контейнера. В моем скрипте CI я запускаю клиент для проверки соединения mongodb сразу после запуска контейнера mongo. Проблема в том, что клиент не может подключиться, потому что служба еще не запущена. Помимо добавления большого sleep 10 в мой скрипт, я не вижу никакой возможности ждать, пока контейнер будет запущен и работает.

У Docker есть команда wait, которая в этом случае не работает, потому что контейнер не существует. Это ограничение докера?

4b9b3361

Ответ 1

Как прокомментировано в аналогичной проблеме для докера 1.12

HEALTHCHECK поддержка сливается вверх по течению docker/docker # 23218 - это можно считать определением, когда контейнер полезен до начиная с следующего в порядке

Это доступно, так как docker 1.12rc3 (2016-07-14)

docker-compose находится в процессе поддержки функциональности для ожидания определенных условий.

Он использует libcompose (поэтому мне не нужно перестраивать взаимодействие докеров) и добавляет для этого набор команд конфигурации. Посмотрите здесь: https://github.com/dansteen/controlled-compose

Вы можете использовать его в файле Docker, например:

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

Официальные документы: https://docs.docker.com/engine/reference/builder/#/healthcheck

Ответ 2

Нашел это простое решение, искал что-то лучшее, но не повезло...

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;

Ответ 3

Если вы не хотите раскрывать порты, как и в случае, если вы планируете связать контейнер и, возможно, запускаете несколько экземпляров для тестирования, я обнаружил, что это хороший способ сделать это в одной строке:) Этот пример основан на ожидании готовности ElasticSearch:

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

Для этого требуется, чтобы wget был доступен, что является стандартным для Ubuntu. Он будет повторять попытку 5 раз, 3 секунды между попытками, даже если соединение отказано, а также ничего не загружает.

Ответ 4

Если запущенная контейнерная служба не всегда хорошо реагирует на завивки или запросы wget (что вполне вероятно для многих служб), вы можете вместо этого использовать nc.

Здесь находится фрагмент от хоста script, который запускает контейнер 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-адресу 'private' для контейнера. Однако это работает, только если демон хост-докера прослушивает loopback (127.x.x.x). Если (например) вы находитесь на Mac и запускаете виртуальную машину boot2docker, вы не сможете использовать этот метод, поскольку вы не можете перенаправить на 'private' IP-адреса контейнеров из оболочки Mac.

Ответ 5

Предполагая, что вы знаете порт хоста + вашего сервера 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"

Ответ 6

У меня получилось что-то вроде:

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

Ответ 7

Бросив мое собственное решение:

Я использую 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...

Ответ 8

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 ready :)"

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

Я тестирую, как порт прослушивает или нет. В этом случае у меня есть тест, запускаемый из внутреннего контейнера, но также возможно извне, готов ли mongodb или нет.

$ docker run -p 37017:27017 -d myimage

И проверьте, прослушивает ли порт 37017 или нет из контейнера-хоста.

Ответ 9

Мне пришлось заняться этой репетицией и придумал идею. Когда я занимался исследованиями для этой задачи, я пришел сюда, поэтому я решил поделиться своим решением с будущими посетителями этого сообщения.

Решение на основе Docker-compose

Если вы используете docker-compose, вы можете проверить мой протокол синхронизации докеров. Я объединил некоторые идеи в других вопросах (спасибо за это - поддержал).

Основная идея заключается в том, что каждый контейнер в составе предоставляет диагностическую службу. Вызов этой службы проверяет, открыт ли в контейнере необходимый набор портов и возвращает общий статус контейнера (WARMUP/RUNNING в соответствии с POC). В каждом контейнере также есть утилита для проверки при запуске, если зависимые службы запущены и работают. Только после этого контейнер запускается.

В приведенной ниже примерной среде для докеры есть две службы server1 и server2, а клиентская служба, ожидающая запуска обоих серверов, отправляет запрос обоим из них и выходит.

Выдержка из 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

Основная реализация диагностической srervice (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

Ответ 10

Вы можете использовать wait-for-it, "чистый bash script, который будет ждать наличия хоста и TCP порт. Это полезно для синхронизации разворота взаимозависимых сервисов, таких как связанные контейнеры докеров. Поскольку это чистый bash script, он не имеет внешних зависимостей".

Однако вы должны попытаться разработать свои службы, чтобы избежать такой взаимозависимости между службами. Может ли ваша служба попытаться подключиться к базе данных? Можете ли вы позволить своему контейнеру просто умереть, если он не может подключиться к базе данных, и разрешить для вас использовать контейнерный оркестр (например, Docker Swarm)?

Ответ 11

Docker-составьте решение

После docker-compose я не знаю имя контейнера docker, поэтому использую

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

и проверка true как здесь fooobar.com/questions/151972/...

Ответ 12

Для экземпляра докера mongoDB мы сделали это и работали как шарм:

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

Ответ 13

Чтобы проверить, работает ли контейнер Docker PostgreSQL или MySQL (в настоящее время) (особенно для таких инструментов миграции, как Flyway), вы можете использовать бинарный код ожидания: https://github.com/ArcanjoQueiroz/wait-for.