はじめまして。 尾崎と申します。 プログラムを作るのは得意ではないですが、インフラ、サーバ、ネットワーク構築が大好きで、 スパイシーソフトでは主にインフラの業務を担当しています。 よろしくお願い致します。
今回は始めて、ということで、軽めの話題から始めようと思います。
通常、耐障害性を高めるために、サーバ台数を増やして 1台が壊れてもサービス全体として影響が出ないようにします。
アプリケーションサーバは複数台用意して負荷分散も同時に行いますし DBサーバはレプリケーションやHDDネットワークミラーなどの手法を用いて 耐障害性を高めます。
これらの手法はあちこちのwebページで解説されており、当たり前のように あちこちのサイトで行われています。
今回はcronなどが動作するサーバを二重化して耐障害性をあげてみます。 条件は以下です。 (1)アクティブ・スタンバイ構成とする (2)アクティブサーバがダウンした場合には即座に自動でフェイルオーバーしスタンバイサーバが処理を引き継ぐ (3)アクティブサーバ、スタンバイサーバが同時にcronに登録された処理を起動しない(=二重に処理を行わない、処理を行うのはどちらか片方のみ)
また、ネットワークは以下のようになっているとします。
cron1
IPアドレス:192.168.1.2
cron2
IPアドレス:192.168.1.3
cron,vip
IPアドレス:192.168.1.4
他のサーバからcronサーバにアクセスする際にはこのvipを使用します。
以上です。
これらの条件を満たすためにまず、 keepalivedを使用します。 また、cronの内容の同期をとるために lsync、rsyncを使用します。
まず、2台でcronの内容を同期するためのlsync、rsyncをインストールします。 cronは通常/var/spool/cronに保存されるので、 このディレクトリをlsync、rsyncで同期します。 cron1の/etc/rsyncd.conf
uid = root
gid = root
read only = no
hosts allow = 192.168.1.3
[cron]
path = /var/spool/cron
cron2の/etc/rsyncd.conf
uid = root
gid = root
read only = no
hosts allow = 192.168.1.2
[cron]
path = /var/spool/cron
この設定で2台のcronサーバのrsyncdを起動します。
またlsyncdの起動ですが、以下のように行います
cron1
lsyncd --rsync /var/spool/cron 192.168.1.3::cron
cron2
lsyncd --rsync /var/spool/cron 192.168.1.2::cron
これで、crontabの内容がリアルタイムで同期されるようになります。 誰かがアクティブサーバ上でcrontabコマンドでcronの内容を書き換えると すぐにスタンバイサーバのcronも書き換えられます。
これでcronの冗長性は確保できました。
ところが。 これでは、cronの内容が2台で重複しているため、cron上の同じコマンドが 2台のサーバで重複して起動されることになってしまいます。 これでは、最初の条件の(3)に反してしまいます。
これを避けるために、 /var/spool/cronを直接同期することはやめちゃいます。 私の方では /var/spool/_cronというディレクトリを作成し、このディレクトリを同期するようにしました。 そしてアクティブサーバは /var/spool/_cronから/var/spool/cronにsymlinkを作成します。 スタンバイサーバはそのまんまです。 こうすることにより、cronの処理を行うのはアクティブサーバのみになります。
さて、これで、一通りの動作をするサーバの構築が完了しました。
この後は自動フェイルオーバの機能を構築します。
このためにkeepalivedを設定しますが、keepalivedはフェイルオーバ時、 フェイルバック時に指定したコマンドを発行することができます。 これを利用して、以下の動作を実装します。
アクティブサーバがダウンした時 /var/spool/_cronから/var/spool/cronへのsymlinkを削除
スタンバイサーバがアクティブに昇格した時 /var/spool/_cronから/car/spool/cronへのsymlinkを作成
この動作を実装するため、keepalived.confを以下のようにしてみます。
global_defs {
notification_email {
love@example.com
}
notification_email_from lovelove@example.com
smtp_server 192.168.1.254
smtp_connect_timeout 30
router_id CRON_EXAMPLE
}
vrrp_instance ETH1 {
state BACKUP
interface eth1
virtual_router_id 32
priority 100
garp_master_delay 3
nopreempt
advert_int 1
notify_master "/root/scripts/master.sh"
notify_backup "/root/scripts/slave.sh"
notify_fault "/root/scripts/slave.sh"
authentication {
auth_type PASS
auth_pass LOVELOVE
}
virtual_ipaddress {
192.168.1.4/24 dev eth1
}
}
ここで、master.shというのと、slave.shというのが先ほどのsymlink作成、symlink削除の シェルスクリプトになります。
簡略化したものを記述してみます。 master.sh
#!/bin/sh
if [ -d /var/spool/cron ]; then
rm -rf /var/spool/cron
elif [ -L /var/spool/cron ]; then
rm -f /var/spool/cron
fi
ln -s /var/spool/_cron /var/spool/cron
/etc/init.d/crond restart > /dev/null
slave.sh
#!/bin/sh
if [ -d /var/spool/cron ]; then
rm -rf /var/spool/cron
elif [ -L /var/spool/cron ]; then
rm -f /var/spool/cron
fi
/etc/init.d/crond restart > /dev/null
これで2台のサーバのkeepalivedの設定が終わり、です。
試してみましょう。
cron1です。
-bash-4.1$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 192.168.1.2 brd 192.168.1.255 scope global eth1
inet 192.168.1.4 scope global secondary eth1
-bash-4.1$ ls -la /var/spool/
total 36
drwxr-xr-x. 9 root root 4096 Jan 5 14:07 .
drwxr-xr-x. 21 root root 4096 Dec 7 20:00 ..
drwxr-xr-x. 2 root root 4096 Sep 29 21:03 anacron
drwx------. 3 daemon daemon 4096 Sep 29 21:03 at
lrwxrwxrwx 1 root root 16 Jan 17 14:07 cron -> /var/spool/_cron
drwx------. 2 root root 4096 Jan 11 20:21 _cron
drwxr-xr-x. 2 root root 4096 Nov 11 2010 lpd
drwxrwxr-x. 2 root mail 4096 Jan 3 18:00 mail
drwxr-xr-x. 2 root root 4096 Nov 1 2010 plymouth
drwxr-xr-x. 16 root root 4096 Sep 29 21:03 postfix
シンボリックリンクがあります。
この状態でのcron2です。
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 192.168.1.3/24 brd 172.16.7.255 scope global eth1
-bash-4.1$ ls -la /var/spool/
total 40
drwxr-xr-x. 10 root root 4096 Jan 10 09:42 .
drwxr-xr-x. 22 root root 4096 Dec 21 14:39 ..
drwxr-xr-x. 2 root root 4096 Sep 30 23:12 anacron
drwx------. 3 daemon daemon 4096 Sep 30 23:12 at
drwx------ 2 root root 4096 Jan 17 09:42 cron
drwxr-xr-x 2 root root 4096 Jan 11 20:21 _cron
drwxr-xr-x. 2 root root 4096 Nov 11 2010 lpd
drwxrwxr-x. 2 root mail 4096 Jan 3 18:36 mail
drwxr-xr-x. 2 root root 4096 Nov 1 2010 plymouth
drwxr-xr-x. 16 root root 4096 Sep 30 23:12 postfix
symlinkになってません。
アクティブサーバのcron1を落として、 リンクの内容を見てみましょう。
-bash-4.1$ /etc/init.d/keepalived stop
-bash-4.1$ ls -la /var/spool/
total 40
drwxr-xr-x. 10 root root 4096 Jan 10 09:42 .
drwxr-xr-x. 22 root root 4096 Dec 21 14:39 ..
drwxr-xr-x. 2 root root 4096 Sep 30 23:12 anacron
drwx------. 3 daemon daemon 4096 Sep 30 23:12 at
drwx------ 2 root root 4096 Jan 10 09:42 cron ←symlinkが消えてます
drwxr-xr-x 2 root root 4096 Jan 11 20:21 _cron
drwxr-xr-x. 2 root root 4096 Nov 11 2010 lpd
drwxrwxr-x. 2 root mail 4096 Jan 3 18:36 mail
drwxr-xr-x. 2 root root 4096 Nov 1 2010 plymouth
drwxr-xr-x. 16 root root 4096 Sep 30 23:12 postfix
-bash-4.1$ ip addr show
1: lo: mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth1: mtu 1500 qdisc mq state UP qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 192.168.1.2 brd 192.168.1.255 scope global eth1
リンクが消えて、VIPの192.168.1.4が消えました。
この状態でcron2を見てみます。
-bash-4.1$ ls -la /var/spool/
total 36
drwxr-xr-x. 9 root root 4096 Jan 5 14:07 .
drwxr-xr-x. 21 root root 4096 Dec 7 20:00 ..
drwxr-xr-x. 2 root root 4096 Sep 29 21:03 anacron
drwx------. 3 daemon daemon 4096 Sep 29 21:03 at
lrwxrwxrwx 1 root root 16 Jan 17 14:07 cron -> /var/spool/_cron ←symlinkが作成されてます
drwx------. 2 root root 4096 Jan 11 20:21 _cron
drwxr-xr-x. 2 root root 4096 Nov 11 2010 lpd
drwxrwxr-x. 2 root mail 4096 Jan 3 18:00 mail
drwxr-xr-x. 2 root root 4096 Nov 1 2010 plymouth
drwxr-xr-x. 16 root root 4096 Sep 29 21:03 postfix
-bash-4.1$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 192.168.1.3 brd 192.168.1.255 scope global eth1
inet 192.168.1.4 scope global secondary eth1
symlinkが作成され、vipがcron2に移ったことが確認できます。
これで実際にcronを登録してみて動作の確認を取ってみれば、 2台のうちアクティブサーバのみでcronが起動されることが確認できるはずです。
いくつか課題 ・このkeepalived.confではcrondの状態を監視していないので crondが落ちた場合はfailoverしません ・cronに登録されたタスクが途中で終わってしまった場合どうしよう?
上記2点についてはまた機会をあらためて記述することにいたします。
それではごきげんよう。