2017-02-13 1 views
6

Что было бы лучшим подходом ждать postgres, чтобы полностью запустить внутри моего ENTRYPOINT, прежде чем переходить на выполнение nosetests?Как ждать запуска postgres в ENTRYPOINT?

Прямо сейчас я назначил запуск на моей машине примерно на 50 секунд. Поэтому я просто сплю 60 секунд. Это не очень хорошо, так как это может не работать при запуске на другой машине.

ENTRYPOINT \ 
      runuser -l postgres -c '/usr/lib/postgresql/9.3/bin/postgres -D /var/lib/postgresql/9.3/main -c config_file=/etc/postgresql/9.3/main/postgresql.conf & ' && \ 
      sleep 60 && \ 
      nosetests --verbose --cover-erase --with-coverage --cover-package=stalker 

Это выход запуска postgres:

2017-02-13 13:46:49.541 UTC [9] LOG: database system was interrupted; last known up at 2017-02-13 12:53:23 UTC 
2017-02-13 13:47:37.951 UTC [9] LOG: database system was not properly shut down; automatic recovery in progress 
2017-02-13 13:47:37.994 UTC [9] LOG: redo starts at 0/1783EA0 
2017-02-13 13:47:37.995 UTC [9] LOG: record with zero length at 0/17841E8 
2017-02-13 13:47:37.995 UTC [9] LOG: redo done at 0/17841B8 
2017-02-13 13:47:37.995 UTC [9] LOG: last completed transaction was at log time 2017-02-13 12:53:23.731984+00 
2017-02-13 13:47:38.384 UTC [9] LOG: MultiXact member wraparound protections are now enabled 
2017-02-13 13:47:38.387 UTC [7] LOG: database system is ready to accept connections 
2017-02-13 13:47:38.387 UTC [13] LOG: autovacuum launcher started 

Пожалуйста, я понимаю, что это идет вразрез с конвенцией работает несколько команд в ENTRYPOINT. У меня есть веские причины сделать это в этом случае.

+1

Вы можете запустить [ 'pg_isready'] (https://www.postgresql.org/docs/current /static/app-pg-isready.html) в цикле, в то время как код возврата равен 1. –

ответ

0

Всегда лучше не запускать несколько вещей в одном контейнере. Лучший способ состоял бы в том, чтобы вы провели postgres в одном контейнере и получили еще один для вашего nosetests.

Вы можете создать файл для архивирования, в котором nosetest «зависит» от базы данных.

+0

_depends_ просто вводит порядок, в котором будут запускаться контейнеры, но тот факт, что начальный контейнер был запущен, не означает, что он готов (например, готовность к тестированию), поэтому вы также должны использовать правильную [healthcheck] (https://docs.docker.com/compose/compose-file/#/healthcheck), чтобы убедиться, что процесс _postgress_ внутри containe r действительно готов. – zeppelin

+0

Это действительно хороший момент, и я понятия не имею, как я это отпустил. Кроме того, в то время как я стою на 100% позади моего аргумента, это не очень полный ответ как есть, потому что он фактически не решает проблему. – Nanne

1

Я обычно использую небольшой «TCP-порт-ожидания» сценарий, как это:

#!/bin/bash 
set -e 

if [ -z "$1" -o -z "$2" ] 
then 
    echo "tcp-port-wait - block until specified TCP port becomes available" 
    echo "Usage: ntcp-port-wait HOST PORT" 
    exit 1 
fi 
echo Waiting for port $1:$2 to become available... 
while ! nc -z $1 $2 2>/dev/null 
do 
    let elapsed=elapsed+1 
    if [ "$elapsed" -gt 90 ] 
    then 
     echo "TIMED OUT !" 
     exit 1 
    fi 
    sleep 1; 
done 

echo "READY !" 

Ждать, пока определенная служба не работает и готов.

В случае Postgresql порт по умолчанию он будет слушать это , поэтому команда будет выглядеть так:

tcp-port-wait localhost 5432 

Это не будет блокировать до службы Postgresql готов обслуживать соединения на: 5432 на интерфейс loopback внутри контейнера (при запуске в контексте сценария ENTRYPOINT).

Вы, конечно, должны скопировать этот скрипт в контейнер, , добавив строку, что ваш Dockerfile:

COPY tcp-port-wait /usr/local/bin/ 

, прежде чем использовать его.

А также установить netcat.

Вы можете использовать это для других видов услуг, таких как Tomcat или Mysql.

И, если вам нужно, вы также можете ждать «вне контейнера», как это:

docker exec my_container tcp-port-wait localhost 5432 

Note, есть, конечно, и другие способы сделать это, например, используя инструмент оркестровки, например docker-compose с healthcheck directive или какой-либо менеджер процесса внутри самого контейнера.

+0

Это выглядит великолепно, но для меня этот скрипт сразу же думает, что db встал: http://pastebin.com/x8UwhHQD – fredrik

+0

Хм, это странно, видимо, он принимает соединения, пока происходит восстановление, попробуйте заменить 'nc - z $ 1 $ 2' с 'pg_isready' (это специальная утилита PostgreSQL для проверки ее статуса) и посмотрите, помогает ли она. – zeppelin

+0

Спасибо, используя 'pg_isready'! Кроме того, мне пришлось удалить проверку аргументов. Если вы хотите изменить свой ответ, я буду отмечать его как принятый. – fredrik

7

Благодаря @zeppelin за предложение pg_isready.Я закончил с использованием этого:

#!/bin/bash 
# wait-for-postgres.sh 

set -e 

cmd="[email protected]" 
timer="5" 

until runuser -l postgres -c 'pg_isready' 2>/dev/null; do 
    >&2 echo "Postgres is unavailable - sleeping for $timer seconds" 
    sleep $timer 
done 

>&2 echo "Postgres is up - executing command" 
exec $cmd 

Я использую это в моем ENTRYPOINT:

ENTRYPOINT \ 

      # Start PostgreSQL 
      runuser -l postgres -c '/usr/lib/postgresql/9.3/bin/postgres -D /var/lib/postgresql/9.3/main -c config_file=/etc/postgresql/9.3/main/postgresql.conf & ' && \ 

      # Exectute tests when db is up 
      ./wait-for-postgres.sh nosetests --verbose --cover-erase --with-coverage --cover-package=stalker