Having HAProxy check mysql status through a xinetd script

HAProxy is able to load balance MySQL wonderfully. The main issue is how to make sure that the backend MySQL server to forward the request to is up and running (I mean not just to establish a connection to port 3306, I mean something more “complete”, that performs a little operation against the MySQL server).

It is possible to make haproxy check the status of a mysql server using a small shell script managed through the xinetd daemon.

What this script basically does is performs a basic operation against the mysql database then returns http status 200 if the operation was successful or http status 500 if it there was any error (i.e. mysql was not available).

Script

The script looks like this:

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/bin/bash
#
# This script checks if a mysql server is healthy running on localhost. It will
# return:
#
# "HTTP/1.x 200 OK\r" (if mysql is running smoothly)
#
# - OR -
#
# "HTTP/1.x 500 Internal Server Error\r" (else)
#
# The purpose of this script is make haproxy capable of monitoring mysql properly
#
# Author: Unai Rodriguez
#
# It is recommended that a low-privileged-mysql user is created to be used by
# this script. Something like this:
#
# mysql> GRANT SELECT on mysql.* TO 'mysqlchkusr'@'localhost' \
# -> IDENTIFIED BY '257retfg2uysg218' WITH GRANT OPTION;
# mysql> flush privileges;
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
MYSQL_USERNAME="mysqlchkusr"
MYSQL_PASSWORD="secret"
TMP_FILE="/tmp/mysqlchk.out"
ERR_FILE="/tmp/mysqlchk.err"
#
# We perform a simple query that should return a few results :-p
#
/usr/bin/mysql --host=$MYSQL_HOST --port=$MYSQL_PORT --user=$MYSQL_USERNAME \
    --password=$MYSQL_PASSWORD -e"show databases;" > $TMP_FILE 2> $ERR_FILE
#
# Check the output. If it is not empty then everything is fine and we return
# something. Else, we just do not return anything.
#
if [ "$(/bin/cat $TMP_FILE)" != "" ]
then
    # mysql is fine, return http 200
    /bin/echo -e "HTTP/1.1 200 OK\r\n"
    /bin/echo -e "Content-Type: Content-Type: text/plain\r\n"
    /bin/echo -e "\r\n"
    /bin/echo -e "MySQL is running.\r\n"
    /bin/echo -e "\r\n"
else
    # mysql is fine, return http 503
    /bin/echo -e "HTTP/1.1 503 Service Unavailable\r\n"
    /bin/echo -e "Content-Type: Content-Type: text/plain\r\n"
    /bin/echo -e "\r\n"
    /bin/echo -e "MySQL is *down*.\r\n"
    /bin/echo -e "\r\n"
fi

Steps on the MySQL server

First, you should create the script somewhere, and assign proper permissions:

Shell
1
2
chown nobody /opt//mysqlchk
chmod 744 /opt//mysqlchk

Then, set permissions into the mysql server:

Shell
1
2
3
4
mysql> GRANT SELECT on mysql.* TO 'mysqlchkusr'@'localhost' \
-> IDENTIFIED BY 'secret' WITH GRANT OPTION;
mysql> flush privileges;
mysql> exit

Test:

Shell
1
2
/opt/mysqlchk
HTTP/1.x 200 OK

Now, configure xinetd by adding this line at the bottom of /etc/services:

Shell
1
mysqlchk 9200/tcp # mysqlchk

Then add this file /etc/xinetd.d/mysqlchk:

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# default: on
# description: mysqlchk
service mysqlchk
{
flags = REUSE
socket_type = stream
port = 9200
wait = no
user = nobody
server = /opt/mysqlchk
log_on_failure += USERID
disable = no
only_from = 0.0.0.0/0 # recommended to put the IPs that need
# to connect exclusively (security purposes)
per_source = UNLIMITED # Recently added (May 20, 2010)
# Prevents the system from complaining
# about having too many connections open from
# the same IP. More info:
# http://www.linuxfocus.org/English/November2000/article175.shtml
}

Restart xinetd (you can watch for issues on /var/log/syslog):

Shell
1
2
/etc/init.d/xinetd stop
/etc/init.d/xinetd start

Test:

Shell
1
2
3
4
5
6
7
8
9
10
11
telnet localhost 9200
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
HTTP/1.1 200 OK
Content-Type: Content-Type: text/plain
MySQL is running.
Connection closed by foreign host.

Steps on the HAProxy server
Now, in order to make haproxy check the status of the mysql service through the xinetd-managed-script, we should add something similar to this on the haproxy.cfg file:

Shell
1
2
3
4
5
listen MySQL 10.135.2.67:3306
mode tcp
    option httpchk
server 10.135.2.69:3306 10.135.2.69:3306 check port 9200 inter 12000 rise 3 fall 3
source 10.135.2.67

What is important?

  1. option httpchk.- tells haproxy to check for full http response (i.e. http headers: 2xx OK or 5xx ERROR)
  2. check port XXXX.- tells haproxy to check the status of the service by sending an http request on that port

How to install NAGIOS NRPE plugin under Debian Linux

NRPE allows you to remotely execute Nagios plugins on other Linux/Unix machines. This allows you to monitor remote machine metrics (disk usage, CPU load, etc.). NRPE can also communicate with some of the Windows agent addons, so you can execute scripts and check metrics on remote Windows machines as well. Citation.

You may follow the steps to install NRPE in any of the following ways:

1) Steps (compiling from sources)

First, you should download the latest NRPE version from HERE.

Then, install some required packages:

Shell
1
2
apt-get update
apt-get install build-essential libssl-dev

Unpack the NRPE addons, configure and install:

Shell
1
2
3
4
5
6
cd /opt
tar xvfz nrpe-2.12.tar.gz
cd nrpe-2.12
./configure --enable-command-args
make all
make install-plugin

2) Steps (using apt binaries)

Shell
1
2
apt-get update
apt-get install nagios-nrpe-plugin

Invocation
NRPE can now be invoked using the following:

Shell
1
/usr/lib/nagios/plugins/check_nrpe

Another option would be to create a symlink to make the invocation easier:

Shell
1
ln -s /usr/lib/nagios/plugins/check_nrpe /usr/bin/check_nrpe

Thus:

Shell
1
check_nrpe

Fixing VMware clock synchronization problems

On a VMWare environment sometimes guest operating systems may experience synchronization problems resulting into wrong dates and/or times. This could be more than annoying.

From Timekeeping in VMware Virtual Machines, page 14:

VMware Tools includes a time synchronization feature that periodically checks the guest operating system clock against the host operating system clock and corrects the guest clock. Unlike non-VMware synchronization software, VMware Tools time synchronization works in concert with the built-in catchup feature in VMware virtual machines and avoids turning the clock ahead too far. To enable VMware Tools time synchronization in a guest, first install VMware Tools in the guest operating system. Next, check that time synchronization is turned on. You can enable synchronization from the graphical VMware Toolbox application within the guest. Alternatively, you can set the .vmx configuration file option tools.syncTime = true to enable time synchronization. Note that time synchronization in a Linux guest works even if you are not running the VMware Toolbox application. All that is necessary is that the VMware guestd process is running in the guest and tools.syncTime is set to true.

VMware Tools time synchronization is designed to be a second line of defense to deal with special cases where a guest operating system’s clock falls behind real time despite the built-in catchup mechanism provided in the virtual machine. It is normal for a guest’s clock to be behind real time whenever the virtual machine is stopped for a while and then continues running; in particular, after a suspend/resume, snapshot, disk shrink, or VMotion operation. These are the main cases that VMware Tools time synchronization is meant to handle. The guest’s clock may also fall behind in less common circumstances, such as under heavy load when the guest has not been able to get enough CPU time to handle all its timer interrupts. The VMware Tools time synchronization daemon is quite simple and has a few limitations. The daemon checks the guest clock only once per minute. If the guest clock is much farther behind the host time than the virtual machine’s built-in catchup mechanism expects it to be, the daemon resets the guest clock to host time and cancels any pending catchup. For most guest types, the daemon never turns the guest clock backward, even if the guest’s clock time is running ahead of real time. Turning the clock backward is seldom needed and can cause some guest software to become confused. If your guest’s clock is running ahead of real time, see Known Issues and Troubleshooting on page 18 for troubleshooting tips and potential solutions and workarounds.

Solution
Install VMware Tools and have the Virtual Machine synchronize its clock with the Host Machine’s (keep in mind that this might bring issues if the host and the guest are in different timezones because the guest will get the exact host’s time).

You may proceed by stopping the Virtual Machine and then editing the configuration file (xxxxxx.vmx) on the host machine, setting:

Shell
1
tools.syncTime = "true"

After that, you may start the Virtual Machine. The clock should now keep synchronized.

References

VMware Virtual Disk Manager usage

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
VMware Virtual Disk Manager - build 39867.
Usage: vmware-vdiskmanager.exe OPTIONS diskName | drive-letter:
Offline disk manipulation utility
Options:
-c : create disk; need to specify other create options
-d : defragment the specified virtual disk
-k : shrink the specified virtual disk
-n : rename the specified virtual disk; need to
specify destination disk-name
-p : prepare the mounted virtual disk specified by
the drive-letter for shrinking
-q : do not log messages
-r : convert the specified disk; need to specify
destination disk-type
-x : expand the disk to the specified capacity
Additional options for create and convert:
-a : (for use with -c only) adapter type (ide, buslogic or lsilogic)
-s : capacity of the virtual disk
-t : disk type id
Disk types:
0 : single growable virtual disk
1 : growable virtual disk split in 2Gb files
2 : preallocated virtual disk
3 : preallocated virtual disk split in 2Gb files
The capacity can be specified in sectors, Kb, Mb or Gb.
The acceptable ranges:
ide adapter : [100.0Mb, 950.0Gb]
scsi adapter: [100.0Mb, 950.0Gb]
ex 1: vmware-vdiskmanager.exe -c -s 850Mb -a ide -t 0 myIdeDisk.vmdk
ex 2: vmware-vdiskmanager.exe -d myDisk.vmdk
ex 3: vmware-vdiskmanager.exe -r sourceDisk.vmdk -t 0 destinationDisk.vmdk
ex 4: vmware-vdiskmanager.exe -x 36Gb myDisk.vmdk
ex 5: vmware-vdiskmanager.exe -n sourceName.vmdk destinationName.vmdk
ex 6: vmware-vdiskmanager.exe -k myDisk.vmdk
ex 7: vmware-vdiskmanager.exe -p m:
(A virtual disk first needs to be mounted at m:
using the VMware Diskmount Utility.)

VMware Virtual Disk Manager examples

Converting growable into preallocated disk
This line will convert the growable virtual disk ‘WebFileServer.vmdk’ to type 3 (aka ‘preallocated virtual disk split in 2Gb files’). The resulting virtual disk will be created as ‘WebFileServer_pre-alloc.vmdk’.

Shell
1
vmware-vdiskmanager -r "WebFileServer.vmdk" -t 3 "WebFileServer_pre-alloc.vmdk"

See Also