Docker Compose

Jarret B

Well-Known Member
Staff member
May 22, 2017
Reaction score
With Docker you can create containers and get other systems to interact with the containers. It can occur that you may want to create multiple containers at once.

Multiple containers can be created at one time with one command. When running multiple containers in a group it is mandatory that the containers are non-interactive. The containers must run on a single Terminal at once.

In the examples used in this article I will limit the number of containers to two, but more containers can be created.

Creation of Containers

If you should build multiple containers which are very similar or the same then the build time will be less since sections will be cached and re-used. In my first example I am creating two MineTest servers. They will be exactly the same except one server will use Port 30,000 and the other Port 30,001.

First, we can create a folder structure to work with for this example. You can change these as needed, but the location must be changed later in the ‘docker-compose.yml’ file:

cd ~
mkdir Docker
cd Docker
mkdir compose-mtest
cd compose-mtest
mkdir compose
mkdir mtserver1
mkdir mtserver2
touch compose/docker-compose.yml
touch mtserver1/dockerfile
touch mtserver2/dockerfile

The contents of ‘dockerfile’ for ‘mtserver1’ and ‘mtserver2’ needs to be filled as follows:

FROM ubuntu:xenial
RUN apt update
RUN apt install software-properties-common -y
RUN add-apt-repository ppa:minetestdevs/stable
RUN apt update
RUN apt install minetest -y
RUN mkdir /root/.minetest
COPY ./minetest.conf /root/.minetest/minetest.conf
CMD ["/usr/bin/minetest","--server"]

The ‘dockerfile’ in both folders should contain the same entries. The ‘minetest.conf’ file can be downloaded by performing:


The file should download and you can edit the file to make changes, but none are needed. The file needs to be renamed so it will be copied by the script into the container with the command:

mv minetest.conf.example minetest.conf

Place the ‘minetest.conf’ in both the ‘mtserver1’ and ‘mtserver2’ folders with ‘dockerfile’.
In the ‘compose’ folder you will edit ‘docker-compose.yml’ and place the following into it:

version: '3'
      build: /home/jarret/Docker/compose-mtest/mtserver1/.
         - "30000:30000/udp"

      build: /home/jarret/Docker/compose-mtest/mtserver2/.
         - "30001:30000/udp"

NOTE: Each indent is at least 1 space. Use spaces and not tabs. Keep indentations the same throughout the ‘yml’ file. Make sure you stick to proper indentation or errors can occur.

The first line specifies we are using Docker-Compose version 3. The second line shows we are going to create services. Looking at lines 3 and 8 we are creating two services named ‘mtserver1’ and ‘mtserver2’. The service names match the folder names, but this is not necessary. On the ‘build’ lines the ‘dockerfile’ location is specified for each service. Lines 5 and 10 show we are creating a Port mapping. The Port mapping for ‘mtserver1’ is 30,000 for input and 30,0000 for output using UDP. The Port mapping for ‘mtserver2’ sets an input for Port 30,001 and an output of 30,000. The Port mapping allows ‘mtserver1’ to be accessed on Port 30,000 from the the network and ‘mtserver2’ from Port 30,001.

NOTE: It is imperative that multiple services do not use the same Port mapping or an error is generated. Port mappings are specified in the ‘docker-compose.yml’ file and not from the command line.

Since each MineTest server will be receiving connections internally on Port 30,000 there is no need to change the ‘minetest.conf’ file.
Once these changes have all been saved you can open a Terminal in the folder ‘~/Docker/compose-mtest/compose’.
Now comes the magic!
At the command prompt enter the following command:

docker-compose building
docker-compose up

The first line causes the images to be created from the two ‘dockerfile’ files. The second command will start the two containers.

NOTE: If the images are not created then the ‘docker-compose up’ command will build the images and start them.

You should see something similar to Figure 1.

Figure 1.jpg


