Docker compose, formerly known as Fig, is a tool which can define and run complex applications using Docker. Basically it does the job of creating multiple containers and links between them.
Using Docker Compose requires defining the environment required for your app using a Dockerfile and the services required for the app in a '.yml' file. One can then use a single command to create and start all the services from the configuration file. In this writeup, we will learn how to install and use compose on Ubuntu 15.10. We will also touch upon how to run your app using it.
Installation
The prerequisite to installing Docker Compose is Docker Engine. If you have not already installed Docker Engine, here are the quick steps for the same:
$ sudo apt-get update $ sudo apt-get install linux-image-extra-$(uname -r) $ sudo apt-get install docker-engine
To verify if the Docker installation was successful, let us run a hello-world program:
$sudo docker run hello-world
poornima@BNPTHKPD:~$ sudo docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 03f4658f8b78: Pull complete a3ed95caeb02: Pull complete Digest: sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7 Status: Downloaded newer image for hello-world:latest Hello from Docker. This message shows that your installation appears to be working correctly. .......
Now to install Compose, execute the following curl command in the terminal:
$ curl -L https://github.com/docker/compose/releases/download/1.7.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
Set executable permissions to the binary
$ chmod +x /usr/local/bin/docker-compose
Verify if the installation is complete:
$docker compose --version
root@BNPTHKPD:/home/poornima# docker-compose --version docker-compose version 1.7.0, build 0d7bf73
Docker compose commands
Before we go ahead and learn how to run your applications using Compose, let me introduce you to some of its important commands.
Syntax for docker-compose command is
docker-compose [-f=...] [options] [commands] [args]
One can verify the version of docker-compose using:
docker-compose -v, --version
When used with 'ps' command, it lists the available containers
docker-compose ps
You can create and start your containers using the 'up' command and adding '-d' option will run the containers in the background
docker-compose up -d
Listed below are some more commands that can be used with docker-compose:
build - to build services pause / unpause - pause and unpause services stop - stop services restart - restart services rm - remove stopped containers logs - view output from containers help - to get help on a command
Building and Running your app
In this section, we will focus on building a simple Python web application and running it using Docker Compose.
Setup
Let us first create a directory for our app.
poornima@BNPTHKPD:~$ mkdir dockcompose poornima@BNPTHKPD:~$ cd dockcompose/
We will now create a Hello World web application myapp.py using the Flask framework in this directory with the following contents:
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World using Docker Compose' if __name__ == '__main__': app.run(debug=True,host='0.0.0.0')
Create a requirements.txt file in the same project directory containing the following:
Flask==0.10.1
In the next step, we need to create a Docker image containing all the dependencies that the Python application needs.
Creating a Docker Image
For this, create a file called Dockerfile again in the project directory with the following contents:
FROM python:2.7 ADD . /code WORKDIR /code RUN pip install -r requirements.txt CMD python myapp.py
This file informs Docker to build an image using Python 2.7, add the directory '.' into the path '/code' in the image, set the working directory to /code, install Python dependencies as mentioned in the requirements.txt file and set the default command of the container to 'python myapp.py'
We will now build the image.
$ docker build -t web .
poornima@BNPTHKPD:~/dockcompose$ sudo docker build -t web . Sending build context to Docker daemon 5.632 kB Step 1 : FROM python:2.7 ---> a3b29970a425 Step 2 : ADD . /code ---> 855e1a126850 Removing intermediate container 2e713165c053 Step 3 : WORKDIR /code ---> Running in 431e3f52f421 ---> 157b4cffd6df Removing intermediate container 431e3f52f421 Step 4 : RUN pip install -r requirements.txt ---> Running in 07c294591a76 Collecting Flask==0.10.1 (from -r requirements.txt (line 1)) Downloading Flask-0.10.1.tar.gz (544kB) Collecting Werkzeug>=0.7 (from Flask==0.10.1->-r requirements.txt (line 1)) Downloading Werkzeug-0.11.8-py2.py3-none-any.whl (306kB) Collecting Jinja2>=2.4 (from Flask==0.10.1->-r requirements.txt (line 1)) Downloading Jinja2-2.8-py2.py3-none-any.whl (263kB) Collecting itsdangerous>=0.21 (from Flask==0.10.1->-r requirements.txt (line 1)) Downloading itsdangerous-0.24.tar.gz (46kB) Collecting MarkupSafe (from Jinja2>=2.4->Flask==0.10.1->-r requirements.txt (line 1)) Downloading MarkupSafe-0.23.tar.gz Building wheels for collected packages: Flask, itsdangerous, MarkupSafe Running setup.py bdist_wheel for Flask: started Running setup.py bdist_wheel for Flask: finished with status 'done' Stored in directory: /root/.cache/pip/wheels/d2/db/61/cb9b80526b8f3ba89248ec0a29d6da1bb6013681c930fca987 Running setup.py bdist_wheel for itsdangerous: started Running setup.py bdist_wheel for itsdangerous: finished with status 'done' Stored in directory: /root/.cache/pip/wheels/97/c0/b8/b37c320ff57e15f993ba0ac98013eee778920b4a7b3ebae3cf Running setup.py bdist_wheel for MarkupSafe: started Running setup.py bdist_wheel for MarkupSafe: finished with status 'done' Stored in directory: /root/.cache/pip/wheels/94/a7/79/f79a998b64c1281cb99fa9bbd33cfc9b8b5775f438218d17a7 Successfully built Flask itsdangerous MarkupSafe Installing collected packages: Werkzeug, MarkupSafe, Jinja2, itsdangerous, Flask Successfully installed Flask-0.10.1 Jinja2-2.8 MarkupSafe-0.23 Werkzeug-0.11.8 itsdangerous-0.24 ---> 9ef07d3ed698 Removing intermediate container 07c294591a76 Step 5 : CMD python myapp.py ---> Running in ac5ce91ddc85 ---> 65d218cbea14 Removing intermediate container ac5ce91ddc85 Successfully built 65d218cbea14 poornima@BNPTHKPD:~/dockcompose$ sudo docker-compose up Starting dockcompose_web_1 Attaching to dockcompose_web_1 web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) web_1 | * Restarting with stat web_1 | * Debugger is active! web_1 | * Debugger pin code: 151-559-328 web_1 | 172.17.0.1 - - [19/Apr/2016 08:17:43] "GET / HTTP/1.1" 200 - web_1 | 172.17.0.1 - - [19/Apr/2016 08:17:43] "GET /favicon.ico HTTP/1.1" 404 -
This command can automatically locate the required Dockerfile, requirements.txt and myapp.py files and builds the image 'web' by using them.
Services files
Different services to be used in your app should be put together in a file called docker-compose.yml. The service file for our python HelloWorld app looks like the following:
web: build: . ports: - "5000:5000"
The above file is defining the web service which builds from the current directory and forwards the container's exposed port 5000 to port 5000 on the host.
Running the app
Now let's go to the project directory and run the app:
$docker-compose up
In order to view the app running, point your web browser to the following:
http://0.0.0.0:5000
Here is how your browser displays the message for you:
More commands
Let us try out some commands to see how they work.
Note: All the docker compose commands should be run from the directory that contains docker-compose.yml
To run your services in the background, use '-d' option.
poornima@BNPTHKPD:~/dockcompose$ sudo docker-compose up -d Starting dockcompose_web_1
To list all the containers, use the 'ps' option.
poornima@BNPTHKPD:~/dockcompose$ sudo docker-compose ps Name Command State Ports ------------------------------------------------------------------------- dockcompose_web_ /bin/sh -c Up 0.0.0.0:5000->50 1 python myapp.py 00/tcp
To take a look at the environment variables available in the configured service (in this case, web), use the 'env' option.
poornima@BNPTHKPD:~/dockcompose$ sudo docker-compose run web env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=d5c2b9eeab7f TERM=xterm WEB_PORT=tcp://172.17.0.2:5000 WEB_PORT_5000_TCP=tcp://172.17.0.2:5000 WEB_PORT_5000_TCP_ADDR=172.17.0.2 WEB_PORT_5000_TCP_PORT=5000 WEB_PORT_5000_TCP_PROTO=tcp WEB_NAME=/dockcompose_web_run_1/web WEB_ENV_LANG=C.UTF-8 WEB_ENV_GPG_KEY=C01E1CAD5EA2C4F0B8E3571504C367C218ADD4FF WEB_ENV_PYTHON_VERSION=2.7.11 WEB_ENV_PYTHON_PIP_VERSION=8.1.1 WEB_1_PORT=tcp://172.17.0.2:5000 WEB_1_PORT_5000_TCP=tcp://172.17.0.2:5000 WEB_1_PORT_5000_TCP_ADDR=172.17.0.2 WEB_1_PORT_5000_TCP_PORT=5000 WEB_1_PORT_5000_TCP_PROTO=tcp WEB_1_NAME=/dockcompose_web_run_1/web_1 WEB_1_ENV_LANG=C.UTF-8 WEB_1_ENV_GPG_KEY=C01E1CAD5EA2C4F0B8E3571504C367C218ADD4FF WEB_1_ENV_PYTHON_VERSION=2.7.11 WEB_1_ENV_PYTHON_PIP_VERSION=8.1.1 DOCKCOMPOSE_WEB_1_PORT=tcp://172.17.0.2:5000 DOCKCOMPOSE_WEB_1_PORT_5000_TCP=tcp://172.17.0.2:5000 DOCKCOMPOSE_WEB_1_PORT_5000_TCP_ADDR=172.17.0.2 DOCKCOMPOSE_WEB_1_PORT_5000_TCP_PORT=5000 DOCKCOMPOSE_WEB_1_PORT_5000_TCP_PROTO=tcp DOCKCOMPOSE_WEB_1_NAME=/dockcompose_web_run_1/dockcompose_web_1 DOCKCOMPOSE_WEB_1_ENV_LANG=C.UTF-8 DOCKCOMPOSE_WEB_1_ENV_GPG_KEY=C01E1CAD5EA2C4F0B8E3571504C367C218ADD4FF DOCKCOMPOSE_WEB_1_ENV_PYTHON_VERSION=2.7.11 DOCKCOMPOSE_WEB_1_ENV_PYTHON_PIP_VERSION=8.1.1 LANG=C.UTF-8 GPG_KEY=C01E1CAD5EA2C4F0B8E3571504C367C218ADD4FF PYTHON_VERSION=2.7.11 PYTHON_PIP_VERSION=8.1.1 HOME=/root
In order to stop containers, use the 'stop' option:
poornima@BNPTHKPD:~/dockcompose$ sudo docker-compose stop Stopping dockcompose_web_1 ... done
You can pause and unpause them using the 'pause' and 'unpause' option.
poornima@BNPTHKPD:~/dockcompose$ sudo docker-compose pause Pausing dockcompose_web_1 ... done poornima@BNPTHKPD:~/dockcompose$ sudo docker-compose ps Name Command State Ports ------------------------------------------------------------------------- dockcompose_web_ /bin/sh -c Paused 0.0.0.0:5000->50 1 python myapp.py 00/tcp poornima@BNPTHKPD:~/dockcompose$ sudo docker-compose unpause Unpausing dockcompose_web_1 ... done
Use the 'kill' command to stop all containers in one go.
$ sudo docker-compose kill
Compose logs can be reviewed using 'log' command.
$ sudo docker-compose logs
If one needs help to list all the available commands / options, use the help command.
poornima@BNPTHKPD:~/dockcompose$ sudo docker-compose --help Define and run multi-container applications with Docker. Usage: docker-compose [-f=...] [options] [COMMAND] [ARGS...] docker-compose -h|--help Options: -f, --file FILE Specify an alternate compose file (default: docker-compose.yml) -p, --project-name NAME Specify an alternate project name (default: directory name) --verbose Show more output -v, --version Print version and exit -H, --host HOST Daemon socket to connect to --tls Use TLS; implied by --tlsverify --tlscacert CA_PATH Trust certs signed only by this CA --tlscert CLIENT_CERT_PATH Path to TLS certificate file --tlskey TLS_KEY_PATH Path to TLS key file --tlsverify Use TLS and verify the remote --skip-hostname-check Don't check the daemon's hostname against the name specified in the client certificate (for example if your docker host is an IP address) Commands: build Build or rebuild services config Validate and view the compose file create Create services down Stop and remove containers, networks, images, and volumes events Receive real time events from containers exec Execute a command in a running container help Get help on a command kill Kill containers logs View output from containers pause Pause services port Print the public port for a port binding ps List containers pull Pulls service images restart Restart services rm Remove stopped containers run Run a one-off command scale Set number of containers for a service start Start services stop Stop services unpause Unpause services up Create and start containers version Show the Docker-Compose version information
Conclusion
Docker Compose is a wonderful tool to easily build a feature rich and scalable app. With its capabilities and simplicity, it is quite useful as a development tool. For more information on the tool and on building apps, please visit its official page