외부스크립트를 이용해서 HAProxy node 체크하기

HAProxy + MariaDB Galera Cluster 구성을 하고 테스트를 진행하니 문제가 발생해서 글을 남겨본다.

HAProxy

haproxy.cfg 설정파일에서 아래 옵션을 사용

option mysql-check user haproxy

이 옵션은 TCP 포트로의 접속가능 여부만 판단해서 health check를 한다.
Galera Cluster의 경우 노드가 복구될 때 쿼리를 하면 아래 메시지가 출력된다.

WSREP has not yet prepared node for application use

따라서 이 경우는 HAProxy에서 노드를 살려줘서는 안된다.

MariaDB Galera Cluster

MariaDB [(none)] > show global status where variable_name='wsrep_local_state';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| wsrep_local_state | 4     |
+-------------------+-------+

동기화가 완료되서 사용이 가능한 상태값이다.
다른 상태값은 아래 링크에서 확인한다.
https://mariadb.com/docs/ent/ref/mdb/status-variables/wsrep_local_state/

HAProxy external-check

기존에 mysql-check를 외부 스크립트를 이용하도록 변경한다.
외부 스크립트는 wsrep_local_state 값을 읽어서 원하는 값이면 exit 0 을 리턴하고 다른값이면 exit 255를 리턴시켜주면 된다.

/etc/haproxy/haproxy.cfg

global
        log /dev/log    local0
        log /dev/log    local1 notice	
        stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
        stats timeout 30s
        user haproxy
        group haproxy
        daemon
        external-check
        insecure-setuid-wanted

frontend mysql-front
        bind *:3306
        mode tcp
        default_backend mysql-back

backend mysql-back
        mode tcp        
	#option mysql-check user haproxy
	option external-check
        external-check path "/usr/bin:/bin"
        external-check command /etc/haproxy/script/check_node.sh
	balance roundrobin
        server db1 172.16.0.20:3306 check
        server db2 172.16.0.21:3306 check backup weight 2
        server db3 172.16.0.22:3306 check backup weight 1
  1. global 항목에 external-check 값이 추가되었다.
  2. external-check를 사용하기위해서 insecure-setuid-wanted 값을 추가해야한다
    https://www.haproxy.com/blog/announcing-haproxy-2-2/#security-hardening
  3. backend 항목에 기존 mysql-check 항목을 external-check로 변경
  4. external-check path 추가
  5. external-check command 추가

/etc/haproxy/script/check_node.sh

#!/bin/bash

MYSQL_HOST="$3"
MYSQL_PORT="$4"
MYSQL_USERNAME="haproxy"
MYSQL_PASSWORD=""
MYSQL_BIN="/bin/mysql"
MYSQL_OPTS="--no-defaults --connect-timeout=10 -snNE"
CMDLINE="$MYSQL_BIN $MYSQL_OPTS --host=$MYSQL_HOST --port=$MYSQL_PORT --user=$MYSQL_USERNAME -e"
WSREP_LOCAL_STATE_CHK=`$CMDLINE "SHOW GLOBAL STATUS WHERE VARIABLE_NAME='wsrep_local_state'" | tail -1`

if [ "$WSREP_LOCAL_STATE_CHK" != "4" ]; then
    exit 255
fi

exit 0

파라메터 정보

$1 = Virtual Service IP (VIP)
$2 = Virtual Service Port (VPT)
$3 = Real Server IP (RIP)
$4 = Real Server Port (RPT) 
$5 = Check Source IP 

$3, $4를 이용해서 노드의 상태를 읽는다.