以前、(ELBとからめて)Hostヘッダでの振り分けをHAProxyでやってみるのような記事を紹介しました。

しかし、下記のような指摘をいただきました。

HAProxyは起動時に名前解決してIPをキャッシュするので、ELBのIP変更を検知・リロードする仕組みが必要ですね @suz_lab – blog: (ELBとからめて)Hostヘッダでの振り分けをHAProxyでやって… htn.to/72F8JM
— Michael H. Oshitaさん (@ijin) 12月 10, 2012

よく考えるとご指摘の通りで、HAProxyはバックエンドサーバをDNS名で指定すると、最初に名前解決した
IPアドレスをキャッシュし、そのまま使ってしまいます。

そして、ELBは(internalも)IPスケールアウト/インなどでIPアドレスが変わってしまう可能性があるので、
このままでは、今後問題が発生してしまいます。

そこで、ELBのDNS名に対するIPアドレスが変更されたら、HAProxyをリロード(無停止で設定を入れ替える)仕組みを
Monitで実現してみました。
(HAProxyのリロードに関する話はHAProxy で graceful restart する方法の記事が大変参考になります)

○DNS名に対するIPアドレスの変更をチェックするNagiosプラグイン

Monitに関することですが、表記のチェックに関してはNagiosの監視でも使いそうなので、Nagiosのプラグインとして
作成してみました。

check_dns_ip

#!/bin/sh

. `dirname $0`/utils.sh

set -e
trap 'echo "UNKNOWN: $?"; exit $STATE_UNKNOWN' ERR

WARN=1
CRIT=1

while getopts c:w:n: OPTNAME; do
case "$OPTNAME" in
w)
WARN="$OPTARG"
;;
c)
CRIT="$OPTARG"
;;
n)
DNS_NAME="$OPTARG"
;;
*)
echo "UNKNOWN: Usage"
exit $STATE_UNKNOWN
;;
esac
done

IP_FILE=`dirname $0`/../../var/run/check_dns_ip-$DNS_NAME.txt
IP_LIST=`dig +noall +answer $DNS_NAME | awk '{print $5}' | sort`

if [ ! -f $IP_FILE ]; then
echo $IP_LIST > $IP_FILE
echo "OK : Initial Setup"
exit $STATE_OK
fi

COUNT=`echo $IP_LIST | diff - $IP_FILE | wc -l`

if [ $COUNT -ge $CRIT ]; then
echo "CRITICAL: IP Address Chenged"
echo $IP_LIST > $IP_FILE
exit $STATE_CRITICAL
elif [ $COUNT -ge $WARN ]; then
echo "WARNING: IP Address Chenged"
echo $IP_LIST > $IP_FILE
exit $STATE_WARNING
elif [ $COUNT -eq 0 ]; then
echo "OK: IP Address Not Chenge"
exit $STATE_OK
fi

echo "UNKNOWN: End"; exit $STATE_UNKNOWN

注意点は下記となります。

  • 同じディレクトリにutils.shが必要
    • /usr/lib64/nagios/plugins/utils.sh等にある場合はシンボリックリンクが必要
  • ../../var/run/にIPアドレスの状態を保持するファイルが作成できるようにする
    • ファイルの中身は10.0.64.53 10.0.65.164のようになる

下記のように実行することができます。

・最初に実行した場合

# ./check_dns_ip -n internal-web-xxx.ap-northeast-1.elb.amazonaws.com
OK : Initial Setup

・IPアドレスが変わっていない場合

# ./check_dns_ip -n internal-web-xxx.ap-northeast-1.elb.amazonaws.com
OK: IP Address Not Chenge

・IPアドレスが変わった場合

# ./check_dns_ip -n internal-web-xxx.ap-northeast-1.elb.amazonaws.com
CRITICAL: IP Address Chenged

※ステータスファイルもアップデートされるので、このアラートは一回のみです。

○Monitの設定ファイルとチェックプログラムの作成

Monitの設定ファイルは、下記のようにしました。

・check_dns_ip_elb.conf

check program check_dns_ip_elb with path "/opt/suz-lab/etc/monit/check_dns_ip_elb.sh"
if status != 0 then exec "/etc/init.d/haproxy reload"

チェック用のプログラムを実行し、終了ステータスコードが0以外の場合は、HAProxyを
リロードするようにしています。

本来はチェックプログラムは直接、上記で作成したスクリプトを利用したかったのですが、
引数が使えないという制約で、改めて下記のような専用のスクリプトを用意しています。

・check_dns_ip_elb.sh

#!/bin/sh
DNS_NAME=internal-web-xxx.ap-northeast-1.elb.amazonaws.com
set -e
trap 'echo "NG: $?"' ERR
/opt/suz-lab/lib/nagios/check_dns_ip -n $DNS_NAME
exit $?

以上で、Monitが定期的にELBのアドレスをチェックし、変更があった場合HAProxyを再起動
するようになります。

○SUZ-LAB CentOS AMIで具体的に設定して確認

次のようにGitHubから取ってくるのが早いかもしれません。

# cd /opt/
# git clone https://github.com/suz-lab/suz-lab-centos-ami.git suz-lab
# chmod 755 /opt/suz-lab/lib/nagios/check_dns_ip
# ln -s /usr/lib64/nagios/plugins/utils.sh /opt/suz-lab/lib/nagios/utils.sh
# ls /opt/suz-lab/etc/monit/
README.md check_dns_ip_elb.conf check_dns_ip_elb.sh
# cat /etc/monit.conf
...
include /opt/suz-lab/etc/monit/*.conf
# /etc/init.d/monit restart

ELBのIPアドレスが変更されると、次のようにHAProxyがリロードされます。

# cat /var/log/messages
...
Dec 13 23:20:13 ip-10-0-1-52 monit[19484]: 'check_dns_ip_elb' status failed (2) for /opt/suz-lab/etc/monit/check_dns_ip_elb.sh. Error: no output to stderr..
Dec 13 23:20:13 ip-10-0-1-52 monit[19484]: 'check_dns_ip_elb' exec: /etc/init.d/haproxy
Dec 13 23:20:14 localhost haproxy[19612]: Proxy web started.
Dec 13 23:20:14 localhost haproxy[13041]: Pausing frontend proxy.
Dec 13 23:20:14 localhost haproxy[19612]: Proxy proxy started.
Dec 13 23:20:14 localhost haproxy[13041]: Stopping frontend proxy in 0 ms.
Dec 13 23:20:14 localhost haproxy[13041]: Stopping backend web in 0 ms.
Dec 13 23:20:14 localhost haproxy[13041]: Proxy proxy stopped (FE: 0 conns, BE: 0 conns).
Dec 13 23:20:14 localhost haproxy[13041]: Proxy web stopped (FE: 0 conns, BE: 0 conns).
Dec 13 23:21:13 ip-10-0-1-52 monit[19484]: 'check_dns_ip_elb' status succeeded
...

こちらの記事はなかの人(suz-lab)監修のもと掲載しています。
元記事は、こちら