keepalived を使ってみたメモ

いまさらだけど keepalived を使ってみたメモ。LVS ではなく HAProxy の冗長化に使用するつもりなので LVS 関係の設定はありません。

CentOS 7 に yum で入れたバージョンで試しています。

  • keepalived-1.2.13-7.el7.x86_64

vrrp_script と track_script

vrrp_script でチェックスクリプトを定義して、

vrrp_script chk_haproxy {
    script "systemctl is-active haproxy"
    interval 3 # スクリプトが実行されるインターバル
    fall 3     # 非ゼロの終了コードが 3 回続いたら成功から失敗に遷移する
    rise 2     # 非ゼロの終了コードが 2 回続いたら失敗から成功に遷移する
}

vrrp_script chk_http_port {
    script "< /dev/tcp/127.0.0.1/80"
    interval 3
    fall 3
    rise 2
}

vrrp_instancetrack_script で VRRP インスタンスに設定する。

vrrp_instance VI_1 {

    :

    track_script {
      chk_haproxy
      chk_http_port # 複数指定できる
    }
}

vrrp_script の weight

vrrp_sync_group を設定していてかつ weight も設定しているとチェック自体が実行されなくなる。

vrrp_sync_group を設定していなければ weight の値によって次のように動作する。

  • weight が未設定
    • スクリプトが失敗ると FAULT になる
  • weight が正数
    • スクリプトが成功するとプライオリティが指定値だけ上がる
  • weight が負数
    • スクリプトが失敗するとプライオリティが指定値だけ下がる

weight を指定している場合に、nopreempt も指定しているとスクリプトが失敗してもフェールオーバーしない(MASTER が FAULT にならないかぎりフェイルオーバーしないため)。

smtp_alert

global_defs で通知先やメールサーバを設定し、vrrp_sync_groupvrrp_instancesmtp_alert を指定すると、ステートの変化時にメールで通知できる。

global_defs {
    notification_email {
        ore@example.com
    }
    notification_email_from keepalived@example.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 10

    :
}

vrrp_sync_group VG_1 {
    :
    smtp_alert
}

vrrp_instance VI_1 {
    :
    smtp_alert
}

送信されるメールの内容は次のようなもの。

Sublect: [192.168.33.11] VRRP Group VG - Entering BACKUP state
Body: => All VRRP group instances are now in BACKUP state <=
Sublect: [192.168.33.11] VRRP Instance VIP - Entering BACKUP state
Body: => VRRP Instance is nolonger owning VRRP VIPs <=

MASTER や BACKUP になったときは通知されるけど FAULT になったときは通知されない。

notify

vrrp_sync_groupvrrp_instance でステートの変化時に実行するスクリプトを指定することができる。

vrrp_sync_group VG_1 {
    :
    notify        "/vagrant/notify.sh"
    notify_master "/vagrant/notify.sh master"
    notify_backup "/vagrant/notify.sh backup"
    notify_fault  "/vagrant/notify.sh fault"
}

vrrp_instance VI_1 {
    :
    notify        "/vagrant/notify.sh"
    notify_master "/vagrant/notify.sh master"
    notify_backup "/vagrant/notify.sh backup"
    notify_fault  "/vagrant/notify.sh fault"
    notify_stop   "/vagrant/notify.sh stop"
}

notify は指定した値がそのまま実行可能ファイル名だと認識されるので引数を指定することはできない。

notify "/vagrant/notify.sh"     # OK
notify "/vagrant/notify.sh arg" # NG

その他のスクリプトは引数を指定することができる。

notify_master "/vagrant/notify.sh master"
notify_backup "/vagrant/notify.sh backup"
notify_fault  "/vagrant/notify.sh fault"
notify_stop   "/vagrant/notify.sh stop"

notify は次のように引数が付けられて実行される。

notify.sh GROUP VG_1 MASTER 0
notify.sh INSTANCE VI_1 MASTER 100
notify.sh GROUP VG_1 BACKUP 0
notify.sh INSTANCE VI_1 BACKUP 100
notify.sh GROUP VG_1 FAULT 0
notify.sh INSTANCE VI_1 FAULT 100

最後の数字は優先度で GROUP のときは優先度とか無いので常に 0 になる。

その他のスクリプトは引数はつかない(設定で指定した引数がそのまま渡される)。

notify_stopvrrp_instance にのみ設定することができて、 VRRP インスタンスのシャットダウン時に実行される。

iptables や tcpdump で VRRP パケットを操作

iptables を有効にする。

sudo yum install -y iptables-services
sudo systemctl start iptables.service
sudo systemctl enable iptables.service
sudo iptables -F
sudo service iptables save

プロトコルには vrrp を指定する。

iptables -A INPUT -p vrrp -j DROP

tcpdump でも vrrp を指定できる。

tcpdump -nn -i any vrrp

vrrp のタイムアウト

vrrp のタイムアウト(MASTER が停止したと判断される時間)は advert_int の 3 倍で、変更できない。

unicast

自分自身に unicast しても届かないので、次のように2台で同じ値を設定しても多分大丈夫。

unicast_peer {
    192.168.33.10
    192.168.33.11
}

ログ

/etc/rsyslog.d/keepalived.conf 辺りで次のようにしておけば、ログを /var/log/keepalived.log に出力することができる(デフォだと /var/log/messages に出る)。

/etc/rsyslog.d/keepalived.conf

:programname, startswith, "Keepalived" /var/log/keepalived.log
& stop

:programname, startswith, "keepalived" /var/log/keepalived.log
& stop

ログローテートも必要。

/etc/logrotate.d/keepalived

/var/log/keepalived.log {
    daily
    rotate 10
    missingok
    sharedscripts
    postrotate
        /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
    endscript
}

これだと1回のローテートで rsyslogd に複数回 HUP される気がするので /etc/logrotate.d/syslog に追記するほうが良いかもしれない。

/etc/logrotate.d/syslog

/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
/var/log/keepalived.log
{
    missingok
    sharedscripts
    postrotate
        /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
    endscript
}

参考