はじめまして。
尾崎と申します。
プログラムを作るのは得意ではないですが、インフラ、サーバ、ネットワーク構築が大好きで、
スパイシーソフトでは主にインフラの業務を担当しています。
よろしくお願い致します。
今回は始めて、ということで、軽めの話題から始めようと思います。
通常、耐障害性を高めるために、サーバ台数を増やして
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点についてはまた機会をあらためて記述することにいたします。
それではごきげんよう。