Ansible: Configure HaProxy for Webserver on EC2

Aman Jhagrolia
8 min readSep 16, 2020
Ansible AWS HaProxy Integration

In my last article, we have learnt to provision the ec2 instance on AWS then dynamically fetch its IP and configure web server in it using ansible. But today in this article we will again provision four instances on AWS and configure haproxy loadbalancer in one of them and webserver in the remaining three. The instance having haproxy loadbalancer configured will balance the load between our web server instances.

Ansible is an open-source software provisioning, configuration management, and application-deployment tool enabling infrastructure as code.

Ansible Roles provide a framework for fully independent, or interdependent collections of variables, tasks, files, templates, and modules. In Ansible, the role is the primary mechanism for breaking a playbook into multiple files. This simplifies writing complex playbooks, and it makes them easier to reuse.

Here is my GitHub Repository link for this complete Ansible Playbook -

Here we have created three different roles, One role named as “aws” is to create security group, key-pairs and Launch ec2 instance, Other role named as “webserver” is to configure the web server in the instance which is just launched by aws role and last one role named as “loadbalancer” is to configure the HaProxy LoadBalancer in one of the EC2 instances which balance the load between other Webserver Instances.

Ansible Configuration file - This file is an ansible configuration file which contains different configurations like the path of inventory, the path of the private key for ec2 instances and the privilage_escalation configurations. As in ec2 instance by default we always log in with ec2-user but to install something we need root privileges, so we have used privilege_escalation block here to become root.

/etc/ansible/ansible.cfg

Inventory - This is an inventory file before ansible-playbook runs, there is no. IP here as we are using the concept of dynamic inventory.

/etc/ansible/hosts/myhosts.txt

Let’s Move to our Ansible Playbook YML Code :-

aws-web.yml - This is my main Ansible Playbook file. we have to run this file and to do all the configurations. It includes role and applies them to different host groups according to the requirements. Here “aws” role will run on localhost, “loadbalancer” role will run on ‘loadbalancer’ group and “webserver” role will run on ‘webserver’ group of hosts. Here my loadbalancer and webserver group are ec2 instances and their IPs are dynamically fetched.

aws-web.yml

In the AWS Role :-

Variables file - This file contains all the variables used in the aws role like region, instance type, ami_id and subnet_id.

roles/aws/vars/main.yml

Tasks file - This file contains all the tasks for AWS Role. There are many tasks written here for different purposes.

  • The first task will create a Key-Pair for our ec2 instances, and on changed it will also notify the handler “Save Key PEM File” which will save the PEM key.
  • The second task will create a Security Group for our web server instances. It will also add an ingress rule for SSH and HTTP so that loadbalancer instance can connect to our webservers.
  • The third task will create a Security Group for our loadbalancer instance. It will also add an ingress rule for SSH and HTTP so that clients can connect to our loadbalancer IP.
  • The fourth task will launch the instances in which we are going to configure the webserver. It will launch three instances.
  • The fifth task will launch the instance in which we are going to configure the LoadBalancer.
  • Next task is to update the inventory for us. Dynamically this task will fetch the IP address of our instance launched for webserver and loadbalancer and then it will add these IPs in webserver and loadbalancer host group respectively.
  • Finally, our last task is just a pause for sometime before going ahead so that instances become ready in AWS Cloud.
roles/aws/tasks/main.yml

Handlers file - This files contain all the handlers used in aws role. Here we have used one handler to save the private key PEM in a file. This handler is notified by the “Creating key-pair” task that is If this task will change that means new key-pair is created, so this handler will be notified and private key PEM will be saved to /etc/ansible/webenvkey.pem

roles/aws/handlers/main.yml

In the Webserver Role :-

Tasks file - This is the tasks file for webserver role which contains the tasks to Install the httpd web server in the instance launched, after that start the httpd service and copy our webpage into its document root i.e. /var/www/html/ directory

roles/webserver/tasks/main.yml

