MurakumoによるElastic Network Interfaceのフェイルオーバー

Murakumo 0.4.5をリリースしました。
https://rubygems.org/gems/murakumo/versions/0.4.5
今回はKeepalived/Heartbeatのような冗長化機能を追加しました。

Elastic Network Interfaceを使った冗長化の例

■概要

アクティブなサーバのMySQLが落ちたとき・サーバ自体が落ちたときに、バックアップ側にENIを付け替える例です。

■準備

まずVPCインスタンスを用意します。

server-01にENIをアタッチして、ルーティングテーブルを設定します。

server-01


[root@server-01 ~]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
169.254.169.254 * 255.255.255.255 UH 0 0 0 eth0
10.0.0.0 * 255.255.255.0 U 0 0 0 eth0
10.0.0.0 * 255.255.255.0 U 0 0 0 eth1
default 10.0.0.232 0.0.0.0 UG 0 0 0 eth0

server-02


[root@server-02 ~]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
169.254.169.254 * 255.255.255.255 UH 0 0 0 eth0
10.0.0.0 * 255.255.255.0 U 0 0 0 eth0
default 10.0.0.232 0.0.0.0 UG 0 0 0 eth0
※169.254.169.254を設定しておかないとメタ情報がとれなくてはまります


MurakumoとMySQLをインストールします。

Murakumo


yum install ruby-devel sqlite-devel make gcc-c++
gem install murakumo

MySQL


yum install mysql-devel mysql-server
gem install mysql


Murakumoの設定はこんな感じ。

/etc/murakumo.yml
---
address: 0.0.0.0
port: 53

auth-key: onion
log-level: debug
resolver: 10.0.0.2, 8.8.8.8
max-ip-num: 8

domain: ap-northeast-1.compute.internal

init-script: /etc/murakumo-init.rb

addr-includes: ^10\..*

notification:
  host: 127.0.0.1
  sender: sender@mail.from
  recipients:
    - recipient@mail.from

# alias hostname, ttl, master/secondary/backup, weight
alias:
  - mysql-server,60,master,100

health-check:
  mysql-server:
    interval: 5
    timeout: 5
    healthy: 2
    unhealthy: 2
    script: |
      mysql_check 'root'

# hook of activation of backup/secondary
activity-check:
  mysql-server:
    start-delay: 60
    interval: 10
    active: 2
    inactive: 2
    on-activate: /usr/local/sbin/attach_if

murakumo-init.rbでサーバ情報の取得するので、どちらのサーバも内容は同じです。
Aliasは「mysql-server」。


murakumo-init.rbはこんな感じ。

/etc/murakumo-init.rb

AWS_ACCESS_KEY_ID = '...'
AWS_SECRET_ACCESS_KEY = '...'
REGION = 'ap-northeast-1'

# get self ip address
ip_addr = Murakumo::Util.self_ip_address

# get hostname
tags = Murakumo::Util.ec2_tags(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, REGION)
hostname = tags['Name'] || `curl -s http://169.254.169.254/latest/meta-data/local-hostname`

# rewrite host option
@options['host'] = "#{ip_addr}, #{hostname}"

# get instances
ip_addrs = Murakumo::Util::ec2_private_ip_addresses(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, REGION)

# rewrite initial-nodes
nodes = ip_addrs.select {|inst_id, ip_addr, status|
  status == 'running'
}.map {|inst_id, ip_addr, status| ip_addr }

@options['initial-nodes'] = nodes.join(',') unless nodes.empty?


それからENIをフェイルオーバーするスクリプトがこんな感じ。

/usr/local/sbin/attach_if

#!/bin/sh
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
REGION=ap-northeast-1
IF_ID=eni-...

/usr/bin/murakumo-attach-ec2-attach-interface \
  -k "$AWS_ACCESS_KEY_ID" -s "$AWS_SECRET_ACCESS_KEY" \
  -r $REGION -n $IF_ID 2>&1 | logger

exit 0


最後にserver-01/02でMySQLとMurakumoを起動します。


[root@server-01 ~]# /etc/init.d/mysqld start
Starting mysqld: [ OK ]
[root@server-01 ~]# /etc/init.d/murakumo start
Starting daemon...
Waiting for daemon to start...
Daemon status: running pid=15143

■実験

初期状態ではserver-01にENIが刺さっています。

server-01


[root@server-01 ~]# ifconfig | grep ^e
eth0 Link encap:Ethernet HWaddr 02:40:B5:1B:3F:9A
eth1 Link encap:Ethernet HWaddr 02:40:B5:12:49:35

server-02


[root@server-02 ~]# ifconfig | grep ^e
eth0 Link encap:Ethernet HWaddr 02:40:B5:37:0B:C0

Murakumoのステータスはこんな感じです。


