Starting my career as a network engineer I’m immediately drawn to the very “infrastructurey” components in my current position. I flock to software such as HaProxy, Varnish, Nginx, VyOS, and RabbitMQ to name a few. The design aspects of high availability carry over from hardware to software – and I love to design with these solutions.
I was recently working with a client who’s network path toward their API was needlessly long and took a few too many hops. Instead of re-configuring their current environment I purposed we setup HaProxy on the same LAN at which the load balancing will happen. Once time freed up and they could afford to fix the bad path, they would do so.
As everyone knows by know HaProxy is a beast. It’s written in C and can handle a LOT of traffic – however the former network engineer in me would not be able to sleep unless I had at least one method of HA. Luckily keepalived has been tweaked to work with HaProxy offering a mechanism to check two HaProxy instances. Keepalived uses VRRP which is something familiar to me. VRRP is a protocol which allows two [originally]routers to have one IP. With VRRP both nodes have a “real” ip and mac address. While both nodes are up the primary will own a VIP (virtual ip address) and will respond to ARP’s for that IP address. If the secondary node notices that the primary is gone (via a multicast keep alive control packet, hence the name) the secondary node will send a gratuitous ARP which says “Hey! I own this MAC and IP Address now!”
Okay enough with the background let’s get into the configs:
I have 4 servers in play here – two HaProxy boxes and two web servers:
192.168.1.1 – haproxy01p
192.168.1.2 – haproxy02p
192.168.1.3 – api01p
192.168.1.3 – api02p
I will also be using a VIP:
192.168.1.4 (this is the virtual ip address that will belong to both HaProxy boxes)
First things first – Get HaProxy and KeepaliveD installed. I’m on CentOs and both packages are in the default repository. Feel free to install these on both HaProxy boxes.
yum install haproxy keepalived -y
Let’s configure haproxy01p and 02p – they are going to have the same exact configs
#/etc/haproxy/haproxy.cfg global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy user haproxy group haproxy daemon defaults log global mode http option httplog option dontlognull option forwardfor option http-server-close timeout connect 5000 timeout client 50000 timeout server 50000 frontend platforminternal_frontend bind 192.168.1.4:80 option httplog reqadd X-Forwarded-Proto:\ https default_backend platforminternal_backend backend platforminternal_backend balance roundrobin server api01p 192.168.1.2:80 check server api02p 192.168.1.3:80 check listen stats :1936 mode http stats enable stats uri / stats hide-version stats auth admin:admin
Note that the frontend is an IP address that isn’t currently on the box. If you were to start up haproxy right now it would fail since the VIP is not configured on this box. We don’t need to manually add another IP to the server – keepalived will handle this.
Now let’s edit keepalived configuration file – this we will actually have two different configurations, changing the priority in haproxy02p in order to indicate it’s the secondary.
# haproxy01p /etc/keepalived/keepalived.conf bal_defs { notification_email { alteremail@alertemail.com } } vrrp_script chk_haproxy { script "killall -0 haproxy" interval 2 weight 2 } vrrp_instance VI_1 { interface ens160 state MASTER virtual_router_id 10 priority 101 virtual_ipaddress { 192.168.1.4 } track_script { chk_haproxy } }
And for haproxy02p
bal_defs { notification_email { alertemail@alertemail.com } } vrrp_script chk_haproxy { script "killall -0 haproxy" interval 2 weight 2 } vrrp_instance VI_1 { interface ens160 state MASTER virtual_router_id 10 priority 100 virtual_ipaddress { 192.168.1.4 } track_script { chk_haproxy } }
It goes to note – a higher priority wins – so 101 beats 100 for priority and 01p becomes the master.
With this all setup go ahead and start keepalived and then HaProxy. You should notice an extra IP address on the master node.
Test out your load balancing and your stat’s page. If everything looks good try to do a fail over. I typically do a simple test by starting a continuous ping to the VIP and hard resetting the master node.
So that’s really all there is too it – nice, quick, and easy win for high availability.
UPDATE:
Thanks to MMDeveloper on reddit I was given a pretty awesome tip here it is verbatim
When I’m setting up haproxy pools I sometimes like to monitor more than one service on each of the HAProxy nodes, I usually script keepalived to use a check script instead of a one-liner.. for example:
vrrp_script chk_loadbalancedservices { script "/etc/keepalived/check.sh" interval 2 weight 2 }
contents of check.sh
#!/bin/bash ### This will check all processes you wish to monitor ### In the event one of them is 'down', it will trigger ### a failover to the next-in-line HAProxy server killall -0 haproxy 2> /dev/null if [ $? -eq 1 ] then exit 1 fi ### Copy/Paste the above block of code for each ### process you want to monitor ### This script should always exit with a code of 0 or 1 ### An exit code of 0 means all is good ### An exit code of 1 will trigger a failover exit 0
What MMDeveloper is doing here is giving us the ability to check multiple services on the haproxy box to give a more granular approach to fail over. The script is generic and you can place which ever process name you’d like. If you have a critical service that runs next to haproxy on the same box, then add another stanza for this service:
killall -0 otherimportantservice 2> /dev/null if [ $? -eq 1 ] then exit 1 fi
Now if other important service fails – fail over will occur.