INSIGHT

インサイト

2012年119

cronのサーバを二重化する

はじめまして。 尾崎と申します。 プログラムを作るのは得意ではないですが、インフラ、サーバ、ネットワーク構築が大好きで、 スパイシーソフトでは主にインフラの業務を担当しています。 よろしくお願い致します。

今回は始めて、ということで、軽めの話題から始めようと思います。

通常、耐障害性を高めるために、サーバ台数を増やして 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点についてはまた機会をあらためて記述することにいたします。

それではごきげんよう。