HAProxy Loadbalancer configuration using Ansible Playbooks and Role with testing on AWS!

Shubhambhalala
8 min readDec 27, 2020

In this article, you will come to know how you can configure HAProxy Loadbalancer using Ansible. We will see two ways of managing playbooks concerning this use case, similarly, you can also use it for different use cases. These two ways are managing using playbooks and other is Ansible roles.

The architecture of this setup will require two things:

  1. Webservers: at least two, so that we can demonstrate that it is actually working.
  2. HAProxy server: we will have one instance which will work as a load balancer and reverse proxy.

For demonstration purposes, we will have one playbook to perform both the tasks that are, setting up a web server and configuring HAProxy and two roles one for setting up a web server and the other for configuration HAProxy. We will perform this on RHEL v8 VMs. One controller node and three managed nodes. Here, one will be for the HAProxy load balancer and the other two for the webserver.

Github:

Step 0: Make the workspace as you are comfortable, for me, it's this way.

mkdir /ansible_code/lbtask

Here our ansible local configuration file, inventory, and playbooks will be placed. I personally follow this method for managing Ansible playbooks because it is very handy and clear to have configuration and inventory for each use case locally in the workspace itself. The next step will be to make the Ansible configuration and inventory files.

Step 1: Ansible local configuration.

vim ansible.cfg

This is our local configuration file for our use case.

vim ansiblehosts.txt

This is our host file. We have two host groups, one for the webserver and the other for the load balancer.

Step 2: Writing playbook.

We will use variables and template files for this use case, hence we will first make a variable file.

vim lbvar.yml & vim webservervar.yml

We have created two variable files one having proxy_port and the other having docu_root and web_port. Here, tac is a Linux command, it works like a cat but prints the output in the reverse order that is, the last line first. ( For some reason my cat command is not working ; )

vim haproxy.conf.j2

This is the configuration file for HAProxy in the local system. We have to copy this from the /etc/haproxy directory. This is the exact configuration file haproxy by default creates. You can get this by installing haproxy using yum install haproxy then copy this file.

The highlighted one pointed by the red arrow is the one that we have to edit. These are Jinja2 templates. This will help us dynamically configure the haproxy for our use case. Finally, we will write a playbook.

vim weblb.yml

This is the play for configuring the webserver, in this webserver, we will print the IP address so that while testing we can see whether the load balancer is redirecting the traffic to a different server. In this playbook, we will continue writing the code for the HAProxy load balancer.

continue the weblb.yml

Finally, the whole playbook is created. Now some of the things which is a good practice to follow are:

  1. Using template instead of copy module. Using the template module we can use Jinja2 templates in the file. The Jinja2 syntax which we see in the haproxy.conf.j2 will be dynamically edited if we use the template module.
  2. Using the variable file for making the whole thing change dynamically.
  3. Using handlers for unwanted restarting of the services because unwanted restarting of service can make the user feel downtime.

Finally, we will start executing this playbook.

Step 3: Executing playbook.

ansible-playbook weblb.yml — check

First, we will do a dry run using — check flag, its a good practice to do so, this will let you know if there is any fault or error in your playbook and how many changes will occur when we actually apply it.

ansible-playbook weblb.yml

This will finally apply the playbook on the managed host according to our configuration everything is in pace and running fine. Now we will check whether our setup is successful or not. To check this we must see that we will see two different IPs when we refresh the page. If we see this, we can confirm that the HAProxy load balancer is working great.

Results:

first-time result
after refreshing it

Hence, we can conclude that this is working great!

Now, we will see how to make a role for it and how to execute a role.

How to implement a role for the same use case.

Here there will be some changes in the configuration file and of course the directory or workspace.

mkdir /ansible_code/roles

In this directory, we will maintain all the roles.

vim ansible.cfg

In this directory copy the ansible.cfg and ansiblehosts.txt file in this directory for making local ansible work.

Step 0: Creating roles.

ansible-galaxy role init haproxyloadbalancer && ansible-galaxy role init webserver

This will create two directories with the name you want to give. Special about these directories is they are pre-created directory system if you change anything which is pre-defined things might not work properly. In these directories, everything is divided into folders and each folder will have a pre-made yml file which we just have to edit. So, we have to just distribute the things which we made in the playbook.

Step 1: Editing roles.

copy the haproxy.cfg.j2 file created earlier

In the templates folder, we have to place the template file, we have one created which is for configuring haproxy. hence, we just have to copy the file made earlier into this directory.

vim vars/main.yml

These should be the content of the vars/main.yml file. So, in the tasks where ever we use these variables will be automatically used from this file, we don’t have to mention them.

vim handlers/main.yml

Here, we have to copy-paste the handler code for haproxy. In task whenever we use the notify it will automatically take the handler from this file.

vim tasks/main.yml

Similarly, we will write all tasks in this task file. Here we don't have to mention the hosts and var files or template file or handlers file, as said earlier, this is a pre-defined directory structure hence it will automatically read from the respective file we don’t have to mention it anywhere.

Similarly, we will edit for the webserver role.

vim /webserver/vars/main.yml
vim /webserver/templates/web.config.j2

This can be used if you want to change the listening port and default document root of the webserver.

vim /webserver/tasks/main.yml
vim /webserver/handler/main.yml

Step 2: Using role.

To use role for our host groups we have to make a file we name it setup.yml

vim setup.yml

Here we can see that, we have defined the host and which role to implement on that host group.

Finally, we will apply this playbook the same way we do for others.

ansible-playbook setup.yml

Results:

first-time result
result after refresh

Hence, our roles are also working great!

Let’s test this role on the AWS cloud!

vim ansible.cfg
vim awshosts.txt
ansible-playbook setup.yml

This throws an error of making entry into the firewall since it is an AWS, it doesn’t have a firewall as the security group we attached is the firewall. Hence, we can make use of ignore_error for handling the error in this case.

vim tasks/main.yml
vim tasks/main.yml
error solved by ignoring it
Now, there is an error in the display of the webpage because in code we have ifconfig enp0s3

We have hardcoded in the code that ifconfig enp0s3, but we don’t know whether it will have enp0s3 as a network interface or not, hence we will remove the interface name from the code file.

re-execution

Results:

first-time result

We can even keep on editing the awshosts.txt file if we encounter a new webserver.

New instance
editing the awshosts.txt file with a new instance IP
re-execution

Results:

--

--

Shubhambhalala

C|EH | Cybersecurity researcher | MLOps | Hybrid Multi Cloud | Devops assembly line | Openshift | AWS EKS | Docker