Templates - It contains all the template files which are used in webserver role. Here we need to copy our HTML code i.e. webpage in the instance. Before copying, we need to update the hostname in that webpage, so here we are using a template. So this is our HTML code template file which will be copied in the instance after updating the hostname of that instance in it.

roles/webserver/templates/webpage.j2

In the LoadBalancer Role :-

Tasks file - This is the tasks file for loadbalancer role which contains the tasks to Install the haproxy package in the instance launched, after that copy the haproxy configuration file into /etc/haproxy/ directory and finally start the haproxy service.

roles/loadbalancer/tasks/main.yml

Templates - It contains all the template files which are used in the loadbalancer role. We need to copy our haproxy configuration file in the instance. Before copying, we need to update the IP of our web servers in this configuration file i.e. to register the web servers in the LoadBalancer. So here we are using a template. So this is our haproxy configuration template file which will be copied in the instance after updating the IPs of webservers in it.

roles/loadbalancer/templates/haproxy.cfg.j2

Handlers file - This files contain all the handlers used in loadbalancer role. As we know that we need to restart the service if the configuration of something is changed, So Here we have used one handler to restart the haproxy LoadBalaner service. This handler is notified by the “Copy haproxy config file” task that is If this task will change that means something is changed in configuration file, so this handler will be notified and haproxy service will be restarted.

roles/loadbalancer/handlers/main.yml

— — — — — — — — — — — — — — — — — — — — — — — — — —

Now we are ready to run our Ansible code. Before running playbook this is the status of EC2 dashboard, i.e. no instance is running, no key-pair is there and only one security group is there i.e. default.

EC2 Dashboard Before

Here in the ansible to use our aws we need to provide the access_id and access_key so that Ansible can log in to our aws and do something for us. So if we provide our aws credentials in a normal file (i.e. in plain text) then anybody can read it. so here we used ansible vault.

Ansible vault encrypts our file, only those can read it who have the vault password. So I created ansible vault named “aws-login.yml”, in which I have provided aws_access_id and aws_secure_access_key, and this will be encrypted.

Now if someone tries to open it with the wrong pass then it shows an error, it will only show real decrypted data to whom who have the right password. Also if anyone tries to open it directly then it will show some encrypted data.

Ansible vault

Here, we run the Playbook using “ansible-playbook --ask-vault-pass playbook_name.yml” command. we have used --ask-vault-pass option because we are using vault here and we need to pass the password so that ansible-playbook is able to decrypt it. Here in between the running playbook, we can see that the roles webserver and loadbalancer are applied to some IPs but there is no IP in the inventory before so here this IP is dynamically fetched by the aws role after launching the instance.

Playbook Running

Now after the playbook completes running this is the status of my ec2 dashboard, now we can see that one key pair and two more security groups are created. And now there are four instances running, one of them is for haproxy loadbalancer and others are webservers.

EC2 Dashboard After

Here are our four instances. Three of them are named as “webserver” and One as “loadbalancer”.

Running Instances

Two new Security Groups are created. And one Key-Pair is also created and the private key of that is stored in webenvkey.pem file in /etc/ansible/ directory.

Security Groups and Key

Here is my haproxy configuration file in ec2 loadbalancer instance. As we have used template module to copy this file, so here we can see that the IPs of our webserver instances are automatically updated in this configuration.

As our instance are launched and also configured, but when we open our inventory file we can’t see any IP there under loadbalancer or webserver host group. Here our Ansible Playbook is dynamically fetching the IP but not updating it in the inventory file. The IPs which it fetches will remain in the memory of inventory only till ansible-playbook completes running. As soon as playbook stops running it will forget that IPs i.e. we can only use those dynamically fetched IPs in this same playbook only.

Finally, our webservers and loadbalancer are configured. Now when we connect to our LoadBalancer IPs then we will be redirected to our web server running in the backend of loadbalancer and every time we again connect to loadbalancer IP we are redirected to different webserver i.e. load-balancing is done between all of our webservers. Here we can see that using the same loadbalancer IP we are connected to a different instance every time.

Here is the small video demo showing the complete scenario -

Thanks for reaching out here, I hope this is helpful to you🙂

--

--