How To Set Up a Load Balancer(Reverse Proxy) on AWS Instances Using Ansible

Rahul Bhardwaj
6 min readDec 31, 2020

--

In this article we will set-up a reverse-proxy using haproxy program on one of our Redhat AWS instance with the help of Ansible and run it.

Prerequisites:

  • How to launch AWS EC2 instances.
  • Ansible-playbook.
  • Concept of Reverse-proxy and Back-end servers.

Overview:

  • We are going to launch four AWS instances. The first Redhat instance is going to be a control node and the rest three are going to be target nodes. Out of these three first one will be our Reverse proxy server and the rest will be backend servers. One of the backend server used here is Amazon Linux.
  • To avoid complexity the security group is set to allow all inbound traffic.
  • To show the working of Load Balancer we’re using a .php file that will show the ip of the web server which is currently showing the web page.

Installing Ansible and Pythons Modules on our Control node:

For ease of doing execute commands with root for configuration.

First of all install python3 if your system doesn’t have it-

yum install python3

After this install boto3-

pip3 install boto3

Unlike virtual machines, installing ansible with the help of python’s operator isn’t going to work. So we need to use yum for that and for downloading ansible we’ll need epel repository. So we use the following command for that:

yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm

In this practical I used putty software to run the instances so I suggest you to do the same as it will be easy to copy and paste various things that we’ll be going to need in upcoming steps.

After that,

yum install ansible

And do check if it is installed or not:

ansible --version

It will show the detail of the Ansible installed you are good to go.

Creating Dynamic Inventory:

Create a directory for the inventory-

mkdir /inventory

Give the location of the inventory in the configuration file of your instance-

vi /etc/ansible/ansible.cfg

Here you’ll find many commands eliminated with #. Under the [inventory] section either remove the command with # or add yourself a new line-

and save the file. Now, moving to the part of setting up a dynamic inventory.

A dynamic inventory is the one that adds the newly created nodes on its own to the inventory. When we run the any ansible command the program will look into the directory of inventory that we created and execute the files that it can from it find the IPs of the target nodes. Somehow, it only executes the file without extensions or .yaml or .py file.

Remember: Do not enable any plugin in configuration file. Or, if you didn’t touch anything in the .cfg file just leave it that way unless you know what you’re doing.

If you want to dynamically include IPs from your Ansible inventory you’ll need to download two python files in inventory path. These are the pre-created files from the community members that do the job of renewing IPs dynamically for you.

wget https://raw.githubusercontent.com/ansible/ansible/stable-2.9/contrib/inventory/ec2.pywget https://raw.githubusercontent.com/ansible/ansible/stable-2.9/contrib/inventory/ec2.ini

Remember to download both the files as the python file assumes the .ini file to be there already. To make these files working make the python file executable-

chmod +x ec2.py 

For accessing the ec2 instances from your account it needs to go through authentications and for that you can create a IAM user in AWS with the permission of PowerUserAccess (or above).

And for using the credentials in the ec2.py file you can use the command:

export AWS_ACCESS_KEY_ID='AKIAIARG473H*********'
export AWS_SECRET_ACCESS_KEY='S1luiMAUz1cRk3SYt********************'

Remember: Everytime your putty session expires or you change the user you have to upload them again. So it is recommended to not use root user from now onwards

If you run the ec2.py file with python3 you’ll find some errors. For that:

Edit the first line of code with

#!/usr/bin/env python3

Also, there will be a module missing so go and just comment that file with # in the line no described and the file will work just fine.

You can now very well run the command -

ansible all --list-hosts

but if you try to ping the IPs you’ll find error.

For this you’ll have to do ssh authentication using the .pem files that are used in the instances. So, just copy the .pem files to your control node and perform the given operations. During ssh authentication you may find a warning that says permission are too open and will reject the files. So before doing anything execute-

chmod 600 <path_of_the_.pem_file>

for all your files.

After that execute:

ssh-agent bash
ssh-add <path_of_your_.pem_file>

repeat the second line for all your files.

Remember: you have to fill this every time your session expires or you change user.

Now you’re good to go with Ansible.

ansible all -m ping

Note: The command try to login into other users with the same user as their is in the control node by default. So if you’re using root it will not be possible to ping with this method. So it is recommended to use ec2-user.

In case you find this method tedious there is another way you can create and work with Dynamic Inventory. Follow the initial part of the article in https://rahul18bhardwaj-23.medium.com/ansible-role-to-configure-k8s-multi-node-cluster-over-aws-cloud-3bf86fe4b030.

Tags and Groups:

Now, the part comes where you have to make your ansible command distinguish between target and control nodes and between reverse proxy server and backend severs.

For that you have to create tags of your instances in such a way that they categorizes themselves accordingly.

Now you can ping the groups accordingly:

ansible tag_node_target -m ping
ansible tag_server_haproxy -m ping
ansible tag_server_backend -m ping

Creating the Playbook:

This part is almost same as that in static inventory so we can even use the same file as that. (Click here to see that in detail)

We’re uploading the php file from control node to the rest of backend nodes. Also, to execute them we’ll have to download php in all those nodes.

Now to make changes in the haproxy configuration file we first keep a copy of that file in our system by downloading haproxy on our own system. Then we make use of Jinja in the following way to update the IPs. The port we’ll use for our Load Balancer will be 789.

You can see that the variable we use here is tag_server_backend.

To disable SELinux we used a module here but used ignore_errors because on of instances in the practical I used was Amazon Linux for which SELinux is already disabled by default so any error shouldn’t be causing any trouble.

Running the playbook:

Using the IP_address:port/php_file for our Load Balancer on browser:

We got two different IPs in the output on the same url after reloading which was exactly what we needed. Therefore, Load Balancer’s working perfectly ! This Load Balancer will get updated every time a new instance is created with backend server tag.

Thanks for reading !

--

--