30

I have a Kong API Gateway container and a postgres container and I need to check whether postgres has started up and ready from the Kong container before running the migrations. I was thinking of installing the postgres client utilities into a custom image based on the official Kong image using RUN yum install postgresql -y && yum clean all in my Dockerfile and using either psql or pg_isready to achieve this. I've created a postgres user called polling with an empty password specifically for checking the status of the server by these two utilities. Neither of them work.

I tried to execute these commands from the custom Kong image:

  1. psql. The command psql -h postgres -U polling -w -c '\l' fails with the error psql: fe_sendauth: no password supplied. But the user has no password. What am I doing wrong? The full shell script checking whether the server is ready using psql is described here.

  2. pg_isready. I don't get how to install this utility separately into a custom image based on the official Kong image which in turn based on the centos:7 image, the postgresql package doesn't include pg_isready. Only these utilities are installed and can be found in /usr/bin: pg_config, pg_dump, pg_dumpall, pg_restore, psql. How to install pg_isready? I don't want to have the full server installation in the Kong image.

super.t
  • 2,526
  • 7
  • 32
  • 51
  • Regarding #1, have you adjusted the pg_hba.conf? See https://dba.stackexchange.com/questions/83164/remove-password-requirement-for-user-postgres – bluescores Oct 01 '17 at 20:53
  • @bluescores right, I need to change this config or add .pgpass on the client. Solved the issue with the latter. I should notice that I had to set a password for my polling user, psql shouted at me if the pass was empty regardless .pgpass – super.t Oct 02 '17 at 08:18

4 Answers4

65

Here is a shell one liner using pg_isready tool provided by PostgreSQL.

To call outside docker:

DOCKER_CONTAINER_NAME="mypgcontainer"
timeout 90s bash -c "until docker exec $DOCKER_CONTAINER_NAME pg_isready ; do sleep 5 ; done"

Based on a post from Jeroma Belleman.

Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435
  • 1
    I am surprised this answer doesn't get more upvotes. I came to the same conclusion, it really works with `pg_isready` while doesn't work with the "wait for-it.sh" bash script as the TCP port is ready before postgres is really ready to "work". Otherwise, you can get errors like: `An exception occurred in driver: SQLSTATE[08006] [7] server closed the connection unexpectedly`. – COil Aug 30 '20 at 09:17
  • 3
    It is a new answer. – Mikko Ohtamaa Aug 30 '20 at 19:41
21

I tried wait-for-it, but it may be a problem to run it in docker container as in the docker image may not be installed nc (sometimes there is not even ping, telnet, curl..). So to check if the DB is up and running I have used HealthCheck in docker compose file what was checking return value of pg_isready, what is part of postgres database, so you do not need to install anything into docker images:

version: '2.3'
services:
  postgres-db:
    image: postgresImage
    healthcheck:
      test: /usr/bin/pg_isready
      interval: 5s
      timeout: 10s
      retries: 120
    ports:
      - '5432:5432'

  aplication:
    image: applicationImage
    depends_on:
      postgres-db:
        condition: service_healthy
Thuthu
  • 211
  • 2
  • 2
  • 6
    depends_on is removed in compose v3 – super.t Feb 19 '19 at 18:26
  • 1
    @super.t `depends_on` is [still around](https://docs.docker.com/compose/compose-file/#depends_on) in v3. – Mike Branski Oct 11 '19 at 15:31
  • 3
    @MikeBranski [Version 3 no longer supports the condition form of depends_on](https://docs.docker.com/compose/compose-file/#depends_on) – davidgoli Feb 13 '20 at 20:44
  • 6
    @MikeBranski @davidgoli @super.t To add to the confusion, Docker-Compose v3.9 re-added `condition` for `depends_on`. You can now control startup via `service_started`, `service_healthy` and `service_completed_successfully` conditions. – dvdgsng Oct 17 '22 at 17:32
8

We solve this with a simple TCP check on port 5432, without any PG tooling. We just use wait-for-it.sh, and it works well. Postgres does not open the port until the server is actually ready to serve, so this is apparently fine.

Sample Dockerfile: https://github.com/apim-haufe-io/wicked.kong/blob/master/Dockerfile

Corresponding start script (only the last line is interesting for this specific problem): https://github.com/apim-haufe-io/wicked.kong/blob/master/startup.sh

Snippet:

wait-for-it.sh -h $KONG_PG_HOST -p 5432 -t 30 -- kong start --run-migrations

Wait for it: https://github.com/vishnubob/wait-for-it

donmartin
  • 1,753
  • 2
  • 15
  • 30
  • 4
    this doesn't work when you have to launch postgres in a container for the first time as the server will be ready and attempting to run the start up scripts. I've had requests to the server cause the init script to crash sadly. – jemiloii Nov 28 '18 at 22:10
  • 2
    Agree with @jemiloii. The port is available earlier than the Postgres is ready to run scripts – ka3ak Feb 26 '20 at 15:31
  • I have also seen this once in a while, but not that common. In some places, I have also seen `sleep 5` after wait-for-it has returned, and that is typically enough. Belt and suspenders would call for runnint wait-for-it, sleep, wait-for-it. Typically good enough for me. – donmartin Feb 28 '20 at 10:14
  • wait-for-it.sh timeout does not work on mac. – Ezward Jun 15 '22 at 21:37
7

My solution was to create a new image based on the official kong image and override the entrypoint like this:

#!/usr/bin/env bash
set -e

# Disabling nginx daemon mode
export KONG_NGINX_DAEMON="off"

# Setting default prefix (override any existing variable)
export KONG_PREFIX="/usr/local/kong"

# Prepare Kong prefix
if [ "$1" = "/usr/local/openresty/nginx/sbin/nginx" ]; then
    kong prepare -p "/usr/local/kong"
fi

#waiting for postgres
until psql --host=$KONG_PG_HOST --username=$POLLING_USER $POLLING_DATABASE -w &>/dev/null
do
  echo "Waiting for PostgreSQL..."
  sleep 1
done

echo "Postgres is ready, running the migrations..."

kong migrations up

echo "READY TO START UP KONG USING CMD" $@;

exec "$@"
super.t
  • 2,526
  • 7
  • 32
  • 51