DEV Community

Cover image for Docker-Compose Management
Waji
Waji

Posted on

Docker-Compose Management

Introduction

Docker Compose is a tool for defining and running multi-container Docker applications. It allows you to define the services that make up your application and how they interact with each other. Docker Compose uses a YAML file to configure the application services, networks, and volumes.

Here are some of the key elements we can find in a Docker Compose YAML file:

  • version: Specifies the version of the Docker Compose file format being used.
  • services: Defines the various services that make up the application. Each service is given a name and specifies its image, ports, environment variables, and any other necessary configuration options.
  • networks: Specifies the networks that the application's services will use to communicate with each other.
  • volumes: Defines the volumes that will be mounted to the containers in the application. configs: Specifies configuration files that will be injected into the containers as Docker Configs.
  • secrets: Specifies secrets that will be injected into the containers as Docker Secrets.
  • deploy: Specifies options for deploying the application as a stack, including replicas, update policies, and placement constraints.

💡 To read more regarding docker compose, you can look at the official documentation over here

compose!


Some of the important terminologies

✨ Infrastructure as Code (IaC)

  • Technology for deploying and managing IT system infrastructure in the form of software, rather than by people.
  • As the software is written in source code, management quality can be improved.
  • Decreased work time for infrastructure managers due to parallel processing of multiple systems.
  • Cost savings due to efficient processing possible by reducing work time.
  • Lower error rate because only defined operations are performed by the software.

✨ Container Scaling Out (Scale Out)

  • Scale out refers to increasing the number of servers operating the service in response to increasing loads to distribute the load.
  • Horizontal scaling of containers: one of the core technologies of microservices, it prevents unnecessary system expansion by horizontally scaling only the containers responsible for a specific service.
  • Vertical scaling (Scale Up): Concept of expanding the server vertically by increasing insufficient resources such as CPU and RAM.
  • Traditional monolithic scaling method / Hardware is added because the entire system server cannot be added (there are limitations).

✨ Service Dependency and Discovery

  • Services running on each container in a specific project have interdependent relationships (e.g., WEB-DB-Kafka, etc.).
  • In a cloud environment, each service runs on an instance, and these instance information (IP, Port, etc.) has a characteristic that can easily change depending on the situation.
  • Services with interdependencies are highly sensitive to such changes, and to quickly reflect the changed information, service discovery must be configured.

Docker Compose Wordpress

For starters, I will be creating an emtpy directory

mkdir /Compose
cd /Compose
Enter fullscreen mode Exit fullscreen mode

Creating a new .yml file

vi docker-compose.yml

# Compose File Format Version

version: '3.7'    
services:
  wordpress_db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: wordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    networks:
      - wordpress_net
    volumes:
      - wordpress_data:/var/lib/mysql

  wordpress:
    depends_on:
      - wordpress_db
    image: wordpress:latest
    restart: always
    ports:
      - "80:80"
    environment:
      WORDPRESS_DB_HOST: wordpress_db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    networks:
      - wordpress_net
    volumes:
      - wordpress_web:/var/www/html

volumes:
  wordpress_data: {}
  wordpress_web: {}

networks:
  wordpress_net: {}
Enter fullscreen mode Exit fullscreen mode

Checking the docker-compose version

docker-compose -v
Docker Compose version v2.2.3
Enter fullscreen mode Exit fullscreen mode

If we use the following,

docker-compose config
Enter fullscreen mode Exit fullscreen mode

It will show us the current configuration for the docker compose file in the current directory

Now composing the YAML file

docker-compose up -d

 ⠿ Network compose_wordpress_net     Created                                        0.4s
 ⠿ Volume "compose_wordpress_data"   Created                                        0.0s
 ⠿ Volume "compose_wordpress_web"    Created                                        0.0s
 ⠿ Container compose-wordpress_db-1  Created                                        0.7s
 ⠿ Container compose-wordpress-1     Created                                        0.0s
Enter fullscreen mode Exit fullscreen mode

👉 The -d option declares the container to run in the background

After the compose build is done, we can check the docker volume and network are created as per the compose file

docker volume ls
local               compose_wordpress_data
local               compose_wordpress_web

