A simple Postgres setup with Docker Compose
In many of my projects, I need a Postgres database. However, installing Postgres is not usually a trivial operation. I have found that using docker compose to manage a local postgres install for each project works well. This allows each project to use its own version of postgres, and keeps the data isolated, avoiding issues with dependencies and also with work on one project affecting the other.
The basic idea is as follows:
- Create a compose file to run a postgres server
- Configure it to mount a docker volume, which will contain the data.
- Expose the port, which will allow our applications to access the database.
Install docker
To use docker compose, we need to have docker installed.
Create a compose file
Here’s a template of the compose file I use. Save it in our working directory to a file called compose.yaml.
services:
postgres:
image: postgres:17
container_name: postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
volumes:
- type: volume
source: data
target: /var/lib/postgresql/data
ports:
- name: postgres
target: 5432
published: 5432
volumes:
data:
Here’s an annotated version, explaining what’s going on:
services:
# Tell docker compose to create a service called postgres
postgres:
# Specify we want version 17 of postgres.
# This will download it from Docker Hub:
# https://hub.docker.com/_/postgres
image: postgres:17
# Name the container 'postgres'
container_name: postgres
# Specify the required environment variables as specified by the
# Postgres docker documentation. This will create a postgres user with
# the same password. This is fine for local development, but we wouldn't
# want to use this for production.
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
# This creates a docker volume, which will be mounted to the container,
# and provides a persistent place for the database to store its data,
# that will survive the container
# being stopped or removed.
volumes:
- type: volume
source: data
target: /var/lib/postgresql/data
# Exposes port 5432 onto our host machine, so we can access it from our
# application.
ports:
- name: postgres
target: 5432
published: 5432
# Creates a docker volume called 'data', which we use above
volumes:
data:
First run
First we download the image, and then start the container.
-
docker compose pull- this fetches the image -
docker compose up- this starts the container
The first time it will initialise the database with the username and password we supplied. In the output, you should see it initialise the database:
running bootstrap script ... ok
It will start the database, perform some setup, shut it down again, and then start it again. At some point we should see:
PostgreSQL init process complete; ready for start up
and finally
database system is ready to accept connections
We can press CTRL+C to stop the container.
Subsequent runs
Now the database has been initialised, we can run it in the background by using --detach:
docker compose up --detach
You can confirm it’s running by typing docker ps:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8a5ff1548b79 postgres:17 "docker-entrypoint.s…" 4 minutes ago Up 8 seconds 0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp postgres
Here we can see there is a container called postgres running, and that port 5432 is being mapped to our host machine.
When we want to stop it, we can run:
docker compose down
And that’s it! We have a simple isolated postgres server that we can start and stop as we wish.
Upgrading postgres
Unfortunately upgrading postgres running on docker is quite an involved process. I wrote a separate post about that.