¿Cuál sería el mejor enfoque para esperar a que postgres se inicie completamente dentro de mi ENTRYPOINT antes de continuar con la ejecución de nosetests ?
En este momento he cronometrado el inicio de mi máquina en alrededor de 50 segundos. Así que solo estoy durmiendo durante 60 segundos. Esto no se siente bien ya que podría no funcionar cuando se ejecuta en otra máquina.
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 Este es el resultado de iniciar 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 Por favor, entiendo que esto va en contra de la convención de ejecutar varios comandos en ENTRYPOINT . Tengo buenas razones para hacer esto en este caso.
Gracias a @zeppelin por sugerir pg_isready . Terminé usando esto:
#!/bin/bash # wait-for-postgres.sh set -e cmd="$@" 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 Estoy usando esto en mi 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=stalkerNormalmente usaré un pequeño script "tcp-port-wait", como este:
#!/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 !"Esperar hasta que cierto servicio esté activo y listo.
En el caso de Postgresql, el puerto predeterminado en el que escuchará es 5432 , por lo que el comando sería:
tcp-port-wait localhost 5432Eso bloqueará hasta que el servicio Postgresql esté listo para servir conexiones, en: 5432 en la interfaz de bucle invertido dentro del contenedor (cuando se ejecuta en el contexto del script ENTRYPOINT).
Sin duda, debe copiar este script en su contenedor, agregando una línea como esa a su Dockerfile :
COPY tcp-port-wait /usr/local/bin/antes de que puedas usarlo.
Y también instale la utilidad netcat .
También puede usar esto para otros tipos de servicios, como Tomcat o Mysql.
Y, si lo necesitas, también puedes esperar "fuera del contenedor", así:
docker exec my_container tcp-port-wait localhost 5432Tenga en cuenta que ciertamente hay otras formas de hacer esto, por ejemplo, mediante el uso de alguna herramienta de orquestación, como docker-compose con directiva de control de salud, o algún administrador de procesos dentro del propio contenedor.