I have a need to deploy a High Availability Load Balanced reverse proxy solution. We have a back end web service that requires resilience. To achieve this I’ve been looking at Nginx and Keepalived. The Nginx Plus product appears to contain high availability support – but we’re in the realms of zero budget and open source/community supported products.
The front end reverse proxy I’ll use is Nginx, but it could be anything. The clever part is going to be using keepalived to pass a single IP address between two servers.
Find yourself three fresh unused IP addresses. One for each server and one to share as the HA address.
eg. 192.168.1.224, 192.168.1.225, 192.168.1.226
First I installed a pair of Debian Stretch servers (loadbal01, loadbal02) and prepared them as per my usual minimum build with sshd and pretty much nothing else. I used the addresses .225 and .226 for my servers. I’ll use .224 for the “virtual” HA address.
Just to test before converting Nginx into a reverse proxy I installed it box fresh onto each system and created an
index.html file for them to serve just to show which one the keepalived was giving the IP address to.$ sudo install nginx
Create the home page on each:
$ vi /var/www/html/index.html
PRIMARY
and put SECONDARY into loadbal02’s index.html.
If you visit http://loadbal01 or http://loadbal02 you should see the respective index page.
Then installed keepalived:
$ sudo apt-get install keepalived
To configure keepalived edit
/etc/keepalived/keepalived.conf – on the primary my config looks like:global_defs {
# Keepalived process identifier
router_id nginx
}
# Script used to check if Nginx is running
vrrp_script check_nginx {
script "/bin/check_nginx.sh"
interval 2
weight 20
}
# Virtual interface
# The priority specifies the order in which the assigned interface to take over in a failover
vrrp_instance VI_01 {
state MASTER
interface ens192
virtual_router_id 51
priority 101
# The virtual ip address shared between the two loadbalancers
virtual_ipaddress {
192.168.1.224
}
track_script {
check_nginx
}
authentication {
auth_type AH
auth_pass secret
}
}
and on the secondary:
global_defs {
# Keepalived process identifier
router_id nginx
}
# Script used to check if Nginx is running
vrrp_script check_nginx {
script "/bin/check_nginx.sh"
interval 2
weight 20
}
# Virtual interface
# The priority specifies the order in which the assigned interface to take over in a failover
vrrp_instance VI_01 {
state BACKUP
interface ens192
virtual_router_id 51
priority 103
# The virtual ip address shared between the two loadbalancers
virtual_ipaddress {
192.168.1.224
}
track_script {
check_nginx
}
authentication {
auth_type AH
auth_pass secret
}
}
Notice the differences highlighted in bold.
Now the script that monitors nginx is running is a simple bash script that just returns an exit code of 1 if the process id isn’t running. So you could pretty much write a bash script that returns an exit code of 1 for anything.
/bin/check_nginx.sh – permissions 0755
#!/bin/sh if [ -z "`/bin/pidof nginx`" ]; then exit 1 fi
Starting keepalived:
$ sudo systemctl start keepalived
My install made a couple of complaints in
/var/log/syslog that needed addressing for it to work properly.loadbal01 Keepalived[1650]: WARNING - default user 'keepalived_script' for script execution does not exist - please create.
and
loadbal01 Keepalived_vrrp[14383]: Unable to load ipset library - libipset.so.3: cannot open shared object file: No such file or directory
To resolve these issues I created the user with bare user level permisisons and installed the package libipset-dev. Then restarted the keepalived daemon.
$ sudo useradd -g users -M keepalived_script $ sudo apt-get install libipset-dev
$ sudo systemctl restart keepalived
On each server I then checked the IP address using
ip a and as if by magic I could see the .224 address hosted on the primary/master machine.
Then I stopped nginx on the primary and within a second saw the logs elect a new master and the IP address was now hosted on the secondary/backup! So when I visit the URL http://192.168.0.224/ I get the index page from whichever server owns the IP address.
Primary /var/log/syslog
May 15 13:49:51 loadbal01 systemd[1]: Stopped A high performance web server and a reverse proxy server.
May 15 13:49:52 loadbal01 Keepalived_vrrp[17922]: pid 22322 exited with status 1
May 15 13:49:52 loadbal01 Keepalived_vrrp[17922]: VRRP_Script(check_nginx) failed
May 15 13:49:52 loadbal01 Keepalived_vrrp[17922]: VRRP_Instance(VI_01) Changing effective priority from 121 to 101
May 15 13:49:52 loadbal01 Keepalived_vrrp[17922]: VRRP_Instance(VI_01) Received advert with higher priority 120, ours 101
May 15 13:49:52 loadbal01 Keepalived_vrrp[17922]: VRRP_Instance(VI_01) Entering BACKUP STATE
Secondary /var/log/syslog
May 15 13:49:52 loadbal02 Keepalived_vrrp[3768]: VRRP_Instance(VI_01) forcing a new MASTER election May 15 13:49:53 loadbal02 Keepalived_vrrp[3768]: VRRP_Instance(VI_01) Transition to MASTER STATE May 15 13:49:54 loadbal02 Keepalived_vrrp[3768]: VRRP_Instance(VI_01) Entering MASTER STATE
So you can see that the pid 22322 must be the
check_nginx.sh process returning an exit code of 1 and the ip failed over immediately.
Now the failovers work as expected I can reconfigure Nginx to act as a reverse proxy.
Comments
Post a Comment