This tutorial will guide you through setting up haproxy on a fresh Ununtu box using Ansible.
We will follow the steps outlined in How To Use HAProxy to Set Up HTTP Load Balancing on an Ubuntu VPS. Except: instead of doing it manually, this time, we will do it with Ansible.
We will write a playbook that sets up and configures a HAProxy load balancer via a single ansible command.
Here goes:
Requirements
Currently Ansible can be run from any machine with Python 2.6 installed (Windows isn’t supported for the control machine).
This includes Red Hat, Debian, CentOS, OS X, any of the BSDs, and so on.
Install Ansible
On your local computer, run:
pip install ansible
That's pretty easy :). If you run ansible-playbook
from the command you should now see some useful stuff.
Let's get started with the least amount of work necessary
- Create a file called
playbook.yml
- Create a file called
hosts
Things should now look like this:
|_ playbook.yml
|_ hosts
Add your target server to hosts
edit hosts
file and simply paste in the IP of the server that you want to install haproxy on. For this example, we will use a server with the IP 1.2.3.4
.
echo 1.2.3.4 > hosts
(replace 1.2.3.4 with your actual server IP (or domain name)).
Note: You can do a lot more stuff with inventory.
Installing haproxy
Now, paste the following into playbook.yml
- hosts: all
tasks:
- name: update apt cache
apt: update_cache=yes cache_valid_time=3600
- name: install haproxy
apt: name=haproxy state=present
Pretty simple. This will update the apt-cache and install haproxy with apt-get
Let's run the playbook:
ansible-playbook playbook.yml -i hosts -u username
Note: if you are not running this as root, you will need to add the --sudo
flag (possibly in conjunction with --ask-sudo-psss
if relevant)
After that completes successfully haproxy is installed on your target box (the one you defined in your hosts
file. That was easy :)
Nextup, We need to enable HAProxy to be started by the init script. We'll need to edit our /etc/default/haproxy
file. We'll use the replace filter to do this.
Add the following task:
- name: Enable init script
replace: dest='/etc/default/haproxy'
regexp='ENABLED=0'
replace='ENABLED=1'
This will edit /etc/default/haproxy
and replace ENABLED=0
with ENABLED=1
.
You can run this now with the same command:
ansible-playbook -i hosts -u username
Notes:
-
This will run our entire playbook. There's an important point here. Ansible is designed so that you can always run the entire script safely and be comfortable that the state of the server is accurately reflected in your playbook.
-
For debugging purposes you can pass in the flag
--start-at-task=..
which will start the process from the specified task. This can be quite a time-saver while we're testing. For example, we can run our new task with:ansible-playbook -i hosts -u username --start-at-task="Enable init script"
Configuring HAProxy
HAProxy's configuration lives at /etc/haproxy/haproxy.cfg
we're going to use Ansible's template module to build our config file.
Create a templates directory:
mkdir templates
Create and edit templates/haproxy.cfg
:
nano templates/haproxy.cfg
Paste the following config file in there:
global
log 127.0.0.1 local0 notice
maxconn 2000
user haproxy
group haproxy
defaults
log global
mode http
option httplog
option dontlognull
retries 3
option redispatch
timeout connect 5000
timeout client 10000
timeout server 10000
listen {{haproxy_app_name}} 0.0.0.0:80
mode {{haproxy_mode}}
stats {{haproxy_enable_stats}}
{% if haproxy_enable_stats == 'enable' %}
stats uri /haproxy?stats
stats realm Strictly\ Private
{% for user in haproxy_stats_users %}
stats auth {{user.username}}:{{user.password}}
{% endfor %}
{% endif %}
balance {{haproxy_algorithm}}
option httpclose
option forwardfor
{% for server in haproxy_backend_servers %}
server {{server.name}} {{server.ip}}:{{server.port}} {{server.paramstring}}
{% endfor %}
You can learn more about what all these HAProxy configs do in the original tutorial
You'll notice we've got a bunch of things in curly braces (e.g.: {{haproxy_app_name}}
. These are Ansible variables. Ansible uses the jinja2 templating engine. You can learn more about what you can do with Jinja2 templates on the Jinja website.
Since we're using variables in our template, we will need to define them somewhere. For simplicity, we will simply put them directly into our playbook for now. You can read more about variables in the Ansible docs on variables.
Add the following block to your playbook:
...
vars:
haproxy_app_name: myapp
haproxy_mode: http
haproxy_enable_stats: enable
haproxy_algorithm: roundrobin
haproxy_backend_servers:
- {name: server1, ip: 10.133.181.247, port: 80, paramstring: cookie A check}
- {name: server2, ip: 10.133.186.46, port: 80, paramstring: cookie A check}
haproxy_stats_users:
- {username: joe, password: soap}
...
You should substitute sensible values.
Finally, let's add our task to put this config file in place. Add the following task to your playbook.yml
- name: Update HAProxy config
template: src=templates/haproxy.cfg
dest=/etc/haproxy/haproxy.cfg
backup=yes
Notes:
src
tells ansible where to find our template file on the local computer.desc
tells Ansible where to find the file to replace on the remote server- We're going to make a backup of the file before we change it.
backup=yes
Your playbook should now look something like this.
Let's run it:
ansible-playbook playbook.yml -u root -i hosts --start-at-task="Update HAProxy config"
So now we've got a basic HAPProxy load balancer installed and configured. Let's just make sure that it's started. To do this, we'll add a handler
.
In playbook.yml
after our tasks block, add a handler block like so:
handlers:
- name: restart haproxy
service: name=haproxy state=restarted
We will then need to notify
our handler to be called at the appropriate time. Update the task "Update HAProxy config" so that it looks like this:
- name: Update HAProxy config
template: src=templates/haproxy.cfg
dest=/etc/haproxy/haproxy.cfg
backup=yes
notify:
- restart haproxy
Notice we hadded a notify block that will inform the task to make sure that haproxy is restarted in the case that we change the config
Run the playbook again for these changes to take effect.
Now, you should be able to navigate to your haproxy server and you will be forwarded to a different server each time you reload the page (this is because we're using the roundrobin algorithm).
Congratulations. You've just configured a HAProxy server with Ansible.
You can download the code for this tutorial from Github
Next steps:
- Repackage this playbook as a role and post it to the Ansible Galaxy](https://galaxy.ansible.com/). Blog post coming soon.
- Extend our role to also include ACLs which will allow us to handle forwarding multiple different domains to backend clusters. See: HAProxy - route by domain name
References: