8

Deploying HAProxy 1.5 from source

 3 years ago
source link: http://www.linux-admins.net/2014/09/deploying-haproxy-15-from-source.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Deploying HAProxy 1.5 from source

In an older post I showed how to create highly available HAProxy load balancer and front-end it with Pound for SSL termination.  With the release of HAProxy 1.5 the SSL termination is now built in, along with a nice set of new features, such as stick tables.

In this post I'll setup HAProxy with SSL offloading and load balance HTTP, MySQL and rabbitmq in an active/passive mode.

First lets install HAProxy from source (you can of course use a package, but I'll be using Debian Squeeze for this deployment):

[root@server ~] apt-get install libpcre3-dev libssl-dev [root@server ~] wget http://www.haproxy.org/download/1.5/src/haproxy-1.5.4.tar.gz [root@server ~] tar zxfv haproxy-1.5.4.tar.gz [root@server ~] cd haproxy-1.5.4/ [root@server haproxy-1.5.4] make TARGET=custom CPU=native USE_PCRE=1 USE_LIBCRYPT=1 USE_LINUX_SPLICE=1 USE_LINUX_TPROXY=1 USE_OPENSSL=yes [root@server haproxy-1.5.4] make install [root@server haproxy-1.5.4] useradd -M haproxy

Since we are installing from source, we'll need an init script in /etc/init.d and the default options file in /etc/default. You can get one from an older package and make sure that the paths match the installation or just use the one bellow:

[root@server ~] cat /etc/init.d/haproxy #!/bin/sh ### BEGIN INIT INFO # Provides: haproxy # Required-Start: $local_fs $network $remote_fs # Required-Stop: $local_fs $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: fast and reliable load balancing reverse proxy # Description: This file should be used to start and stop haproxy. ### END INIT INFO

# Author: Arnaud Cornet <[email protected]>

PATH=/sbin:/usr/local/sbin:/bin:/usr/bin PIDFILE=/var/run/haproxy.pid CONFIG=/etc/haproxy/haproxy.cfg HAPROXY=/usr/local/sbin/haproxy EXTRAOPTS= ENABLED=0

test -x $HAPROXY || exit 0 test -f "$CONFIG" || exit 0

if [ -e /etc/default/haproxy ]; then . /etc/default/haproxy fi

test "$ENABLED" != "0" || exit 0

[ -f /etc/default/rcS ] && . /etc/default/rcS . /lib/lsb/init-functions

haproxy_start() { start-stop-daemon --start --pidfile "$PIDFILE" \ --exec $HAPROXY -- -f "$CONFIG" -D -p "$PIDFILE" \ $EXTRAOPTS || return 2 return 0 }

haproxy_stop() { if [ ! -f $PIDFILE ] ; then # This is a success according to LSB return 0 fi for pid in $(cat $PIDFILE) ; do /bin/kill $pid || return 4 done rm -f $PIDFILE return 0 }

haproxy_reload() { $HAPROXY -f "$CONFIG" -p $PIDFILE -D $EXTRAOPTS -sf $(cat $PIDFILE) \ || return 2 return 0 }

haproxy_status() { if [ ! -f $PIDFILE ] ; then # program not running return 3 fi

for pid in $(cat $PIDFILE) ; do if ! ps --no-headers p "$pid" | grep haproxy > /dev/null ; then # program running, bogus pidfile return 1 fi done

return 0 }

case "$1" in start) log_daemon_msg "Starting haproxy" "haproxy" haproxy_start ret=$? case "$ret" in 0) log_end_msg 0 ;; 1) log_end_msg 1 echo "pid file '$PIDFILE' found, haproxy not started." ;; 2) log_end_msg 1 ;; esac exit $ret ;; stop) log_daemon_msg "Stopping haproxy" "haproxy" haproxy_stop ret=$? case "$ret" in 0|1) log_end_msg 0 ;; 2) log_end_msg 1 ;; esac exit $ret ;; reload|force-reload) log_daemon_msg "Reloading haproxy" "haproxy" haproxy_reload case "$?" in 0|1) log_end_msg 0 ;; 2) log_end_msg 1 ;; esac ;; restart) log_daemon_msg "Restarting haproxy" "haproxy" haproxy_stop haproxy_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; 2) log_end_msg 1 ;; esac ;; status) haproxy_status ret=$? case "$ret" in 0) echo "haproxy is running." ;; 1) echo "haproxy dead, but $PIDFILE exists." ;; *) echo "haproxy not running." ;; esac exit $ret ;; *) echo "Usage: /etc/init.d/haproxy {start|stop|reload|restart|status}" exit 2 ;; esac

