What is Docker Compose?
Docker Compose is a tool that allows you to configure, build and run multiple containers. It's incredibly useful for building and deploying apps that use multiple services, each with their own container.
For example, let's say you have an app that uses 3 services:
site: An ecommerce site that lets users browse and shop for items.
database: A database that stores user, product, and order information.
notifier: A script that monitors your database and sends email notifications to users when their orders have shipped.
Your app directory structure would look like this:
app ├── database │ └── Dockerfile │ └── ... ├── notifier │ └── Dockerfile │ └── ... └── site └── Dockerfile └── ...
Normally, you'd have to start 3 containers yourself, either by running
docker run for each image or by writing a custom script to launch them all. But with Docker Compose, you can launch all 3 containers with a single file AND configure them to boot.
How do I use Docker Compose?
Let's expand on our example above. To use
Docker Compose with our app, we add a
docker-compose.yml file to the top level of our project directory:
app ├── docker-compose.yml ├── database │ └── Dockerfile │ └── ... ├── notifier │ └── Dockerfile │ └── ... └── site └── Dockerfile └── ...
The contents of our docker
docker-compose.yml file would be:
# line below tells docker-compose which version of the docker-compose file format to use version: "3.8" services: database: build: ./database notifier build: ./notifier site: build: ./site
The lines above define each service and tell Docker compose where to find their build files. To build the images for services, we'd run the command
docker-compose build from the top level of the project directory. And to run them, we'd use the command
docker-compose.yml file above is very basic. But Docker compose allows you to configure your services in all sorts of ways. For example: we could add a few lines to tell
docker-compose that the
notifier services depend on the
database service, and that the
database service needs to build and run successfully before the others:
version: "3.8" services: site: build: ./app depends_on: - database notifier build: ./notifier depends_on: - database db: build: ./database
Note that each of our services still has their own Dockerfile. This is useful for long, service specific configurations, when a service might have a long and/or complex Dockerfile. However, you could include all of the configuration options for a service in your
docker-compose.yml file if you wanted.
For example - let's assume the
database service has 2 files:
app ├── docker-compose.yml ├── database │ └── Dockerfile │ └── init.sql ├── notifier │ └── Dockerfile │ └── ... └── site └── Dockerfile └── ...
Let's also assume the contents of
database/Dockerfile are as follows:
FROM postgres:13 COPY ./init.sql /docker-entrypoint-initdb.d/init.sql
This simply tells Docker which image to use for
database, and copies a single file (
init.sql) to the container on build. Note that
/docker-entrypoint-initdb.d is a special directory on
postgres images, and that
.sql files in this directory are run when postgres starts.
We could remove our
database/Dockerfile entirely by changing our
docker-compose.yml as below:
version: "3.8" services: site: build: ./app depends_on: - database notifier build: ./notifier depends_on: - database database: image: "postgres:13" volumes: "./init.sql:/docker-entrypoint-initdb.d/init.sql"
This achieves the same effect - Docker Compose now knows which image to use for
database, and will copy our
init.sql file to the appropriate place in the container (
volumes is slightly different than
COPY, but I won't get into that here).
Hope that's enough to get you started using Docker compose on your own! If you want to learn more, I highly recommend reading the Docker compose docs.