SerfでCDP実装 ~ HA-NAT編|アドカレ2013 : CFn #11

2013.12.11

こんにちは。望月です。
このエントリは、CDP Advent Calendar 11日目 および Classmethod CloudFormation Advent Calendar #11 となっております。

CDP Advent Calendarの前日は、@oko_changさんのCustomize Scaling Metrics Pattern
CloudFomration Advent Calendarの前日は、あけりさんの えっ? ElasticSearchってAWSのサービスじゃなかったんですか!?|アドカレ2013 : CFn #10でした。

CDPアドベントカレンダーに参加することになった

昨日、SAP Japan株式会社様の会場にて、弊社AWSチーム主催の勉強会が開催されました。そちらの詳しい様子は【AWS勉強会】CM re:Growth Developers.IO Meetup 01 を開催してきた #cmdevioを御覧ください。
その中で、CloudFormationとSerfで作る全自動インフラというタイトルで発表させて頂きました。

上記の発表をしたところ、勉強会に参加して頂いていた@maroon1stさんに声をかけていただき、CDP Advent Calendarにも参加させていただくこととなりました。

High Availability NATパターン

High Availability NAT(以下HA-NAT)は、CDP(Cloud Design Pattern)の一つです。

この実装には様々な方法があります。corosync + pacemakerやkeepalivedなどで死活監視を行い、どちらかに異常が発生した際にProtected SubnetのRoute Tableを書き換えます。

今回はSerfを使ってHA-NATを実装してみました。Serfについての簡単な説明は以前私が書いたブログを御覧ください。

さっそくデモ版を起動してみましょう!

HA-NATでは、NATインスタンスからRouteTableを書き換えるため、その権限を持ったIAM Roleを割り当てる必要があります。
このテンプレートではPowerUserRoleを作成しています。

パラメータ名 入力 デフォルト
AccessFromCIDR SSH接続の接続元CIDR 0.0.0.0/0
AZ1 利用するAZ ap-northeast-1a
AZ2 利用するAZ ap-northeast-1c
KeyName SSH KeyPairの名前 -

HA NATのデモを起動

実装

Serfの設定ファイルは/etc/serf.confとしました。わずか5行です!(jsonなので1行でもかけますw)

{
  "role" : "nat-i-6de81d6a",
  "event_handlers" : [
    "member-failed,member-leave=/opt/serf/ha-nat.sh >> /var/log/serf-event.log 2>&1"
  ]
}

member-failed, member-leaveが発生した際に、Route Tableを書き換えるシェルスクリプト/opt/serf/ha-nat.shが実行されるという仕組みです。member-failedが発生した時には、そのインスタンスのロールが標準入力から渡ってくるので、それを利用してスクリプトを実行します。
シェルスクリプトの内容は以下の通りです。冒頭のインスタンスID取得の部分はSerfに特化したものですが、それ以外の部分はSerf以外でHA−NATを実装する際にも使えると思います。

#!/bin/bash

export AWS_DEFAULT_REGION=ap-northeast-1

# role format : nat-{instanceid}
while read hostname ip role
do
  peerinstanceid=$(echo ${role} | sed -e 's/nat-//')
done
myinstanceid=$(curl http://169.254.169.254/latest/meta-data/instance-id)

routetableid=$(aws ec2 describe-route-tables | jq -r '.RouteTables[] | select(.Routes[].InstanceId == "'${peerinstanceid}'") | .RouteTableId')

if [ -z "${routetableid}" ]; then
    echo 'no failover executed'
    exit 0
fi

aws ec2 delete-route --route-table-id ${routetableid} --destination-cidr-block 0.0.0.0/0
aws ec2 create-route --route-table-id ${routetableid} --destination-cidr-block 0.0.0.0/0 --instance-id ${myinstanceid}

実践編

さて、実践編では既存のVPCにHA-NATを組み込みます。

このテンプレートは、既存のVPCのルーティングを書き換えます。取り扱いには十分注意してください。

パラメータ名 入力 デフォルト
AccessFromCIDR SSH接続の接続元CIDR 0.0.0.0/0
VpcId VPCのID -
VPCCidr VPCのCIDRアドレス -
KeyName SSH KeyPairの名前 -
PublicSubnet1 1つ目のNATインスタンスのサブネットID -
PublicSubnet2 2つ目のNATインスタンスのサブネットID -
ProtectedRouteTable ProtectedRouteTableのID -

HA-NATを起動

まとめ

前回の記事ではSerfの紹介だけでしたが、少し実践的な使い方ができたかと思います。この他にも色々なCDPに応用できると思いますので、是非皆さんで使っていきましょう!

明日の記事にもご期待ください!最後に一つ。
CDP Advent Calendarは明日(以降)書いてくれる方を絶賛募集中です!