:

[root@server ~] chmod u+x /etc/init.d/haproxy [root@server ~] cat /etc/default/haproxy # Set ENABLED to 1 if you want the init script to start haproxy. ENABLED=1

Time to configure HAProxy for 4 different services - plain HTTP, HTTPS terminated by the load balancer, and MySQL and RabbitMQ in active/passive mode:

[root@server ~] mkdir /etc/haproxy [root@server ~] cat /etc/haproxy/haproxy.cfg

global log 127.0.0.1 local1 log-tag haproxy maxconn 4096 user haproxy group haproxy daemon stats socket /var/run/haproxy.sock mode 600 level admin stats timeout 2m tune.ssl.default-dh-param 2048

defaults log global mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms option dontlognull option http-server-close

peers HAPEERS peer haproxy-n01 10.13.238.51:5555 peer haproxy-n02 10.13.238.51:5555

frontend http bind 10.13.238.21:80 reqadd X-Forwarded-Proto:\ http default_backend http_nodes

frontend https-terminated bind 10.13.238.22:443 ssl crt /etc/ssl/certs/api.example.net.pem ciphers RC4+SHA:!aNULL:!MD5 no-sslv3 option httpclose option forwardfor option httplog clf reqadd X-Forwarded-Proto:\ https default_backend https-terminated_nodes

frontend mysql mode tcp bind 10.13.238.19:3306 timeout client 168h default_backend mysql_nodes log global option tcplog option logasap

frontend rabbitmq mode tcp bind 10.13.238.20:5672 timeout client 168h default_backend rabbitmq_nodes log global option tcplog option logasap

backend http_nodes mode http balance leastconn option httpclose option forwardfor option redispatch # This check will fail a node on codes that are not 2xx or 3xx option httpchk GET / # This check will fail a node on 5xx codes only # http-check expect ! rstatus ^5 cookie JSESSIONID prefix server apt-n01 10.13.238.39:80 check inter 5000

backend https-terminated_nodes mode http balance roundrobin cookie JSESSIONID prefix option redispatch option httpchk GET / server api-n01 10.13.238.37:8888 check inter 5000 server api-n02 10.13.238.38:8888 check inter 5000

backend mysql_nodes mode tcp balance roundrobin option mysql-check user haproxy_check stick-table type ip size 20k peers HAPEERS stick on dst timeout server 168h server mysql-n01 10.13.238.53:3306 check server mysql-n02 10.13.238.54:3306 check backup

backend rabbitmq_nodes mode tcp balance roundrobin stick-table type ip size 20k peers HAPEERS stick on dst timeout server 168h server rabbitmq-n01 10.13.238.35:5672 check server rabbitmq-n02 10.13.238.36:5672 check backup

All of the options are documented [1], but the most interesting once are the "stats socket", which allows you to connect to a socket and perform simple operations on HAProxy and gather statistics without needing to restart the server. You can do this in either interactive or non-interactive mode using the socat utility:

[root@server ~] apt-get install socat [root@server ~] socat /var/run/haproxy.sock readline # Or on newer versions of socat: # socat /var/run/haproxy.sock stdio prompt

> show info Name: HAProxy Version: 1.5.4 Release_date: 2014/09/02 Nbproc: 1 Process_num: 1 Pid: 17066 Uptime: 0d 1h07m55s Uptime_sec: 4075 Memmax_MB: 0 Ulimit-n: 8248 Maxsock: 8248 Maxconn: 4096 Hard_maxconn: 4096 CurrConns: 313 CumConns: 1792 CumReq: 27874 MaxSslConns: 0 CurrSslConns: 0 CumSslConns: 537 Maxpipes: 0 PipesUsed: 0 PipesFree: 0 ConnRate: 1 ConnRateLimit: 0 MaxConnRate: 68 SessRate: 1 SessRateLimit: 0 MaxSessRate: 68 SslRate: 0 SslRateLimit: 0 MaxSslRate: 5 SslFrontendKeyRate: 0 SslFrontendMaxKeyRate: 6 SslFrontendSessionReuse_pct: 0 SslBackendKeyRate: 0 SslBackendMaxKeyRate: 0 SslCacheLookups: 0 SslCacheMisses: 0 CompressBpsIn: 0 CompressBpsOut: 0 CompressBpsRateLim: 0 Tasks: 345 Run_queue: 1 Idle_pct: 100 node: zxtm-n01 description:

> quit