docker network ls
755a8af21193        compose_wordpress_net   bridge              local
Enter fullscreen mode Exit fullscreen mode

We can also check compose status as well

docker-compose ls
docker-compose ps
Enter fullscreen mode Exit fullscreen mode

Now if we open the website using the IP address of our host system

wordpress

💡 When deleting composed containers, we can use docker-compose down however this won't delete the docker volume. We will need to include the -v option to delete the docker volume as well


Docker Compose building Nginx

I will now demonstrate using docker compose to build a Dockerfile

Creating a new directory

mkdir /Compose/build
cd /Compose/build
Enter fullscreen mode Exit fullscreen mode

Creating an index.html

echo "Hello My Nginx" > index.html
Enter fullscreen mode Exit fullscreen mode

Creating the Dockerfile

vi Dockerfile

FROM nginx:latest
LABEL maintainer "Author <Author@localhost.com>“
ADD index.html /usr/share/nginx/html
Enter fullscreen mode Exit fullscreen mode

Creating the docker-compose YAML file

vi docker-compose.yml

version: '3.7'
services:
  web:
    image: myweb/nginx:v1
    build: .
    restart: always
Enter fullscreen mode Exit fullscreen mode

Now using docker compose to build our Dockerfile

docker-compose -p myweb up -d --build

[+] Running 2/2
 ⠿ Network myweb_default  Created                                                   0.1s
 ⠿ Container myweb-web-1  Started                                                   0.2s
Enter fullscreen mode Exit fullscreen mode

👉 Here the "-p" option specifies a project name, and the "--build" option skips the image search and pull, performing only the build operation. If the "--build" option is omitted, the pull operation is automatically performed, but using it is recommended during build operations to avoid errors.

We can confirm the process

docker-compose -p myweb ps -a
NAME                COMMAND                  SERVICE             STATUS              PORTS
myweb-web-1         "/docker-entrypoint.…"   web                 running             80/tcp
Enter fullscreen mode Exit fullscreen mode

Another thing we can try is,

docker-compose -p myweb up -d --scale web=3

[+] Running 3/3
 ⠿ Container myweb-web-3  Started                                                   0.9s
 ⠿ Container myweb-web-2  Started                                                   0.9s
 ⠿ Container myweb-web-1  Started                                                   0.9s
Enter fullscreen mode Exit fullscreen mode

Checking the compose process again

docker-compose -p myweb ps

NAME                COMMAND                  SERVICE             STATUS              PORTS
myweb-web-1         "/docker-entrypoint.…"   web                 running             80/tcp
myweb-web-2         "/docker-entrypoint.…"   web                 running             80/tcp
myweb-web-3         "/docker-entrypoint.…"   web                 running             80/tcp
Enter fullscreen mode Exit fullscreen mode

👉 With the "--scale" option, it's possible to horizontally scale specific service containers, explicitly declaring a scale of 1 reduces the containers to 1. However, this option cannot be used when ports are specified, as it's not possible to expose multiple containers to the outside with the same port number. To serve multiple instances of the same web container, a proxy server must be used


Docker Compose HAproxy with Nginx LB

Proxy

Starting with an empty directory

mkdir /Compose/prod
cd /Compose/prod
Enter fullscreen mode Exit fullscreen mode

Creating an index.html

echo "Hello My Nginx" > index.html
Enter fullscreen mode Exit fullscreen mode

Creating a Dockerfile for Nginx and HAproxy

vi Dockerfile_nginx

FROM nginx:latest
LABEL maintainer "Author <Author@localhost.com>"
ADD index.html /usr/share/nginx/html
WORKDIR /usr/share/nginx/html

vi Dockerfile_haproxy

FROM haproxy:2.3
LABEL maintainer "Author <Author@localhost.com>"
ADD haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
Enter fullscreen mode Exit fullscreen mode

Configuring the haproxy.cfg file

vi haproxy.cfg
global
        log /dev/log  local0
        log /dev/log  local1 notice
        chroot /var/lib/haproxy
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

defaults
        log global
        mode http
        option httplog
        option dontlognull
        option dontlog-normal
        option http-server-close
        maxconn 3000
        timeout connect 10s
        timeout http-request 10s
        timeout http-keep-alive 10s
        timeout client 1m
        timeout server 1m
        timeout queue 1m

