Launch PostgreSQL Using Docker Compose
Razvan Ludosanu
Founder, learnbackend.dev
Published: 4/5/2024
The short answer
To set up a PostgreSQL database using Docker Compose, you can start by creating a compose.yaml file with the following content:
version: '3'
services:
db:
image: postgres
environment:
POSTGRES_USER: <username>
POSTGRES_PASSWORD: <password>
POSTGRES_DB: <database>
volumes:
- ./data:/var/lib/postgresql/data
ports:
- 5432:5432
Run in Warp
Where:
- POSTGRES_USER is used to create the specified user with superuser power.
- POSTGRES_PASSWORD is used to define the password of the user identified by the POSTGRES_USER variable.
- POSTGRES_DB is used to define a different name for the default database that is created when the image is first started. If it is not specified, then the value of POSTGRES_USER will be used.
Then run the following docker-compose command to start the PostgreSQL container:
$ docker compose -f compose.yaml up -d
Run in Warp
Where:
- The -f flag is used to specify the file path of the Compose file.
- The -d flag is used to launch the services in the background (i.e. detached mode).
Note that when running this command, the database data will be stored in the data directory relative to the compose.yaml file.
You can learn more about the docker compose up by visiting the official Docker documentation page.
Easily retrieve this syntax using Warp AI
If you’re using Warp as your terminal, you can easily retrieve this syntax using the Warp AI feature:
Entering docker compose postgres in the AI question input will prompt a human-readable step by step guide including code snippets.
Persisting database data with named volumes
To persist the database data in a volume instead of a bind mount, you can create a new named volume using the top-level volumes field:
version: '3'
services:
db:
image: postgres
environment:
POSTGRES_USER: <username>
POSTGRES_PASSWORD: <password>
POSTGRES_DB: <database>
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- 5432:5432
volumes:
pgdata:
Run in Warp
In this example, the database data will be stored in a volume named pgdata, which can be managed using the available docker volume commands.
You can learn more about using volumes in Compose by checking out the official documentation page.
You can also read our other article on how to mount files in Compose.
Executing scripts and SQL files on startup
To initialize the database with a shell script or a file containing SQL instructions, for example to insert dummy data or migrate an existing database, you can place your *.sh and *.sql files within a directory on your local machine and mount it to the /docker-entrypoint-initdb.d directory using the volumes field as follows:
version: '3'
services:
db:
image: postgres
environment:
POSTGRES_USER: <username>
POSTGRES_PASSWORD: <password>
POSTGRES_DB: <database>
volumes:
- ./data:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d
ports:
- 5432:5432
Run in Warp
Once the user and the database are created, postgres will run any of the files found in the /docker-entrypoint-initdb.d directory before starting the service.
Connecting Postgres to an application
To connect a PostgreSQL database to an application you can use the depends_on field, which is used to express dependency between services.
version: '3'
services:
db:
image: postgres
environment:
POSTGRES_USER: <username>
POSTGRES_PASSWORD: <password>
POSTGRES_DB: <database>
volumes:
- ./data:/var/lib/postgresql/data
ports:
- 5432:5432
app:
image: node
depends_on:
- db
Run in Warp
The use of this field causes Compose to start services in dependency order, which means that, in this example, the db service will be started first, then the app service.
Controlling the application's startup with a health check
By default, Compose doesn't wait for a service to be ready to start the next one, only until it's running. This can cause issues if, for example, you have an application that needs to wait for the database to be up and running before being able to handle incoming connections.
To solve this issue you can use the condition field to define a startup condition based on the status of the service it depends on.
version: '3'
services:
db:
image: postgres
environment:
POSTGRES_USER: <username>
POSTGRES_PASSWORD: <password>
POSTGRES_DB: <database>
volumes:
- ./data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
ports:
- 5432:5432
app:
image: node
depends_on:
db:
condition: service_healthy
Run in Warp
In the above example, we are telling Compose to wait for the db service to be up and running before launching the app service by defining a startup condition whose value is set to service_healthy.
The service_healthy represents a boolean value returned by the execution of the pg_isready command declared in the healthcheck field of the db service, which is a utility for checking the connection status of a PostgreSQL database server. The exit status specifies the result of the connection check.
This way, Compose will wait for the pg_isready utility to return true before launching the app service.
Connecting pgAdmin to Postgres
To manage your database using the pgAdmin interface, you can use the following compose.yaml file:
version: '3'
services:
db:
image: postgres
environment:
POSTGRES_USER: <username>
POSTGRES_PASSWORD: <password>
POSTGRES_DB: <database>
volumes:
- ./data:/var/lib/postgresql/data
ports:
- 5432:5432
pgadmin:
image: dpage/pgadmin4
environment:
PGADMIN_DEFAULT_EMAIL: <email>
PGADMIN_DEFAULT_PASSWORD: <password>
ports:
- 8080:80
Run in Warp
Where:
- PGADMIN_DEFAULT_EMAIL is used to create a new user account on pgAdmin.
- PGADMIN_DEFAULT_PASSWORD is used as a password for the user account identified by PGADMIN_DEFAULT_EMAIL.
You can then start both PostgreSQL and pgAdmin using the following command:
$ docker compose -f compose.yaml up -d
Run in Warp
And connect to the pgAdmin interface by navigating to the following address 127.0.0.1:8080 in your web browser.
Using .env files for storing sensitive data
In general, sensitive data such as usernames and passwords should live in a different place than the configuration or the code.
In the case of Compose, this data can be stored in a file named .env located at the root of your project, next to the compose.yaml file.
For example, to launch a PostgreSQL container with Compose, you can declare the following environment variables into an .env file:
USERNAME=john
PASSWORD=hello
DATABASE=staging
Run in Warp
And use them in the compose.yaml file using the following syntax:
version: '3'
services:
db:
image: postgres
environment:
POSTGRES_USER: ${USERNAME}
POSTGRES_PASSWORD: ${PASSWORD}
POSTGRES_DB: ${DATABASE}
volumes:
- ./data:/var/lib/postgresql/data
ports:
- 5432:5432
Run in Warp
Note that when running the docker compose up command, Compose will automatically detect the .env file and perform the required variable substitutions before launching your service.
You can learn more about environment variables and secrets by visiting the official Docker documentation pages.
Written by
Razvan Ludosanu
Founder, learnbackend.dev
Filed Under
Related Articles
Override the Container Entrypoint With docker run
Learn how to override and customize the entrypoint of a Docker container using the docker run command.
The Dockerfile ARG Instruction
Learn how to define and set build-time variables for Docker images using the ARG instruction and the --build-arg flag.
Start a Docker Container
Learn how to start a new Docker container from an image in both the foreground and the background using the docker-run command.
Stop All Docker Containers
How to gracefully shutdown running containers and forcefully kill unresponsive containers with signals in Docker using the docker-stop and docker-kill commands.
Use An .env File In Docker
Learn how to write and use .env files in Docker to populate the environment of containers on startup.
Run SSH In Docker
Learn how to launch and connect to a containerized SSH server in Docker using password-based authentication and SSH keys.
Launch MySQL Using Docker Compose
Learn how to launch a MySQL container in Docker Compose.
Execute in a Docker Container
Learn how to execute one or multiple commands in a Docker container using the docker exec command.
Expose Docker Container Ports
Learn how to publish and expose Docker container ports using the docker run command and Dockerfiles.
Restart Containers In Docker Compose
Learn how to restart and rebuild one or more containers in Docker Compose.
Output Logs in Docker Compose
Learn how to output, monitor, customize and filter the logs of the containers related to one or more services in Docker Compose
Rename A Docker Image
Learn how to rename Docker images locally and remotely using the docker tag command.