Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.
Single host deployment
: This means you can run everything on a single piece of hardwareQuick and easy configuration
: Due to YAML scriptsHigh productivity
: Docker Compose reduces the time it takes to perform tasksSecurity
: All the containers are isolated from each other, reducing the threat landscapedocker compose up
and the Docker compose command starts and runs your entire app. You can alternatively run docker-compose up
using the docker-compose binary.Compose can be used in many different ways. Some common use cases are outlined below.
Development environments
The ability to run an application in an isolated environment and interact with it is crucial. The Compose command line tool can be used to create the environment and interact with it.Automated testing environments
: An important part of any Continuous Deployment or Continuous Integration process is the automated test suite. Automated end-to-end testing requires an environment in which to run tests. Compose provides a convenient way to create and destroy isolated testing environments for your test suite.Single host deployments
: Compose has traditionally been focused on development and testing workflows, but with each release we’re making progress on more production-oriented features.Docker Compose relies on Docker Engine for any meaningful work, so make sure you have Docker Engine installed either locally or remote, depending on your setup.
On Linux, you can download the Docker Compose binary from the Compose repository release page on GitHub. Follow the instructions from the link, which involve running the curl command in your terminal to download the binaries. These step-by-step instructions are also included below.
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
docker-compose version 1.29.2, build 5becea4c
Docker Desktop for Mac includes Compose along with other Docker apps, so Mac users do not need to install Compose separately.
Docker Desktop for Windows includes Compose along with other Docker apps, so Mac users do not need to install Compose separately.
Builds, (re)creates, starts, and attaches to containers for a service.
# Usage syntax: docker compose up [SERVICE...]
Options:
--build Build images before starting containers.
-d, --detach Detached mode: Run containers in the background
--no-build Don not build an image, even if it is missing.
--no-color Produce monochrome output.
--no-deps Don not start linked services.
--no-log-prefix Don not print prefix in logs.
--no-recreate If containers already exist, don not recreate them. Incompatible with --force-recreate.
--no-start Don not start the services after creating them.
--quiet-pull Pull without printing progress information.
--remove-orphans Remove containers for services not defined in the Compose file.
-V, --renew-anon-volumes Recreate anonymous volumes instead of retrieving data from the previous containers.
--scale scale Scale SERVICE to NUM instances. Overrides the scale setting in the Compose file if present.
-t, --timeout int Use this timeout in seconds for container shutdown when attached or when containers are already running. (default 10)
--wait Wait for services to be running|healthy. Implies detached mode.
# docker compose up --no-start
[+] Running 7/7
⠿ Network my-wordpress_default Created 0.1s
⠿ Volume "my-wordpress_wordpress_data" Created 0.0s
⠿ Volume "my-wordpress_db_data" Created 0.0s
⠿ Container my-wordpress-db-1 Created 0.1s
⠿ Container my-wordpress-wordpress-3 Created 0.1s
⠿ Container my-wordpress-wordpress-1 Created 0.1s
⠿ Container my-wordpress-wordpress-2 Created 0.1s
# docker compose ps
NAME COMMAND SERVICE STATUS PORTS
my-wordpress-db-1 "docker-entrypoint.s…" db created
my-wordpress-wordpress-1 "docker-entrypoint.s…" wordpress created
my-wordpress-wordpress-2 "docker-entrypoint.s…" wordpress created
my-wordpress-wordpress-3 "docker-entrypoint.s…" wordpress created
# docker compose up -d
[+] Running 7/7
⠿ Network my-wordpress_default Created 0.1s
⠿ Volume "my-wordpress_db_data" Created 0.0s
⠿ Volume "my-wordpress_wordpress_data" Created 0.0s
⠿ Container my-wordpress-db-1 Started 0.5s
⠿ Container my-wordpress-wordpress-3 Started 1.5s
⠿ Container my-wordpress-wordpress-2 Started 1.7s
⠿ Container my-wordpress-wordpress-1 Started 1.6s
Stops containers and removes containers, networks, volumes, and images created by up.
By default, the only things removed are:
Networks and volumes defined as external are never removed.
# docker compose down -v
[+] Running 7/7
⠿ Container my-wordpress-wordpress-2 Removed 1.5s
⠿ Container my-wordpress-wordpress-1 Removed 1.4s
⠿ Container my-wordpress-wordpress-3 Removed 1.5s
⠿ Container my-wordpress-db-1 Removed 1.6s
⠿ Volume my-wordpress_wordpress_data Removed 0.0s
⠿ Network my-wordpress_default Removed 0.3s
⠿ Volume my-wordpress_db_data Removed 0.1s
Starts/Stops existing containers for a service.
# docker compose ps
NAME COMMAND SERVICE STATUS PORTS
my-wordpress-db-1 "docker-entrypoint.s…" db running 33060/tcp
my-wordpress-wordpress-1 "docker-entrypoint.s…" wordpress running 0.0.0.0:49191->80/tcp
my-wordpress-wordpress-2 "docker-entrypoint.s…" wordpress running 0.0.0.0:49192->80/tcp
my-wordpress-wordpress-3 "docker-entrypoint.s…" wordpress running 0.0.0.0:49193->80/tcp
# docker compose stop wordpress
[+] Running 3/3
⠿ Container my-wordpress-wordpress-3 Stopped 1.5s
⠿ Container my-wordpress-wordpress-2 Stopped 1.6s
⠿ Container my-wordpress-wordpress-1 Stopped 1.3s
# docker compose stop
[+] Running 4/4
⠿ Container my-wordpress-wordpress-1 Stopped 0.0s
⠿ Container my-wordpress-wordpress-2 Stopped 0.0s
⠿ Container my-wordpress-wordpress-3 Stopped 0.0s
⠿ Container my-wordpress-db-1 Stopped 1.3s
# docker compose start wordpress
[+] Running 3/3
⠿ Container my-wordpress-wordpress-3 Started 0.6s
⠿ Container my-wordpress-wordpress-1 Started 0.7s
⠿ Container my-wordpress-wordpress-2 Started 0.6s
This is the equivalent of docker exec
. With this subcommand you can run arbitrary commands in your services. Commands are by default allocating a TTY, so you can use a command such as docker-compose exec web sh to get an interactive prompt.
List images used by the created containers.
# docker compose images
Container Repository Tag Image Id Size
my-wordpress-db-1 mysql 5.7 11d8667108c2 450MB
my-wordpress-wordpress-1 wordpress latest b352e074cf4f 605MB
my-wordpress-wordpress-2 wordpress latest b352e074cf4f 605MB
my-wordpress-wordpress-3 wordpress latest b352e074cf4f 605MB
Pauses running containers of a service. They can be unpaused with docker-compose unpause
.
# docker compose ps
NAME COMMAND SERVICE STATUS PORTS
my-wordpress-db-1 "docker-entrypoint.s…" db running 33060/tcp
my-wordpress-wordpress-1 "docker-entrypoint.s…" wordpress running 0.0.0.0:49168->80/tcp
my-wordpress-wordpress-2 "docker-entrypoint.s…" wordpress running 0.0.0.0:49170->80/tcp
my-wordpress-wordpress-3 "docker-entrypoint.s…" wordpress running 0.0.0.0:49169->80/tcp
# ps aux | grep mysql
systemd+ 18290 0.0 5.0 1311300 204276 ? Ssl 10:14 0:00 mysqld
root 19247 0.0 0.0 6208 884 pts/1 S+ 10:20 0:00 grep mysql
# docker compose pause db
[+] Running 1/0
⠿ Container my-wordpress-db-1 Paused 0.0s
# docker compose ps
NAME COMMAND SERVICE STATUS PORTS
my-wordpress-db-1 "docker-entrypoint.s…" db paused 33060/tcp
my-wordpress-wordpress-1 "docker-entrypoint.s…" wordpress running 0.0.0.0:49168->80/tcp
my-wordpress-wordpress-2 "docker-entrypoint.s…" wordpress running 0.0.0.0:49170->80/tcp
my-wordpress-wordpress-3 "docker-entrypoint.s…" wordpress running 0.0.0.0:49169->80/tcp
# ps aux | grep mysql
systemd+ 18290 0.0 5.0 1311300 204276 ? Dsl 10:14 0:00 mysqld
root 19294 0.0 0.0 6208 884 pts/1 S+ 10:21 0:00 grep mysql
# docker compose unpause db
[+] Running 1/0
⠿ Container my-wordpress-db-1 Unpaused 0.0s
Displays log output from services.
Prints the public port for a port binding.
# docker compose ps
NAME COMMAND SERVICE STATUS PORTS
my-wordpress-db-1 "docker-entrypoint.s…" db running 33060/tcp
my-wordpress-wordpress-1 "docker-entrypoint.s…" wordpress running 0.0.0.0:49168->80/tcp
my-wordpress-wordpress-2 "docker-entrypoint.s…" wordpress running 0.0.0.0:49170->80/tcp
my-wordpress-wordpress-3 "docker-entrypoint.s…" wordpress running 0.0.0.0:49169->80/tcp
# docker compose port wordpress 80
0.0.0.0:49168
# docker compose port wordpress 80 --index 3
0.0.0.0:49169
# docker compose port wordpress 80 --index 4
no container found for wordpress_4
Lists containers.
# docker compose ps
NAME COMMAND SERVICE STATUS PORTS
my-wordpress-db-1 "docker-entrypoint.s…" db running 33060/tcp
my-wordpress-wordpress-1 "docker-entrypoint.s…" wordpress running 0.0.0.0:49168->80/tcp
my-wordpress-wordpress-2 "docker-entrypoint.s…" wordpress running 0.0.0.0:49170->80/tcp
my-wordpress-wordpress-3 "docker-entrypoint.s…" wordpress running 0.0.0.0:49169->80/tcp
# docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------
my-wordpress-db-1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
my-wordpress-wordpress-1 docker-entrypoint.sh apach ... Up 0.0.0.0:49168->80/tcp
my-wordpress-wordpress-2 docker-entrypoint.sh apach ... Up 0.0.0.0:49170->80/tcp
my-wordpress-wordpress-3 docker-entrypoint.sh apach ... Up 0.0.0.0:49169->80/tcp
The Compose file is a YAML
file defining services
, networks
and volumes
. The default path for a Compose file is ./docker-compose.yml
.
You can use either a
.yml
or.yaml
extension for this file. They both work.
The example below is the compose file version 3:
version: "3.9"
services:
redis:
image: redis:alpine
ports:
- "6379"
networks:
- frontend
deploy:
replicas: 2
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
db:
image: postgres:9.4
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
deploy:
placement:
max_replicas_per_node: 1
constraints:
- "node.role==manager"
vote:
image: dockersamples/examplevotingapp_vote:before
ports:
- "5000:80"
networks:
- frontend
depends_on:
- redis
deploy:
replicas: 2
update_config:
parallelism: 2
restart_policy:
condition: on-failure
result:
image: dockersamples/examplevotingapp_result:before
ports:
- "5001:80"
networks:
- backend
depends_on:
- db
deploy:
replicas: 1
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
worker:
image: dockersamples/examplevotingapp_worker
networks:
- frontend
- backend
deploy:
mode: replicated
replicas: 1
labels: [APP=VOTING]
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
window: 120s
placement:
constraints:
- "node.role==manager"
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
stop_grace_period: 1m30s
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints:
- "node.role==manager"
networks:
frontend:
backend:
volumes:
db-data:
This is a curated list of all the important configuration options that are extensively used in a Compose file. I will explained them with examples below. Let's get started.
Building your own Blog website is very common in the real-world, let's get started to build our own blog website via WordPress. In the example, I will demonstrates you in two ways to implement the blog system. One is using the docker compose
, the other one is using the docker CLI
. We will see how effective, productive using Docker Compose
.
Step 1. Defind the services that make up blog app in docker-compose.yml.
# mkdir my-wordpress && cd my-wordpress
# cat docker-compose.yml
version: "3.9"
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
volumes:
- wordpress_data:/var/www/html
ports:
- "80"
restart: always
deploy:
replicas: 3
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
db_data: {}
wordpress_data: {}
Step 2. Use docker compose up
to create and run all containers, network, volumes for blog application.
# pwd
/root/my-wordpress
# docker compose up -d
[+] Running 7/7
⠿ Network my-wordpress_default Created 0.1s
⠿ Volume "my-wordpress_wordpress_data" Created 0.0s
⠿ Volume "my-wordpress_db_data" Created 0.0s
⠿ Container my-wordpress-db-1 Started 0.6s
⠿ Container my-wordpress-wordpress-3 Started 1.6s
⠿ Container my-wordpress-wordpress-2 Started 1.7s
⠿ Container my-wordpress-wordpress-1 Started 1.8s
# docker compose ps
NAME COMMAND SERVICE STATUS PORTS
my-wordpress-db-1 "docker-entrypoint.s…" db running 33060/tcp
my-wordpress-wordpress-1 "docker-entrypoint.s…" wordpress running 0.0.0.0:49161->80/tcp
my-wordpress-wordpress-2 "docker-entrypoint.s…" wordpress running 0.0.0.0:49159->80/tcp
my-wordpress-wordpress-3 "docker-entrypoint.s…" wordpress running 0.0.0.0:49160->80/tcp
# docker compose stop
[+] Running 4/4
⠿ Container my-wordpress-wordpress-3 Stopped 1.4s
⠿ Container my-wordpress-wordpress-2 Stopped 1.5s
⠿ Container my-wordpress-wordpress-1 Stopped 1.6s
⠿ Container my-wordpress-db-1 Stopped 1.5s
# docker compose start db
[+] Running 1/1
⠿ Container my-wordpress-db-1 Started 0.5s
# docker compose start wordpress
[+] Running 3/3
⠿ Container my-wordpress-wordpress-2 Started 0.7s
⠿ Container my-wordpress-wordpress-1 Started 0.6s
⠿ Container my-wordpress-wordpress-3 Started 0.7s
# docker compose down
[+] Running 5/5
⠿ Container my-wordpress-wordpress-3 Removed 1.5s
⠿ Container my-wordpress-wordpress-1 Removed 1.4s
⠿ Container my-wordpress-wordpress-2 Removed 1.5s
⠿ Container my-wordpress-db-1 Removed 1.4s
⠿ Network my-wordpress_default Removed 0.2s
This example demonstrates how to build your own blog web site with wordpress
in Docker.
Step 1. Create network dedicated for blog component containers
docker network ls
docker network create --subnet 172.21.0.0/16 --ip-range 172.21.240.0/20 personal-blog
docker network ls
Step 2. Start empty MySQL server instance
docker run --name wordpress-mysql -t \
-e DB_SERVER_HOST="wd-mysql-server" \
-e MYSQL_DATABASE="wordpress" \
-e MYSQL_USER="wordpress" \
-e MYSQL_PASSWORD="wordpress_pwd" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
--network=personal-blog \
--restart unless-stopped \
-d mysql:8.0 \
--character-set-server=utf8 \
--collation-server=utf8_bin \
--default-authentication-plugin=mysql_native_password
Step 3. Start WordPress server instance and link the instance with created MySQL server instance
docker run --name "cerek-wordpress" -t \
-e WORDPRESS_DB_HOST="wordpress-mysql" \
-e WORDPRESS_DB_USER='wordpress' \
-e WORDPRESS_DB_PASSWORD='wordpress_pwd' \
-e WORDPRESS_DB_NAME='wordpress' \
--network personal-blog \
-p 80:80 \
-d wordpress
Step 4. Access blog via http://${DOCKER_IP}