Using a PostgreSQL with Docker like a Pro

TL;DR There are a lot of snippets in the web using PostgreSQL in a Docker Compose setup. They rarely use the essential feature of healthckeck to determine whether the database server is “healthy” or not. This might (or might not) be relevant for your setup. Consider a project that runs data migration scripts as part of the startup procedure it is essential that the database is in a healthy state before firing requests to the database…

The essential part of the setup is the service postgresql in our docker-compose.yaml:

  postgres:
    image:  postgres:9.6.11-alpine
    ports:
      - 127.0.0.1:5432:5432
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s

With docker-compose ps you can easily verify the result:

         Name                        Command                  State                      Ports
--------------------------------------------------------------------------------------------------------------
sandbox_postgres_1        docker-entrypoint.sh postgres    Up (healthy)   127.0.0.1:5432->5432/tcp

This test works well for most scenarios. It was Markus who came up with an improved version of this health check. Let’s wait until a given database (sonar in this case) has been created:

psql -U sonar -lqt | cut -d \| -f 1 | grep -wq sonar

In case you are a bit puzzled (like I was on first sight) - here are the links to explainshell:

Don’t forget to quote correctly when putting the check into your docker-compose.yaml:

    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres && psql -lqt | cut -d \\| -f 1 | grep -qw sonar"]

Create the initial database

When firing up the container all scripts (*.sql or *.sh) in /docker-entrypoint-initdb.d will be executed.

A base shell script creating a database could look like follows:

#!/usr/bin/env bash

set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
    CREATE USER sonarqube with superuser password 's3cr3t';
    CREATE DATABASE sonar;
    GRANT ALL PRIVILEGES ON DATABASE sonar TO sonarqube;
EOSQL

Use the service postgres

So far so good, but…

Note: Version 3 no longer supports the condition form of depends_on

How do we configure the consuming service to wait until the database is ”healthy”?

startup-order comes with a PostgreSQL example to the rescue.

The wait-for-postgres.sh can be used in the entrypoint of the consuming service like follows

    entrypoint: ["/wait-for-postgres.sh", "postgres", "./bin/run.sh"]

Note: This solution requires psql installed in the dependent container.