This series of articles on Docker has so far covered a number of examples of creating and running individual Docker containers. We’ve also seen an example of how multiple Docker containers can be linked together using the –link command line flag.
Best practice for containerization suggests that each container does exactly one job. A full environment stack for a complex application may comprise many components – databases, web applications, web/micro services – each requiring its own container. Setting up the full working environment stack may require several lines of docker run commands, run in the right order, with just the right flags and switches set.
An obvious way to manage this is with a startup script. A neater solution is to use Docker Compose. Docker Compose allows multi-container applications to be defined in a single file and then started from a single command.
To recap, this series covers:
- Running Containers: Installing Docker and starting containers;
- Building Images: How to create a new container image, customized to your requirements;
- Disposable Containers: Using containers to run a short-lived job rather than a long-lived service;
- Composing an Environment Stack: (this post).
The Spanners application stack
It will come as no surprise to regular readers that I’ll use the Spanners demo application to demonstrate Docker Compose. Spanners requires a near trivial application stack – it’s a simple webserver / database application. The Dockerized containers for the Spanners demo application are available on Docker Hub. Part 2 in this series describes how to run them using the docker run command:
sudo docker run --name spanners-database -e MYSQL_ROOT_PASSWORD=my-secret-pw -d hotblac/spanners-database:3.2 sudo docker run --name spanners-webserver --link spanners-database:spanners-database -p 8080:8080 -d hotblac/spanners-webserver:3.2
This demonstrates a shortcoming in Docker. Each image is near trivial – the Dockerfile for each is just a few lines long. The full application stack is also simple – just two servers linked together. But the commands to run these trivial container images in a simple way are quite complex. There are just too many command line switches. In a more realistic environment stack consisting of a dozen or more containers, this would be unmanageable.
Docker Compose exists to manage this complexity.
Composing the stack
Docker Compose allows multi-container applications to be defined in a YAML file. The file contains a definition of every container in the application and their switches / flags. It’s best illustrated with an example:
database: environment: MYSQL_ROOT_PASSWORD: my-secret-pw image: hotblac/spanners-database:3.2 webserver: links: - database:spanners-database ports: - "8080:8080" image: hotblac/spanners-webserver:3.2
This docker-compose.yml file defines two containers labelled database and webserver. The container image is defined for each (hotblac/spanners-database:3.2 and hotblac/spanners-webserver:3.2 respectively).
Specific settings that would normally be defined as command line switches of the docker runcommand can be defined in the docker-compose.yml file. In this case, the database container’s environment settings and the webserver’s link and port settings are defined. This makes the docker-compose.ymlfile equivalent to the two long docker run commands above.
Running the stack
All containers comprising the application can be started with a single simple command:
sudo docker-compose up -d
This command starts all containers defined in ./docker-compose.yml. The -d flag here runs all containers detached – how we’d usually prefer service containers to run. Omitting this flag would start all containers interactively and all shell output of each container would be shown in the host shell.
The containers can be stopped just as easily:
sudo docker-compose stop
Additional docker-compose commands are available, but these two are usually all we need.
Running a containerized application on another machine
Docker Compose makes it trivial to run a full multi-container application on any machine that has Docker and Docker Compose installed. To demonstrate, here are the instructions for running the Spanners demo app. There’s no need to download the source code or install a webserver or database. You don’t even need Java.
- Download the 10 line Spanners docker-compose.yml file
- In the download directory, run sudo docker-compose up -d
- That’s it!
Docker Compose will start the database and webserver containers as defined in the compose file. Docker itself will download the images of these containers if necessary. Browsing to http://localhost:8080/spanners-mvc/ will show the Spanners app welcome page (you can login as jones / password).
The potential benefits should be obvious. A complete working environment stack can be spun up on any developer workstation or server in a matter of seconds. At the moment, Docker Compose is not recommended for production environments. However, Docker Compose can be used to very cheaply create development and test environments. Indeed, one suggested use case is to create a ‘disposable’ CI environment in which build tests are run. When the build is complete, the environment is simply stopped and discarded.