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 withALTER 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
orcmd
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
Remove the
-d
(detach option) fromdocker run
command to see the server logs directly.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