This article is going to introduce Docker Compose and show how to put it to work for your needs. We will install it, write a simple Compose file and launch the container.
We will then see how to launch multiple containers. Then we will see how to build images and lately how to use multiple Compose files to launch containers in different environments, like development and production, for example.
- How to install Docker Compose
- How to write a simple Compose file
- How to execute docker-compose commands to start and stop containers
- How to launch multiple containers
- How to build images with Docker Compose
- How to override using multiple Docker Compose files
Software Requirements and Conventions Used
|Category||Requirements, Conventions or Software Version Used|
|Other||Privileged access to your Linux system as root or via the |
|Conventions|| # - requires given linux commands to be executed with root privileges either directly as a root user or by use of |
We have so far seen how Docker is great for managing images and starting containers. But frequently applications require that different containers are up and communicating with each other. Connecting them through the network, making them share disk volumes, and passing environment variables can easily turn into a sequence of commands that are difficult to document and maintain over time. There enters Docker Compose. Let’s start installing it and then write the Compose file.
Installing Docker Compose
In Ubuntu 18.04 installing Docker Composer is straightforward:
# apt install docker-compose
To test it is installed you can check it’s version:
$ docker-compose -v docker-compose version 1.17.1, build unknown
Docker Engine and Docker Compose versions are important since their releases are frequent and features are added and removed. The version shown above (1.17.1) was released in November 2017. If you need a newer release, you may either enable Ubuntu’s Universe repository and get a newer package, or even download and install the latest release directly from the Docker Compose website:
# curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # sudo chmod +x /usr/local/bin/docker-compose
The Docker Compose File
Docker Compose reads a YAML file, which is usually named
version: "3" services: apache: image: php:7.3-apache container_name: 'apache' ports: - "80:80" volumes: - ./www:/var/www/html
In the beginning, the syntax version is informed as 3. Next, in the services section, only one container is specified (apache) and the tags
volumes are used to describe how it shall be executed.
Now create a directory named
www and drop this
index.html file inside.
<html> <body> Hello </body> </html>
Next, to test PHP is working just drop this file inside
<?php phpinfo(); ?>
Docker Compose Commands
up command will take care of everything: download the images from Docker Hub if they don’t still exist in the local cache, build custom images (which is not the case; we’ll cover that int he next section) and start the containers.
$ docker-compose up -d
-d switch instructs Docker Compose to run containers in the background. In case another filename is used, instead of
docker-compose.yml, it can be informed with
Notice that the launch command is much simpler than it’s
docker run counterpart. It has two more advantages: it doesn’t change regardless of the content of the Compose file, and if the Compose file specifies more than one container, all of them will be started. Just for comparison, the docker run command would be:
$ docker run -d --name='apache-alone' -p 80:80 -v $PWD/www:/var/www/html php:7.3-apache
Because the Compose file syntax is YAML, indentation matters. If you get syntax errors, check the YAML syntax with an online parser, like this one.
You can check the container is running.
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3937d997e029 php:7.3-apache "docker-php-entrypoi…" 8 minutes ago Up 8 minutes 0.0.0.0:80->80/tcp apache
http://localhost in your preferred browser and then
Launching multiple containers
Let’s now see a more complex Compose file. Let’s imagine we are going to setup a local environment to develop a LAMP application. We need a container with Apache and PHP, another container with MySQL, and possibly a PHPMyAdmin container to interact with MySQL. The
docker-compose.yml will be:
version: "3" services: apache: image: php:7.3-apache container_name: 'apache' restart: 'always' ports: - "80:80" - "443:443" volumes: - ./www:/var/www/html - ./php/php.ini:/usr/local/etc/php/php.ini - ./sites-enabled:/etc/apache2/sites-enabled - apache-logs:/var/log/apache2 mysql: image: mariadb:10.4 container_name: 'mysql' restart: 'always' volumes: - mysql-data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: somepassword MYSQL_DATABASE: db_site MYSQL_USER: user MYSQL_PASSWORD: password phpmyadmin: image: phpmyadmin/phpmyadmin:4.8 container_name: 'phpmyadmin' environment: PMA_HOST: mysql PMA_PORT: 3306 ports: - '8080:80' volumes: apache-logs: mysql-data:
This Compose file is launching three containers, each has a section under services. Notice we are defining some environment variables under
restart: always definition is instructing Docker to start the containers automatically when the Docker service is started (in case of a reboot, for example).
The command to start the three containers is the same as in the previous simple example. Easy to remember, right?
$ docker-compose up -d
Check the containers are created.
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f76ece3508fe phpmyadmin/phpmyadmin:4.8 "/run.sh supervisord…" 20 seconds ago Up 4 seconds 9000/tcp, 0.0.0.0:8080->80/tcp phpmyadmin 69b1b5054f3d mariadb:10.4 "docker-entrypoint.s…" 20 seconds ago Up 6 seconds 3306/tcp mysql 6747d7580dac php:7.3-apache "docker-php-entrypoi…" 2 days ago Up 14 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp apache
It’s interesting to notice that the containers can communicate through their names and access each other's ports without the need to expose their ports to the host. For example, we didn’t expose port 3306 of MySQL service (as can be seen in the output above), but PHPMyAdmin is able to access this port. To access PHPMyAdmin, go to
http://localhost:8080 and log in with user and password defined in MySQL service (user / password).
Building Images With Docker Compose
If you need to build an image, instead of using an existing one, just add a
build tag. In the example below, we are telling Docker Compose to look into the current directory for a Dockerfile. The image tag will be used to name the new image.
version: "3" services: apache: build: . image: my-image-name container_name: 'apache' restart: 'always' ports: - "80:80"
Override Using Multiple Docker Compose Files
Docker Compose makes easy to customize the launch of containers for different environments. You just need to create the called override files and launch the containers specifying them. They will overwrite previous definitions made in the base Compose file.
For example, let’s create an override file named
docker-compose-prod.yml and define a different password for MySQL.
version: "3" services: mysql: environment: MYSQL_ROOT_PASSWORD: somepassword_other MYSQL_DATABASE: db_site_other MYSQL_USER: user_other MYSQL_PASSWORD: password_other
You can use another host to start the containers. If you are using the same host, it’s needed to delete the mysql container and it’s associated volume. Otherwise, the existing container with the old credentials will be used.
$ docker stop mysql $ docker rm mysql $ docker volume ls $ docker volume rm directory_mysql-data
And then you can execute the command below. It’s important to keep the order of the files. Multiple files can be used. In our example, only the
environment section of
mysql service will be overridden.
$ docker-compose -f docker-compose.yml -f docker-compose-prod.yml up -d
After checking the containers are running, try to access PHPMyAdmin using the new credentials.
This article introduced Docker Compose, a handy tool to orchestrate the launch of multiple containers in the same host. There are many possibilities and reading the Docker Compose manual is highly recommended. In the next articles, we are going to explore ways to orchestrate Docker containers among multiple hosts.