listen stats
        bind *:9000
        stats enable
        stats realm Haproxy Stats Page
        stats uri /
        stats auth admin:haproxy1

frontend proxy
        bind *:80
        default_backend WEB_SRV_list

backend WEB_SRV_list
        balance roundrobin
        option httpchk HEAD /
        server prod-web-1 prod-web-1:80 check inter 3000 fall 5 rise 3
        server prod-web-2 prod-web-2:80 check inter 3000 fall 5 rise 3
        server prod-web-3 prod-web-3:80 check inter 3000 fall 5 rise 3
Enter fullscreen mode Exit fullscreen mode

👉 At the backend section of the configuration file, the web server's status is checked using the HEAD method every 3 seconds. If the status check fails 5 times in a row, the web server is removed from the load balancer group. If the server becomes available again and passes 3 consecutive status checks, it is added back to the load balancer group.

Finally creating the docker compose YAML file

vi docker-compose.yml

version: '3.7'
services:
  proxy:
    depends_on:
      - web
    image: prod/haproxy:v1
    build:
      context: ./
      dockerfile: ./Dockerfile_haproxy

    restart: always
    ports:
      - "80:80"
      - "9000:9000"
    networks:
      - myweb_net

  web:
    image: prod/nginx:v1
    build:
      context: ./
      dockerfile: ./Dockerfile_nginx
    restart: always
    deploy:
      mode: replicated
      replicas: 3
    networks:
      - myweb_net

networks:
  myweb_net: {}
Enter fullscreen mode Exit fullscreen mode

Using docker compose to build our Dockerfiles

docker-compose up -d --build

Successfully built 5deb0e3b5821
Successfully tagged prod/haproxy:v1
[+] Running 5/5
 :: Network prod_myweb_net  Created                                                                  0.2s
 :: Container prod-web-3    Started                                                                  0.7s
 :: Container prod-web-1    Started                                                                  0.7s
 :: Container prod-web-2    Started                                                                  0.6s
 :: Container prod-proxy-1  Started                                                                  1.5s
Enter fullscreen mode Exit fullscreen mode

Once the job is done, we can check the processes

docker-compose ps
NAME                COMMAND                  SERVICE             STATUS              PORTS
prod-proxy-1        "docker-entrypoint.s…"   proxy               running             0.0.0.0:80->80/tcp, 0.0.0.0:9000->9000/tcp
prod-web-1          "/docker-entrypoint.…"   web                 running             80/tcp
prod-web-2          "/docker-entrypoint.…"   web                 running             80/tcp
prod-web-3          "/docker-entrypoint.…"   web                 running             80/tcp
Enter fullscreen mode Exit fullscreen mode

To test if the load balancing if it is working between these 3 web pages, we can include a different entry in each of the web server

docker exec -it prod-web-1 /bin/bash
root@c6f1c535ce6c:/usr/share/nginx/html# echo "prod-web-1 Server Main Page" >> index.html
root@c6f1c535ce6c:/usr/share/nginx/html# cat index.html
Hello My Nginx
prod-web-1 Server Main Page

docker exec -it prod-web-2 /bin/bash
root@e86233007a76:/usr/share/nginx/html# echo "prod-web-2 Server Main Page" >> index.html
root@e86233007a76:/usr/share/nginx/html# cat index.html
Hello My Nginx
prod-web-2 Server Main Page

docker exec -it prod-web-3 /bin/bash
root@11aa89e08619:/usr/share/nginx/html# echo "prod-web-3 Server Main Page" >> index.html
root@11aa89e08619:/usr/share/nginx/html# cat index.html
Hello My Nginx
prod-web-3 Server Main Page
Enter fullscreen mode Exit fullscreen mode

Testing our setup

1

2

3

👉 We can confirm that round robin load balancing is working


Conclusion

In conclusion, Docker Compose is a powerful tool that simplifies the process of managing and deploying complex multi-container applications. Through hands-on experience building an Nginx server with HAProxy and a WordPress application, we have seen how Docker Compose streamlines the management of container orchestration, network configuration, and service scaling.

Top comments (0)