Docker Compose is a tool that helps you define and run multi-container applications. Instead of you building, running and connecting containers from separate Dockerfiles, it allows you to use a YAML file (called the Compose file) to define all of your application’s services, after which you can create and start them by using a single command.
Some of the most popular uses of Docker Compose include single application deployments, automated testing and local development.
In this tutorial we’ll learn how to install Docker Compose by the end of it, you should have a basic understanding of some of its’ commands and how it works.
NOTE: Even though this tutorial is written for Ubuntu 18.04, the commands should apply to other operating systems as well.
- A non-root sudo user. You can check our tutorial [How to Create a Sudo User on Ubuntu] to see how to set it up.
- Docker installed and optionally allowing non-sudo access to Docker. To do this, you can follow Step 1 and Step 2 from our previous tutorial – [How to Install & Use Docker on Ubuntu 18.04]
NOTE: Since it’s optional for readers to allow non-sudo access to Docker, the command examples will have
sudo appended to the
docker command, for those who have not enabled non-sudo access.
Table of Contents
Step 1 — Install Docker Compose
Check the latest Docker Compose releases here https://github.com/docker/compose/releases, and replace the version in the following command (
1.23.2 ) with the version you see tagged as the
Latest release, to download the latest version:
$ sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-
uname -m-o /usr/local/bin/docker-compose
Set executable permissions to the Docker Compose binary:
$ sudo chmod +x /usr/local/bin/docker-compose
Check if the installation was successful by checking the Compose version:
$ docker-compose --version
The output should look something like this:
docker-compose version 1.23.2, build 1110ad01
Step 2 — Docker Compose Basics
With Docker Compose installed we can get to running our first container using it. We’ll use the well known Hello World example. To do this we’ll create our first Compose file.
The Compose files are YAML files, and one of the default names that Docker Compose looks for is called
If you want to name the Compose file something else, then you have to use the
-fargument followed by the alternate file name.
Now let’s create a directory for the YAML file and move into it:
$ mkdir hello-world $ cd hello-world
Use your preferred text editor and create the
$ nano docker-compose.yml
Add the following contents in the file:
my-test: image: hello-world
Let’s see what each line means:
my-test – will be used as part of the container name
image: hello-world – we’re telling Docker Compose to use the image by the name hello-world. Just like when we use
docker run hello-world, it will search locally and if it doesn’t find it, it’ll try to
pull it from Docker Hub.
Save and exit the file when you’re finished.
While we’re still in the
~/hello-world directory, we’ll execute the following command:
$ sudo docker-compose up
Now, just like when running
docker run hello-world, it’ll search locally for the hello-world image, and download it from Docker Hub if it doesn’t find it.
The output will look something like this when it’s finished:
Pulling my-test (hello-world:)... latest: Pulling from library/hello-world d1725b59e92d: Pull complete Creating hello-world_my-test_1 ... done Attaching to hello-world_my-test_1 ...
After pulling the image, Docker Compose creates a container from it, attaches, and runs the [hello] program, which then outputs the message confirming that the installation is working and explains the steps that Docker ran through:
... my-test_1 | my-test_1 | Hello from Docker! my-test_1 | This message shows that your installation appears to be working correctly. my-test_1 | my-test_1 | To generate this message, Docker took the following steps: my-test_1 | 1. The Docker client contacted the Docker daemon. my-test_1 | 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. my-test_1 | (amd64) my-test_1 | 3. The Docker daemon created a new container from that image which runs the my-test_1 | executable that produces the output you are currently reading. my-test_1 | 4. The Docker daemon streamed that output to the Docker client, which sent it my-test_1 | to your terminal. ...
Since Docker containers only run as long as the command is active, the container stopped after the
hello program finished running.
We can see that the container is stopped by checking
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
And if we check all of the containers, by using the
-a flag, we can see the container created:
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 17cd42c3da63 hello-world "/hello" About an hour ago Exited (0) About an hour ago hello-world_my-test_1
Using this information, we can remove the container when we’re done with it, to keep things clean. We can remove the container by using the
docker rm command, followed by the name or ID of the container:
$ sudo docker rm hello-world_my-test_1
$ sudo docker rm 17cd42c3da63
When all the containers referencing an image are removed, we can also remove the image by using the
docker rmi command:
$ sudo docker rmi hello-world
You can check out the details and examples on how the
rmisubcommand works in the official Docker documentation
Step 3 — Docker Compose Commands
So we ran
docker-compose up to run a container which ran the
hello program that displayed the output message and then exited. This is not ideal, however. What we want is for
docker-compose to act more like a service.
The Hello World container exits after it’s run, so we’ll need a container that keeps running.
Starting a Container as a Background Process
For this example we’ll use nginx.
Let’s set up a new directory for nginx and move into it:
$ mkdir ~/nginx $ cd ~/nginx
Now create the
docker-compose.ymlfile and paste the following content:
nginx: image: nginx
Save and exit the file when you’re finished.
Now we’ll run the nginx container as a background process by running
docker-compose up and by adding the
-d switch, which tells it do
NOTE: If we don’t add the
-dswitch, then we’d have to type
Ctrl+Cto exit the process.
To start the container and detach, run:
$ sudo docker-compose up -d
The nginx image will be downloaded and the container will be started in the background.
We can see our active containers with the command:
$ sudo docker ps
The output looks something like this:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ff9d47aa7014 nginx "nginx -g 'daemon of…" 9 minutes ago Up 3 seconds 80/tcp nginx_nginx_1
Interacting with a Running Container
If you need to interact with a running container, we can do so by using the
docker exec command, followed by its’ ID or name, to start a shell inside the running container:
$ sudo docker exec -it nginx_nginx_1 /bin/bash
-t switch opens up a terminal, the
-i switch makes it interactive, and by using the
/bin/bash option we’re opening a bash shell in the running container.
You’ll notice your prompt change to
You can now work from the command prompt.
IMPORTANT: Keep in mind, however, that unless you are in a directory that is part of a
data volume ( a linked path on the host machine that can be used by the container ) , your changes will disappear when the container restarts.
That covers installing Docker Compose and a basic usage of it, however there’s more to learn in order to really have fun with it.
To see the full list of configuration options for the
docker-compose.yml file, please check the official Docker Documentation and refer to the Compose file reference.
If you’ve found any issues with this tutorial, or have any questions, then please do not hesitate to contact us.
Also, if you’re looking for a high performance VPS, then do check out our KVM SSD Plans. Our offer starts at 1GB RAM + 10GB SSD at just $9.99/mo.