Compose an Application

As a last exercise step, we want to use Docker compose to first replicate the previous example and then to compose a more complex deployment with a load balancer.

Before you start, change your working directory again to your test folder (e.g., /Users/yourname/test/).

Start a basic example

As the very first step, we replicate the Docker usage of the first exercise, in which we have mounted a folder into an nginx container. Create a file called docker-compose.yml in your test folder and save it with the following content. Make sure that the indentation is consistent!

# docker-compose.yml
services:
  NAME:
    image: nginx
    ports:
      - 8080:80
    volumes:
      - ./html:/usr/share/nginx/html/

This example defines a single service called NAME. This service will be based on the base image nginx, forward local accesses to port 8080 to the container port 80, and mount the html directory into the container.

To start the application use up.

$ docker-compose up -d
[+] Running 1/1
 ✔ Container test-NAME-1  Started

With your browser, visit http://localhost:8080 to validate that nginx is working. Container names are derived from the enclosing folder and from the service name, so you will see that docker ps -a will list a running container called test-NAME-1.

When executed from the folder, in which the compose file is located, you can use docker-compose stop and docker-compose start to start and stop the container. docker-compose logs will give you access to the logs when the deployment is started as a daemon.

When you are done, invoke docker-compose down to shutdown the deployment again and remove all traces. You will see that docker ps -a will show an empty list again.

Deploy a composed application

As a second example, we will deploy an application that is composed of multiple containers. The idea is to reuse the results of the previous exercises, start two nginx instances with different websites, and put a load balancer in front of them.

For this exercise, make sure that your working directory is still the test folder. As a first step, copy the html folder twice and name the two copies html_a and html_b respectively. We will use these two folders in the nginx instances. Change the text in html_b/index.html to “Hello World from B!” and the background color to blue.

A second preparation is necessary: Create a file called nginx.conf in your test folder and save it with the following contents. You do not have to understand the details, but -in a nutshell- this configuration will make nginx work as a load balancer by forwarding requests to two servers a and b.

# nginx.conf
events { worker_connections 1024; }
http {
    upstream app_servers {
        server a:80;
        server b:80;
    }
    server {
        listen 80;
        location / {
            proxy_pass http://app_servers;
        }
    }
}

To put all the pieces together, edit the docker-compose.yml file and save it with the following content.

# docker-compose.yml
services:
  a:
    image: nginx
    volumes:
      - ./html_a:/usr/share/nginx/html/
  b:
    image: nginx
    volumes:
      - ./html_b:/usr/share/nginx/html/
  proxy:
    image: nginx
    ports:
      - 8080:80
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf

This content defines two simple services a and b that follow the previous example: the nginx instances will serve the contents from mounted volumes. The third service proxy is also based on the nginx base image. However, it won’t serve contents, instead, we will replace its configuration file to make it act like a load balancer.

Start this deployment with Docker compose.

$ docker-compose up -d

Reloading http://localhost:8080 should now alternate between the red and the blue website versions of html_a and html_b. You can further validate that indeed three containers have been started by running docker ps -a. The output will contain three containers test-a-1, test-b-1, and test-proxy-1.

Please note that all three containers can communicate with each other without explicitly configuring their ports in the compose file, as all are located within the same Docker network. However, access from the outside requires a port mapping, like it is done for the proxy.

To finish the exercise, run docker-compose down to shutdown all containers and remove all traces. You will see that docker ps -a will show an empty list again.


Last modified on Jun 27, 2023 at 21:59.