How To Launch Containers With Docker Compose

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.

In this tutorial you will learn:

  • 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

PHPMyAdmin

PHPMyAdmin.

Software Requirements and Conventions Used

Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Ubuntu 18.04
Software Docker Compose
Other Privileged access to your Linux system as root or via the sudo command.
Conventions # – requires given linux commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires given linux commands to be executed as a regular non-privileged user

Introduction



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 docker-compose.yml.

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 image, container_name, ports, and 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 www.

<?php
        phpinfo();
?>


Docker Compose Commands

The 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

The -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 -f.

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

Now access http://localhost in your preferred browser and then http://localhost/phpinfo.php.



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 environment. The 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.

Conclusion

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.

More in this Docker article series



Comments and Discussions
Linux Forum