unicast対応でよみがえる keepalived on VPC-EC2
AWSを始め、ほとんどのパブリッククラウドはmulticastが出来なくて不便。と言われてきましたが、だったらunicastでやってしまえば良い!という考え方が 2013年頃すでにありました。なぜmulticastをやりたいの?と言うと そうだね!、LVS + keepalived
だね! (あとはゴシッププロトコル) これまた2年前に EC2 + LVM (DSR) を実践してみたという素敵な解説があり、パッチを当てればいける
ということは知ってたけど、月日がながれて 今日keepalivedの総本山を見てみたら
http://www.keepalived.org/changelog.html
Release 1.2.8 ぐらいからunicast対応してますね。というか、今更開発が活発になってきたのか?これは。というわけで、最新版の 1.2.19を使ってみます。
予備知識
EC2でmulticast でググると日本語を含めて結構な情報が得られます。混乱しないよう先に言うと、keepalivedのVRRPだけ
に限ると、パケットキャプチャ
やらtc
やらで自前実装して、事前準備するということは不要です。keepalivedがVRRPをunicastで実現してくれます
上記でもちらっと匂わせていた話ですが、
www.slideshare.net
は、汎用的な話
です。つまり素直にmulticast/broadcastをエミュレーションしようということです。
www.slideshare.net
は、keepalived固有の話
です。ていうか手順。keepalived側ですでにVRRP via unicastを実現しているので、パケットを覗いてMACアドレス分コピーして再送とかを自前で実装する必要はないです。
構成
LVS * 2 で VRRP冗長
Web * 2
動作確認用 Client
というこれまたパクリ構成です。
- LVSの2つはお互いにVRRPで生きていることを広告します(正確にはVRRPで投げるのはMasterのみ、死亡を確認するとBackupが昇格)。重要な要素はVIP(フローティングIP)の存在です。このVIPを2台のうちどちらが持つかを決定します。
- さらにこのVIPは EIP/ENIとは違います。この方法はEIP/ENIのインスタンスへの付替えは発生しません。大事なことなので2度言いますEIP/ENIの付替えは行いません。 しかし、ルートテーブルのみ書換は行います。詳細は後述。
- VIPという(VPCから見ると)異物で一旦リクエストを受けるので、Src/Destのチェック無効化がLVS側にも必要です。
- Webサーバの死活監視もLVS(keepalived)で行います。
Webサーバ側は、DSRに備えて Src/Dest のチェック無効化と VIP宛のパケットを、自分宛てとみなして受け取る設定が必要です。これも後述。
keepalivedの実装
上記より、インストールさえ済めば、keepalived.confの設定のみで、VRRPの部分は終わりです。そのたDSRを実現する部分やらは Sugawara氏のスライド丸パクリです。
インストール
RPMを作りました、AmazonLinux用のみです。気が向いたらCentOS用も作ります。
http://bit.ly/1OZfBtE
でもSRPMがあれば簡単なので、自力でなんとかなると思います。keepalivedぐらいでしたら、素直にソースビルドでもよいかと。
keepalived.conf
Sugawara氏のスライドと違うところは
vrrp_unicast_bind => unicast_src_ip vrrp_unicast_peer => unicast_peer { xxx } 配列になった!
ぐらいです。
!Configuration File for keepalived global_defs { router_id LVS_DEVEL } vrrp_instance VI_1 { state BACKUP # or MASTER interface eth0 virtual_router_id 51 priority 100 # MASTERは 101 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.20.11 } unicast_src_ip 172.31.18.163 unicast_peer { 172.31.18.164 } notify_master "/etc/keepalived/notify_master.sh" } virtual_server_group VSG_1 { 192.168.20.11 80 } virtual_server group VSG_1 { delay_loop 6 lb_algo rr lb_kind DR protocol TCP real_server 172.31.8.1 80 { weight 1 HTTP_GET { url { path / } } } ... }
切替時に走る スクリプト notify_master.sh EC2-Roleでやったので、credentialのベタ書きはやめました。ここはおこのみで。
#!/bin/bash VIP=192.168.20.11 ROUTE_TABLE_ID=rtb-[your routetable's id] INSTANCE_ID=`curl -s 169.254.169.254/latest/meta-data/instance-id` #export AWS_ACCESS_KEY_ID=... #export AWS_SECRET_ACCESS_KEY=... #export AWS_DEFAULT_REGION=ap-northeast-1 aws --region ap-northeast-1 ec2 delete-route --destination-cidr-block $VIP/32 --route-table-id $ROUTE_TABLE_ID aws --region ap-northeast-1 ec2 create-route --destination-cidr-block $VIP/32 --route-table-id $ROUTE_TABLE_ID --instance-id $INSTANCE_ID
VRRP動作確認
tcpdum -n vrrp
を叩いて、multicast用IPアドレスが出ず、上記で指定したローカルIPアドレスが出ていればOK。他にも
ip a
を叩いて VIPをeth0が持っていないことを確認します。2台ともVIPを持っていたら、スプリットブレイン状態です。多分設定ファイルかSG設定が間違っています
VIPの切り替わりとRouteTable
結構複雑な話が混ざっているので、1つずつひも解きます。
- VIPのこだわり
VIPは必ずVPCのCIDRから外れたもの
を指定します。後で意味が分かります。 具体的にはクラスAを割り当てていれば 172.16.xxx.xxx とか 192.168.xxx.xxx クラスの違うローカルIPを当てるのが良いです。 - RouteTableが必要な理由
VIPの面倒はVRRPが見てくれるなら、RouteTableなんか要らないんじゃないか?それにVIPもVPC(Subnet)内の空いてるIPさせば良いんじゃね?と思いますが、それは出来ないです。
VPC内はそもそもブロードキャストが通りません、よって、MACアドレスの割り出しのためにARPを打っているわけではないのです。これにより、このVIPがわかっていてもそこに至る経路が分かりません。それをRouteTableで何とかします。 - RouteTableのルール
RouteTableで宛先を指定できるならば、VPCのCIDR内のIPでも良いんじゃね?と思いますが、これはやりたくても出来ません。実際にやればわかりますが、エラーが出ます。よって、VPCのCIDR外の適当なIPアドレスをVIPとして、これをRouteTableの経路とします。 - notify_master.shスクリプトがやること
VIPの割当はkeepalivedが勝手にやりますので、経路の変更のみです。ルートテーブルで、VIPへ向き先をMasterとなった自分(インスタンスID > ENI)に向けます。
バックエンドのWebサーバ側の設定
DSRで動かすことを意識した設定が必要です。
- Src/Destのチェックを無効にする
- iptables で VIP宛のパケットを自分宛てにする
点を注意
iptables
iptables -t nat -A PREROUTEING -d 192.168.20.11 -j REDIRECT
動作と解説
上手く動いていると、Clientマシンから curl 192.168.20.11
が正常に動作するはずです。この構成でできることを後述します。
どこでAZをまたいでも問題ない
- Client - LVS(Master)間のAZ跨ぎ
VIPへのアクセス経路はRouteTableに制御されています。よって、NATインスタンスと同じような感覚で使えます。 - LVS間のAZ跨ぎ
結局ただのunicastでVRRPを投げるので、AZを跨いでも全く問題ありません。keepalivedのVRRPについては万事OK。 - バックエンドサーバ - LVSのAZ跨ぎ
問題ないのはわかると思いますが、Client(A) - LVS(C) - Server(A) と最悪の場合でも、DSRでいけるので、コネクション確立後は Client - Server の AZ-A内で通信ができるはずです。
まとめ
- keepalivedの開発がなんか活性化してて、VRRP via unicastに対応。これにより keepalived = multicast必須でなくなった
- VIPの付替えはkeepalivedがやってくれるけど、RouteTableの書き換えはAWS CLIでやる必要あり。EIP/ENI付替えよりはスマートだと思う。
- AZ跨ぎも問題ない。
multicastについて
結局multicast関係無くなってしまいましたが、色々ためしてみました。
まだ途中ではありますが、パケットをキャプチャし、MACアドレス分コピー送信という方法はあまり上手くいっていないです。(私のテストが間違っているだけかもしれませんが)
別解として、GREトンネルを張る方法も下記にドキュメントがあります。いずれ試してみようと思っています。
Overlay Multicast in Amazon Virtual Private Cloud : Articles & Tutorials : Amazon Web Services