[root@server-01 ~]# mrkmctl -L
IP address TTL Priority Weight Activity Hostname
--------------- ------ --------- ------ -------- ----------
10.0.0.133 60 Master 100 Active mysql-server
10.0.0.133 60 Origin - Active server-01
10.0.0.55 60 Backup 100 Active mysql-server
10.0.0.55 60 Origin - Active server-02


まず、server-01のmysqlを落としてみると…

server-01


[root@server-01 ~]# tail /var/log/murakumo.log
I, [2012-01-22T12:27:25.606223 #15143] INFO -- : health condition changed: mysql-server: unhealthy
I, [2012-01-22T12:27:25.722457 #15143] INFO -- : sent the notice: unhealthy
I, [2012-01-22T12:27:40.563515 #15143] INFO -- : activity condition changed: mysql-server: inactive
I, [2012-01-22T12:27:40.640112 #15143] INFO -- : sent the notice: inactive
[root@server-01 ~]# ifconfig | grep ^e
eth0 Link encap:Ethernet HWaddr 02:40:B5:1B:3F:9A

server-02


[root@server-02 ~]# tail /var/log/murakumo.log
I, [2012-01-22T12:27:42.704476 #13467] INFO -- : activity condition changed: mysql-server: active
I, [2012-01-22T12:27:42.820635 #13467] INFO -- : sent the notice: active
[root@server-02 ~]# ifconfig | grep ^e
eth0 Link encap:Ethernet HWaddr 02:40:B5:37:0B:C0
eth1 Link encap:Ethernet HWaddr 02:40:B5:12:49:35

[root@server-01 ~]# mrkmctl -L
IP address TTL Priority Weight Activity Hostname
--------------- ------ --------- ------ -------- ----------
10.0.0.133 60 Master 100 Inactive mysql-server
10.0.0.133 60 Origin - Active server-01
10.0.0.55 60 Backup 100 Active mysql-server
10.0.0.55 60 Origin - Active server-02
server-01がUnhealthyになり、ENIがserver-02にアタッチされます。


次に、server-01のmysqlを再起動します。

server-01


[root@server-01 ~]# tail /var/log/murakumo.log
I, [2012-01-22T12:31:15.765068 #15143] INFO -- : health condition changed: mysql-server: healthy
I, [2012-01-22T12:31:15.842994 #15143] INFO -- : sent the notice: healthy
I, [2012-01-22T12:31:30.658938 #15143] INFO -- : activity condition changed: mysql-server: active
I, [2012-01-22T12:31:30.739008 #15143] INFO -- : sent the notice: active
[root@server-01 ~]# ifconfig | grep ^e
eth0 Link encap:Ethernet HWaddr 02:40:B5:1B:3F:9A
eth1 Link encap:Ethernet HWaddr 02:40:B5:12:49:35

server-02


[root@server-01 ~]# tail /var/log/murakumo.log
I, [2012-01-22T12:31:28.776223 #13467] INFO -- : activity condition changed: mysql-server: inactive
I, [2012-01-22T12:31:28.855345 #13467] INFO -- : sent the notice: inactive
[root@server-02 ~]# ifconfig | grep ^e
eth0 Link encap:Ethernet HWaddr 02:40:B5:37:0B:C0

[root@server-01 ~]# mrkmctl -L
IP address TTL Priority Weight Activity Hostname
--------------- ------ --------- ------ -------- ----------
10.0.0.133 60 Master 100 Active mysql-server
10.0.0.133 60 Origin - Active server-01
10.0.0.55 60 Backup 100 Active mysql-server
10.0.0.55 60 Origin - Active server-02

今度はserver-01がActiveになり、ENIがserver-01にアタッチされます。


最後にサーバ自体が落ちたものとして、server-01のMurakumoを落としてみます。

server-02


[root@server-02 ~]# tail /var/log/murakumo.log
I, [2012-01-22T12:36:08.879923 #13467] INFO -- : activity condition changed: mysql-server: active
I, [2012-01-22T12:36:08.995964 #13467] INFO -- : sent the notice: active
[root@server-02 ~]# ifconfig | grep ^e
eth0 Link encap:Ethernet HWaddr 02:40:B5:37:0B:C0
eth1 Link encap:Ethernet HWaddr 02:40:B5:12:49:35

しばらくするとserver-01のダウンが検知されてserver-02がActiveになり、ENIがserver-02に移ります。



…とまあこんな感じで、元々内部DNS用途だったMurakumoですが、Gossipプロトコルがなかなか便利だったので冗長化機能も持たせてみました。非VPCだとENIは使えませんが、そこは本来のDNSによる冗長化を使うということでどうせオワコンだし

Keepalivedはそもそも使えないしL7のチェックはちょっとめんどくさいし、Heartbeatはマルチキャスト使えないしヘルスチェックはやっぱりめんどいし、、、ということでミドルウェアのヘルスチェック込みで手軽にVPC冗長化したい案件にはちょうどよいと思います。

絶賛、人柱募集中 ぜひぜひご利用ください。