HAProxy L7 Load-Balancing With Docker Containers

Here, we will learn about HAProxy Layer 7 load balancing with Docker containers in action. What we're going to do here is to spin up a HAProxy container with some custom configuration, which listens to the request at port 80 and forwards the traffic to a set of back-end servers containing Kestrel, Apache, and Node Docker containers, each running on a different port and which will look something like what is shown in the below image. We will use Docker-Compose to make things a bit quicker.Docker
I have 3 super simple Docker images i.e. Node, ASP.NET Core and PHP with Apache images and an official HAProxy Docker image on my machine. We will mount a custom HAProxy configuration file `haproxy.cfg` as the volume for HAProxy container which listens for the traffic at port 80 and load-balance them among 3 containers. The HAProxy configuration file looks something like this, 

  1. global  
  2.         debug  
  3.   
  4. defaults  
  5.         log global  
  6.         mode    http  
  7.         timeout connect 5000  
  8.         timeout client 5000  
  9.         timeout server 5000  
  10.   
  11. frontend main  
  12.         bind *:80  
  13.         default_backend app  
  14.   
  15. backend app  
  16.         balance roundrobin  
  17.         mode http  
  18.         server srv1 app1  
  19.         server srv2 app2  
  20.         server srv3 app3  

There are 2 important sections here, frontend and backend, the first of which listens for the incoming HTTP requests and the second if which processes those request. The front-end and back-end can be named anything (here I named main for front-end, and app for back-end). The front-end rule will listen at port 80 and forward the request to the app's back end to process those requests. The back-end specifies the Round-Robin load-balancing algorithm, a mode and three servers to process requests. Here we specified the name of the container, not an actual URI of the server because we want to use embedded Docker Engine DNS to resolve services against all the containers as the containers will be running in the same user-defined network.

Next, we need to specify the Docker Compose file which we will use which is,

  1. version: '2'  
  2.   
  3. services:  
  4.   app1: # Service 1  
  5.     image: haproxy/app1 # ASP.NET Core  
  6.     ports:  
  7.       - 81:80  
  8.     container_name: 'app1'  # Name of the container  
  9.   
  10.   app2: # Service 2  
  11.     image: haproxy/app2 # PHP and Apache  
  12.     ports:  
  13.       - 82:80  
  14.     container_name: 'app2'  # Name of the container  
  15.   
  16.   app3: # Service 3   
  17.     image: haproxy/app3 # Node and Express  
  18.     ports:  
  19.       - 83:80  
  20.     container_name: 'app3'  # Name of the container  
  21.   
  22.   haproxy:  # Haproxy service  
  23.     image: haproxy  # Official HAProxy image  
  24.     ports:  
  25.       - 80:80  
  26.     container_name: 'haproxy' # Name of the container  
  27.     volumes:  # HAProxy configuration volume mount   
  28.       - '~/Documents/practice/haproxy:/usr/local/etc/haproxy/haproxy.cfg:ro'      

Next, go to the Docker Compose directory, open up a terminal and type,

  1. docker-compose up -d  

This will spin up 4 containers with HAProxy container and will serve at localhost port 80.

Docker
Now, refresh the same webpage a couple of times, you will see that requests are being being forwarded to different containers defined in the back-end section of HAProxy.

Docker
Docker
Conclusion

Containers like HAProxy and Nginx can be used to load-balance HTTP and TCP (L7 and L4) traffic. In Swarm, it can also use load-balance TCP traffic among containers that do not work with HTTP such as database containers etc.