以前、(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のプラグインとして
作成してみました。
#!/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
...