Docker Compose, in summary, allows multiple containers (or applications) to interact with each other when needed while running in isolation from one another.
You may have noticed a problem with Docker so far. More often than not, applications require additional services to run, which we cannot do in a single container. For example, modern - dynamic - websites use services such as databases and a web server. For the sake of this task, we will consider each application as a “microservice”.
While we can spin up multiple containers or “microservices” individually and connect them, doing so one by one is cumbersome and inefficient. Docker Compose allows us to create these “microservices” as one singular “service”.
This illustration shows how containers are deployed together using Docker Compose Vs. Docker:
Before we demonstrate Docker Compose, let’s cover the fundamentals of using Docker Compose.
We need Docker Compose installed (it does not come with Docker by default). Installing it is out of scope for this room, as it changes depending on your operating system and other factors. You can check out the installation documentation.
We need a valid docker-compose.yml file
A fundamental understanding of using Docker Compose to build and manage containers.
up
This command will (re)create/build and start the containers specified in the compose file.
Example: docker-compose up
start
This command will start (but requires the containers already being built) the containers specified in the compose file.
Example: docker-compose start
down
This command will stop and delete the containers specified in the compose file.
Example: docker-compose down
stop
This command will stop (not delete) the containers specified in the compose file.
Example: docker-compose stop
build
This command will build (but will not start) the containers specified in the compose file.
Example: docker-compose build
Now, we could manually run the two containers via the following:
Creating the network between the two containers: docker network create ecommerce
Running the Apache2 webserver container: docker run -p 80:80 --name webserver --net ecommerce webserver
Running the MySQL Database server: docker run --name database --net ecommerce webserver
Instead, we can use Docker Compose via docker-compose up to run these containers together, giving us the advantages of:
One simple command to run them both
These two containers are networked together, so we don’t need to go about configuring the network.
Extremely portable. We can share our docker-compose.yml file with someone else, and they can get the setup working precisely the same without understanding how the containers work individually.
Easy to maintain and change. We don’t have to worry about specific containers using (perhaps outdated) images.
Docker-compose.yml files 101
One file to rule them all. The formatting of a docker-compose.yml file is different to that of a Dockerfile. It is important to note that YAML requires indentation (a good practice is two spaces which must be consistent!).
Docker-compose.yml files 101
version
This is placed at the top of the file and is used to identify what version of Compose the docker-compose.yml is written for.
Example: '3.3'
Docker-compose.yml files 101
services
This instruction marks the beginning of the containers to be managed.
Example: services:
Docker-compose.yml files 101
name (replace value)
This instruction is where you define the container and its configuration. "name" needs to be replaced with the actual name of the container you want to define, i.e. "webserver" or "database".
Example: webserver
Docker-compose.yml files 101
build
This instruction defines the directory containing the Dockerfile for this container/service. (you will need to use this or an image).
Example: ./webserver
Docker-compose.yml files 101
ports
This instruction publishes ports to the exposed ports (this depends on the image/Dockerfile).
Example: '80:80'
Docker-compose.yml files 101
volumes
This instruction lists the directories that should be mounted into the container from the host operating system.
This instruction is used to pass environment variables (not secure), i.e. passwords, usernames, timezone configurations, etc.
Example: MYSQL_ROOT_PASSWORD=helloworld
Docker-compose.yml files 101
image
This instruction defines what image the container should be built with (you will need to use this or build).
Example: mysql:latest
Docker-compose.yml files 101
networks
This instruction defines what networks the containers will be a part of. Containers can be part of multiple networks (i.e. a web server can only contact one database, but the database can contact multiple web servers).
Example: ecommerce
With that said, let’s look at our first docker-compose.yml file. This docker-compose.yml file assumes the following:
We will run one web server (named web) from the previously mentioned scenario.
We will run a database server (named database) from the previously mentioned scenario.
The web server is going to be built using its Dockerfile, but we are going to use an already-built image for the database server (MySQL)
The containers will be networked to communicate with each other (the network is called ecommerce).