From another system on the network you can connect to the 2 containers by using the IP address of the system running the containers with either a Port number of 30000 (mtserver1) or 30001 (mtserver2).

Other Commands

There are a few other ‘docker-compose’ commands which you should be aware of when running containers.

docker-compose down

After using CTRL+C to exit the container and return to a command prompt you can stop the containers with the ‘down’ command.

docker-compose start (image)
docker-compose stop (image)

If a single image needs to be started then you could start just one. For example, you can start ‘mtserver1’ by itself. Likewise, a container can be stopped. If I wished to stop ‘mtserver1’ I could use the command ‘docker-compose stop mtserver1’.

docker-compose images

Any images still being held can be listed by using the command. Each image size is also shown in the list.

docker-compose kill (container)

If a container is running and you want to stop its processes completely you can run the kill command. For instance, to kill the ‘mtserver2’ process the command would be ‘docker-compose kill mtserver2’.

docker-compose system prune (-a -f)

If you want to remove the images from the image list then you can run the above command. The parameter ‘-a’ specifies all images and ‘-f’ forces the removal without asking for approval. After the command you can list the individual images to remove if you do not want to remove all of the images with the parameter ‘-a’.

docker run -it compose_(image) bash

The command is useful if you wish to enter the container in interactive mode. Notice the command itself is not ‘docker-compose’ but ‘docker’. Because the command is only ‘docker’ it does not have immediate access to the ‘compose’ images. When the image is named it must be preceded by ‘compose_’. For example, to open ‘mtserver1’ interactively the command would be ‘docker run -it compose_mtserver1 bash’.

Compose Network

All containers started from compose will share an internal network. The IP Addresses will be 172.17.0.x. The network is and the first container should be
The name given to each ‘service’ or container is the name of that container. For example, the two MineTest Servers will be named ‘mtserver1’ and ‘mtserver2’. The name is considered a DNS name and the IP Address is not needed within the containers. I will show this point in the next example.

Ping Containers

In this example we will do something a little differently from the previous example. The ‘docker-compose.yml’ will be in a folder with the ‘dockerfile’ and not by itself.
In the ‘Docker’ folder create a folder called ‘compose-ping’.

NOTE: I try to keep the docker-compose files different from the regular docker files by adding ‘compose-’ in the folder name.

Perform the following commands inside the ‘compose-ping’ folder:

mkdir server1
mkdir server2
touch server1/dockerfile
touch server1/docker-compose.yml
touch server2/dockerfile

The folder structure and the empty files should be created and ready to be filled. Under the folder ‘server1’ the ‘dockerfile’ should have the following added to it:

FROM ubuntu:xenial
RUN apt-get update
RUN apt-get install -y inetutils-ping
CMD ["/bin/ping","server2"]

The ‘dockerfile’ under ‘server2’ should contain the following:

FROM ubuntu:xenial
RUN apt-get update
RUN apt-get install -y inetutils-ping
CMD ["/bin/ping","server1"]

These two ‘dockerfiles’ are the same except for the Command being executed. The ‘server1’ container will ping ‘server2’ and vice versa. You may notice something very important in these two commands. The ping command is not using an IP Address. Containers created using ‘docker-compose’ are on their own network together. Each container can contact the other containers by the Service name used on the ‘docker-compose.yml’ file.
The ‘docker-compose.yml’ file should be filled with the following entries:

version: '3'
       hostname: server1
       build: .

       hostname: server2
       build: /home/jarret/Docker/compose-ping/server2/.

You should be able to see that ‘server1’ is using a ‘dockerfile’ within the same folder as the ‘docker-compose.yml’ file. The ‘dockerfile’ for ‘server2’ is located in a separate folder.
When the containers are started you should have 2 containers continuously pinging each other as shown in Figure 2.

Figure 2.jpg


Use CTRL+C to exit the container view and then ‘down’ and ‘kill’ the containers as you need.
This should hopefully give you an understanding of using Docker Compose. Try a few containers together and see how the containers can interact.