[root@server ~] echo "show stat" | socat - /var/run/haproxy.sock | grep -E "^rabbit|pxname" | tr -s ',' ' ' | tr -d '#' | column -t pxname svname qcur qmax scur smax slim stot bin bout dreq dresp ereq econ eresp wretr wredis status weight act bck chkfail chkdown lastchg downtime qlimit pid iid sid throttle lbtot tracked type rate rate_lim rate_max check_status check_code check_duration hrsp_1xx hrsp_2xx hrsp_3xx hrsp_4xx hrsp_5xx hrsp_other hanafail req_rate req_rate_max req_tot cli_abrt srv_abrt comp_in comp_out comp_byp comp_rsp lastsess last_chk last_agt qtime ctime rtime ttime rabbitmq FRONTEND 194 194 2000 194 0 0 0 0 0 OPEN 1 6 0 0 0 0 44 0 0 0 0 0 0 0 rabbitmq_nodes rabbitmq-n01 0 0 194 194 194 0 0 0 0 0 0 0 UP 1 1 0 0 0 740 0 1 14 1 1 2 0 44 L4OK 0 0 0 0 592 0 0 0 0 rabbitmq_nodes rabbitmq-n02 0 0 0 0 0 0 0 0 0 0 0 0 UP 1 0 1 0 0 740 0 1 14 2 0 2 0 0 L4OK 0 0 0 0 -1 0 0 0 0 rabbitmq_nodes BACKEND 0 0 194 194 2000 194 0 0 0 0 0 0 0 0 UP 1 1 1 0 740 0 1 14 0 1 1 0 44 0 0 0 0 0 0 592 0 0 0 0

[root@server ~] echo "disable server http_nodes/apt-n01" | socat stdio /var/run/haproxy.sock

To enable the static HTTP status page add the following to the config file:

listen stats :8080 mode http stats enable stats hide-version stats realm Haproxy\ Statistics stats uri / stats auth admin:yourpassword

To have some real time view of what's going on, you can use the ncurses hatop, just install and run:

[root@server ~] apt-get install hatop [root@server ~] hatop -s /var/run/haproxy.sock

The SSL termination is configured by specifying the "ssl" option and providing a PEM file, containing the cert and the private key on line 34.

To setup MySQL and RabbitMQ in an active/passive mode, where only one of the servers will be accepting connections, and when the main server comes back up after a failure the connections will still stick to the backup server, you specify the "backup" option and define a stick-table on line 87 and line 83.

One more option worth mentioning is the MySQL health check specified on line 82. The check consists of sending two MySQL packets, one Client Authentication packet, and one QUIT packet, to correctly close the MySQL session, using the specified user - in this case haproxy_check - so make sure you create it first:

mysql> USE mysql; mysql> INSERT INTO user (Host,User) values ('10.13.238.51','haproxy_check'); mysql> FLUSH PRIVILEGES;

Another useful option is the tcp-check. With this it's easy to send and receive certain messages to the back-ends and act on them. This is particularly useful in managing Redis master and slave instances controlled by Sentinel:

backend redis_nodes mode tcp option tcplog option tcp-check tcp-check send AUTH\ somepassword\r\n tcp-check expect string +OK tcp-check send PING\r\n tcp-check expect string +PONG tcp-check send info\ replication\r\n tcp-check expect string role:master tcp-check send QUIT\r\n tcp-check expect string +OK server redis_node1 192.168.1.10:6379 maxconn 4096 check inter 5s server redis_node2 192.168.1.20:6379 maxconn 4096 check inter 5s server redis_node3 192.168.1.30:6379 maxconn 4096 check inter 5s

In the example above HAProxy queries Redis nodes about their role, and it will fail-over only if a back-end became the new master. If Sentinel is controlling the cluster and a new master is elected HAProxy will fail-over traffic to it.

To allow HAProxy to send separate logs to rsyslog you can use a file similar to this:

[root@server ~] cat /etc/rsyslog.d/haproxy.conf $ModLoad imudp $UDPServerAddress 127.0.0.1 $UDPServerRun 514

if $syslogfacility-text == 'local1' and $msg contains 'rabbitmq' then /var/log/haproxy_rabbitmq.log if $syslogfacility-text == 'local1' and $msg contains 'http' then /var/log/haproxy_api.log if $syslogfacility-text == 'local1' and $msg contains 'mysql' then /var/log/haproxy_mysql.log if $syslogfacility-text == 'local1' and ($msg contains 'UP' or $msg contains 'DOWN') then /var/log/haproxy_backends.log

local1.* -/var/log/haproxy.log & ~

And finally start the service:

[root@server ~] /etc/init.d/rsyslog restart [root@server ~] /etc/init.d/haproxy start

Resources:
[1]. http://cbonte.github.io/haproxy-dconv/configuration-1.5.html


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK