
Docker Compose is a multi-container orchestration tool for a single host. It uses the Docker engine to manage and orchestrate the Docker containers. It simplifies your local development environment by allowing you to create complex and interconnected containers declaratively. Docker Compose also automates the test suite in the CI/CD process by providing a temporary and isolated environment for testing.
This article explains how to use Docker Compose to create and manage containers. It covers the basics of the docker compose
command and how to create the compose.yaml
manifest. It also explores the Docker Compose profile for running containers depending on your environment.
The Short Answer
Below are some basic Docker Compose commands that operate on a compose.yaml
or docker-compose.yaml
file.
# Create/build and start all services in the background.
$ docker compose up -d
# Stop and remove all service containers, networks, and volumes.
$ docker compose down
# Stop all services.
$ docker compose stop
# Start and run stopped services.
$ docker compose start
# View the status of running services.
$ docker compose ps
# Check the logs of all services.
$ docker compose logs
Create a Docker Compose File
This section covers creating a sample Docker Compose file compose.yaml
for a sample flask application.
Download the sample application.
console$ git clone https://github.com/ndlrfz/flask-redis-postgresql
Navigate to the
flask-redis-postgresql
project directory.console$ cd flask-redis-postgresql
The directory contains a file
compose.yaml
with the following contents.console$ cat compose.yml
You'll see the following Docker Compose manifest:
yamlname: myproject services: redis: image: "redis:alpine" restart: always ports: - 6379:6379 volumes: - redis:/data postgresql: image: "postgres:16-alpine" ports: - "5432:5432" volumes: - pgdata:/var/lib/postgresql/data environment: POSTGRES_USER: ${DATABASE_USER} POSTGRES_PASSWORD: ${DATABASE_PASSWORD} POSTGRES_DB: ${DATABASE_NAME} flask: build: . restart: always env_file: - ".env" depends_on: - redis - postgresql ports: - "8000:5000" volumes: - ./:/code volumes: redis: driver: "local" pgdata: driver: "local"
In this file,
name
: Sets the project name tomyproject
.services
: Defines the individual containers that make up your application.- Define the
redis
service with these details:image
: Creates the service from theredis:alpine
image.restart: always
: Sets a policy to always restart this container if it stops.ports
: Maps port6379
on the host to port6379
in the container.volumes
: Mounts the named volumeredis
to the/data
directory inside the container for persistent data.
- Define the
postgresql
service with the following:image
: Creates the service from thepostgres:16-alpine
image.ports
: Maps port5432
on the host to port5432
in the container.volumes
: Mounts the named volumepgdata
to the/var/lib/postgresql/data
directory for persistent data.environment
: Sets environment variables inside the container. The values for${DATABASE_USER}
,${DATABASE_PASSWORD}
, and${DATABASE_NAME}
are substituted from your shell's environment (often loaded from an.env
file).
- Define the application service
flask
with the following:build: .
: Builds a Docker image in the current directory from theDockerfile
.restart: always
: Sets a policy to always restart this container if it stops.env_file
: Loads environment variables for the service directly from a.env
file.depends_on
: Controls the startup order. Theflask
service will start only after theredis
andpostgresql
services have been started.ports
: Maps port8000
on the host to port5000
inside the container.volumes
: Mounts the current project directory on the host to the/code
directory inside the container.
volumes
: Defines two named volumes,redis
andpgdata
, using thelocal
driver. These are managed by Docker and stored on the host machine.
Create a file
.env
.console$ nano .env
Add the following environment variables for PostgreSQL credentials. You can replace the following details with your credentials.
iniDATABASE_USER=app_user DATABASE_PASSWORD=app_password DATABASE_NAME=appdb DATABASE_HOST=postgresql DATABASE_PORT=5432
Save and exit the file.
Build and start your services.
console$ docker compose up -d
The option
-d
allows you to run containers in the background.Run the command below to check the running containers or services.
console$ docker compose ps
Output:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS myproject_flask-1 myproject_flask "flask run --debug" flask About a minute ago Up About a minute 0.0.0.0:8000->5000/tcp, [::]:8000->5000/tcp myproject_postgresql-1 postgres:16-alpine "docker-entrypoint.s…" postgresql About a minute ago Up About a minute 0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp myproject_redis-1 redis:alpine "docker-entrypoint.s…" redis About a minute ago Up 32 seconds 0.0.0.0:6379->6379/tcp, [::]:6379->6379/tcp
Output explanation:
flask
service is running on port8000
on the host machine, which is based on the Docker imagemyproject_flask
.postgresql
service running on port5432
based on the Docker imagepostgres:16-alpine
.redis
service is running on port6379
based on the Docker imageredis:alpine
.
Check the list of images that are used by your services.
console$ docker compose images
Output:
CONTAINER REPOSITORY TAG IMAGE ID SIZE myproject_flask-1 myproject_flask latest 1c3d151b6276 254MB myproject_postgresql-1 postgres 16-alpine b56133b65cd3 275MB myproject_redis-1 redis alpine d470ca4bc10c 60.5MB
Open a web browser and visit
http://<SERVER-IP>:8000/
to verify that your application is running.
Manage Docker Compose Stack
The following table describes the common docker compose
commands for managing your application stack.
Command | Description | Example |
---|---|---|
build |
Build or rebuild containers | docker compose build |
up |
Create and start containers | docker compose up -d |
down |
Stop and remove containers | docker compose down |
start |
Start existing containers | docker compose start app |
stop |
Stop containers | docker compose stop app |
kill |
Force stop containers | docker compose kill app |
ps |
Check running containers | docker compose ps |
logs |
Check logs for containers | docker compose logs app |
exec |
Execute command in the container | docker compose exec app bash |
images |
Listing images used by containers | docker compose images |
rm |
Remove stopped containers | docker compose rm |
Use Docker Compose Profiles
Profiles allow selective applications or services to run based on the environment or use cases, such as development and production.
Edit the
compose.yml
file.console$ nano compose.yml
Add the following configuration under the
flask
service.yamladminer: image: adminer restart: always depends_on: [postgresql] profiles: [dev] ports: - 8080:8080 redis-insight: image: redis/redisinsight:latest restart: always profiles: [dev] depends_on: [redis] ports: - "8001:8001"
Save and close the file.
In this configuration:
adminer
: Defines a service namedadminer
that uses theadminer
Docker image.restart: always
: Sets a policy to always restart the container if it stops.depends_on
: Ensures theadminer
service starts only after thepostgresql
service starts.profiles
: Assigns thedev
profile to the service.ports
: Maps port8080
on the host to port8080
in the container.
redis-insight
: Defines a service namedredis-insight
that uses theredis/redisinsight:latest
Docker image.restart: always
: Sets a policy to always restart the container if it stops.depends_on
: Ensures theredis-insight
service starts only after theredis
service starts.profiles
: Assigns thedev
profile to the service.ports
: Maps port8001
on the host to port8001
in the container.
Start the
adminer
service.console$ docker compose --profile dev up -d
Use the
--profile dev
option to activate and start services assigned to thedev
profile. This tells Docker Compose to include theadminer
service, which it ignores by default.Check the running container with the following command.
console$ docker compose ps
You'll see the
adminer
service is running.NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS myproject-adminer-1 adminer "entrypoint.sh docke…" adminer 2 seconds ago Up 1 second 0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp myproject-flask-1 myproject-flask "flask run --debug" flask 2 seconds ago Up 1 second 0.0.0.0:8000->5000/tcp, [::]:8000->5000/tcp myproject-postgresql-1 postgres:16-alpine "docker-entrypoint.s…" postgresql 3 seconds ago Up 2 seconds 0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp myproject-redis-1 redis:alpine "docker-entrypoint.s…" redis 3 seconds ago Up 2 seconds 0.0.0.0:6379->6379/tcp, [::]:6379->6379/tcp myproject-redis-insight-1 redis/redisinsight:latest "./docker-entry.sh n…" redis-insight 3 seconds ago Up 1 second 5540/tcp, 0.0.0.0:8001->8001/tcp, [::]:8001->8001/tcp
To stop a service, for example
adminer
, useconsole$ docker compose stop adminer
Remove the stopped
adminer
service.console$ docker compose rm adminer
Destroy all services (including the
dev
profile).console$ docker compose --profile dev down
Conclusion
In this article, you've explored how to use Docker Compose to manage container stacks. You have learned how to start, stop, restart, and destroy containers using the docker compose
command, how to create the compose.yaml
file for your application stack, and the basic usage of Docker Compose Profiles for selectively running containers depending on your environment. For more information, check the Docker Compose documentation.
No comments yet.