How to customize the configuration file of the official PostgreSQL Docker image?

When you run the official entrypoint (A.K.A. when you launch the container), it runs initdb in $PGDATA (/var/lib/postgresql/data by default), and then it stores in that directory these 2 files:

  • postgresql.conf with default manual settings.
  • postgresql.auto.conf with settings overriden automatically with ALTER SYSTEM commands.

The entrypoint also executes any /docker-entrypoint-initdb.d/*.{sh,sql} files.

All this means you can supply a shell/SQL script in that folder that configures the server for the next boot (which will be immediately after the DB initialization, or the next times you boot the container).

Example:

conf.sql file:

ALTER SYSTEM SET max_connections = 6;
ALTER SYSTEM RESET shared_buffers;

Dockerfile file:

FROM posgres:9.6-alpine
COPY *.sql /docker-entrypoint-initdb.d/
RUN chmod a+r /docker-entrypoint-initdb.d/*

And then you will have to execute conf.sql manually in already-existing databases. Since configuration is stored in the volume, it will survive rebuilds.


Another alternative is to pass -c flag as many times as you wish:

docker container run -d postgres -c max_connections=6 -c log_lock_waits=on

This way you don't need to build a new image, and you don't need to care about already-existing or not databases; all will be affected.


The postgres:9.4 image you've inherited from declares a volume at /var/lib/postgresql/data. This essentially means you can't copy any files to that path in your image; the changes will be discarded.

You have a few choices:

  • You could just add your own configuration files as a volume at run-time with docker run -v postgresql.conf:/var/lib/postgresql/data/postgresql.conf .... However, I'm not sure exactly how that will interact with the existing volume.

  • You could copy the file over when the container is started. To do that, copy your file into the build at a location which isn't underneath the volume then call a script from the entrypoint or cmd which will copy the file to the correct location and start Postgres.

  • Clone the project behind the Postgres official image and edit the Dockerfile to add your own config file in before the VOLUME is declared (anything added before the VOLUME instruction is automatically copied in at run-time).

  • Pass all config changes in command option in docker-compose file

Like this:

services:
  postgres:
    ...
    command:
      - "postgres"
      - "-c"
      - "max_connections=1000"
      - "-c"
      - "shared_buffers=3GB"
      - "-c"
      ...

Inject custom postgresql.conf into Postgres Docker container

The default postgresql.conf file lives within the PGDATA dir (/var/lib/postgresql/data), which makes things more complicated especially when running the Postgres container for the first time, since the docker-entrypoint.sh wrapper invokes the initdb step for PGDATA dir initialization.

To customize the PostgreSQL configuration in Docker consistently, I suggest using the config_file Postgres option together with Docker volumes like this:

Production database (PGDATA dir as Persistent Volume)

docker run -d \
-v $CUSTOM_CONFIG:/etc/postgresql.conf \
-v $CUSTOM_DATADIR:/var/lib/postgresql/data \
-e POSTGRES_USER=postgres \
-p 5432:5432 \
--name postgres \
postgres:9.6 postgres -c config_file=/etc/postgresql.conf

Testing database (PGDATA dir will be discarded after docker rm)

docker run -d \
-v $CUSTOM_CONFIG:/etc/postgresql.conf \
-e POSTGRES_USER=postgres \
--name postgres \
postgres:9.6 postgres -c config_file=/etc/postgresql.conf

Debugging

  1. Remove the -d (detach option) from docker run command to see the server logs directly.

  2. Connect to the Postgres server with the psql client and query the configuration:

    docker run -it --rm --link postgres:postgres postgres:9.6 sh -c 'exec psql -h $POSTGRES_PORT_5432_TCP_ADDR -p $POSTGRES_PORT_5432_TCP_PORT -U postgres'
    
    psql (9.6.0)
    Type "help" for help.
    
    postgres=# SHOW all;
    

With Docker Compose

When working with Docker Compose, you can use command: postgres -c option=value in your docker-compose.yml to configure Postgres.

For example, this makes Postgres log to a file:

command: postgres -c logging_collector=on -c log_destination=stderr -c log_directory=/logs

Adapting Vojtech Vitek's answer, you can use

command: postgres -c config_file=/etc/postgresql.conf

to change the config file Postgres will use. You'd mount your custom config file with a volume:

volumes:
   - ./customPostgresql.conf:/etc/postgresql.conf

Here's the docker-compose.yml of my application, showing how to configure Postgres:

# Start the app using docker-compose pull && docker-compose up to make sure you have the latest image
version: '2.1'
services:
  myApp:
    image: registry.gitlab.com/bullbytes/myApp:latest
    networks:
      - myApp-network
  db:
     image: postgres:9.6.1
     # Make Postgres log to a file.
     # More on logging with Postgres: https://www.postgresql.org/docs/current/static/runtime-config-logging.html
     command: postgres -c logging_collector=on -c log_destination=stderr -c log_directory=/logs
     environment:
       # Provide the password via an environment variable. If the variable is unset or empty, use a default password
       # Explanation of this shell feature: https://unix.stackexchange.com/questions/122845/using-a-b-for-variable-assignment-in-scripts/122848#122848
       - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-4WXUms893U6j4GE&Hvk3S*hqcqebFgo!vZi}
     # If on a non-Linux OS, make sure you share the drive used here. Go to Docker's settings -> Shared Drives
     volumes:
       # Persist the data between container invocations
       - postgresVolume:/var/lib/postgresql/data
       - ./logs:/logs
     networks:
       myApp-network:
         # Our application can communicate with the database using this hostname
         aliases:
           - postgresForMyApp
networks:
  myApp-network:
    driver: bridge
# Creates a named volume to persist our data. When on a non-Linux OS, the volume's data will be in the Docker VM
# (e.g., MobyLinuxVM) in /var/lib/docker/volumes/
volumes:
  postgresVolume:

Permission to write to the log directory

Note that when on Linux, the log directory on the host must have the right permissions. Otherwise you'll get the slightly misleading error

FATAL: could not open log file "/logs/postgresql-2017-02-04_115222.log": Permission denied

I say misleading, since the error message suggests that the directory in the container has the wrong permission, when in reality the directory on the host doesn't permit writing.

To fix this, I set the correct permissions on the host using

chgroup ./logs docker && chmod 770 ./logs