こんにちは。 nakadaです。
AWSで冗長化についてはELB配下にEC2を並べたり、RDSを利用したり色々なパターンがあります。
今回はpacemaker、corosyncを利用して異なるAZ間で仮想IPの設定を試してみたいと思います。 仮想IPはEIPを利用しないで、仮想プライベートアドレス?を利用した構成にします。
ただ、AWSではAZをまたいだサブネットの利用ができないので、下記のブログで紹介されているように、切替時にRoute tableを書き換える構成でいきます。
http://c9katayama.hatenablog.com/entries/2011/12/25
http://blog.suz-lab.com/2013/02/corosync-pacemakerrouting-based-ha.html
構成はこんな感じです。
AMIからサーバを作成していきます。 CentOS7を利用したいので、[AWS Marketplace]でCentOSで検索します。 今回は赤枠で囲っているAMIを使用します。
各instanceのSource/Destination CheckもDisabled にしておきます。
eth0のIPアドレスは固定で割り当てておきます。 サーバA:192.168.2.10 サーバB:192.168.3.10
selinuxは無効にして、updateしておきましょう。
# vi /etc/sysconfig/selinux SELINUX=enforcing ↓変更 SELINUX=disabled #yum update #shutdown -r now
Pacemaker corosync pcsをインストールして構成していく。
###ホスト名を確認してhostsに追加しておきます # uname -n ip-192-168-2-10.apxxx.xxxx</pre> <pre> # vi /etc/hosts ###ホスト名を追記 192.168.2.10 ip-192-168-2-10.apxxx.xxxx 192.168.3.10 ip-192-168-3-10.apxxx.xxxx #yum install -y corosync pacemaker pcs #systemctl enable pcsd.service #systemctl start pcsd.service #passwd hacluster # pcs cluster auth ip-192-168-2-10.ap-northeast-1.compute.internal ip-192-168-3-10.ap-northeast-1.compute.internal Username: hacluster Password: ip-192-168-2-10.ap-northeast-1.compute.internal: Authorized ip-192-168-3-10.ap-northeast-1.compute.internal: Authorized # pcs cluster setup --name aws-cluster ip-192-168-2-10.ap-northeast-1.compute.internal ip-192-168-3-10.ap-northeast-1.compute.internal Shutting down pacemaker/corosync services... Redirecting to /bin/systemctl stop pacemaker.service Redirecting to /bin/systemctl stop corosync.service Killing any remaining services... Removing all cluster configuration files... ip-192-168-2-10.ap-northeast-1.compute.internal: Succeeded ip-192-168-3-10.ap-northeast-1.compute.internal: Succeeded # pcs cluster start --all ip-192-168-2-10.ap-northeast-1.compute.internal: Starting Cluster... ip-192-168-3-10.ap-northeast-1.compute.internal: Starting Cluster... # pcs status Cluster name: aws-cluster WARNING: no stonith devices and stonith-enabled is not false Last updated: Tue Apr 14 09:55:45 2015 Last change: Tue Apr 14 09:55:34 2015 Stack: corosync Current DC: ip-192-168-2-10.ap-northeast-1.compute.internal (1) - partition with quorum Version: 1.1.12-a14efad 2 Nodes configured 0 Resources configured Online: [ ip-192-168-2-10.ap-northeast-1.compute.internal ip-192-168-3-10.ap-northeast-1.compute.internal ] Full list of resources: PCSD Status: ip-192-168-2-10.ap-northeast-1.compute.internal: Online ip-192-168-3-10.ap-northeast-1.compute.internal: Online Daemon Status: corosync: active/disabled pacemaker: active/disabled pcsd: active/enabled
その前にroute変更のスクリプトで使用するので、awscliをインストールしておきます。
#rpm -iUvh http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm #yum -y install python-pip #pip install awscli #aws configure ##アクセスキーなどを設定しておきます。
仮想IPアドレスを割り当てるlo:0 を作成しておきます。 書き換える対象のルートテーブルも作成します。下のスクリプトでNameをべた書きしてしまっているので、Nameを「nat」にしておきます。
Subnet Associationsで192.168.2.0/24,192.168.3.0/24を追加します。
下記のようなスクリプトを作成して、/usr/lib/ocf/resource.d/heartbeat/ route-change 保存しておきます。 下のスクリプトはインスタンスIDを取得して、それをroute tableに登録させるようにしてます。 stopすると、ルーティング設定は削除され、既に設定されている場合は上書きするようにしてます。
#!/bin/sh # # Resource Agent for managing RT resources. # meta_data() { cat <<END <?xml version="1.0"?> <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> <resource-agent name="change_route"> <version>0.1</version> <longdesc lang="en"> This is a Resource Agent for AWS EC2 Route Tables </longdesc> <shortdesc lang="en">Manage AWS EC2 Route Tables</shortdesc> <parameters> <parameter name="route_table" unique="0" required="1"> <longdesc lang="en"> Route Tables </longdesc> <shortdesc lang="en">rt</shortdesc> <content type="string"/> </parameter> <parameter name="ip" unique="1" required="1"> <longdesc lang="en"> The IPv4 example IPv4 "10.0.0.10". </longdesc> <shortdesc lang="en">IPv4</shortdesc> <content type="string" default="" /> </parameter> </parameters> <actions> <action name="start" timeout="20" /> <action name="stop" timeout="20" /> <action name="monitor" timeout="20" interval="10" depth="0" /> <action name="meta-data" timeout="5" /> <action name="validate-all" timeout="20" /> </actions> </resource-agent> END } ###### : ${OCF_FUNCTIONS_DIR=/usr/lib/ocf/resource.d/heartbeat} . ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs ##接続環境情報の指定 export AWS_CONFIG_FILE="/root/.aws/credentials" export AWS_DEFAULT_REGION=ap-northeast-1 #####AWS環境設定############# ##利用するroute tableの指定 ROUTE_TABLE_ID=`aws ec2 describe-tags --filters "Name=resource-type,Values=route-table" "Name=value,Values=nat" --query "Tags[*].[ResourceId]" --output text` ##ec2 instance idの取得 INSTANCE_ID=`curl -s http://169.254.169.254/latest/meta-data/instance-id` ############################# ###CIDER-BLOCKの指定 CIDER_BLOCK="${OCF_RESKEY_ip}/32" ###function Logger_Cmd() #/var/log/messages に指定した内容を追記する #$1 に追記する内容を記載する #example:Logger_Cmd testlog function Logger_Cmd() { logger -t `basename $0` "$1" sync;sync;sync; } #####処理内容の記載########## RT_USAGE() { echo "Usage: $0 {start|stop|monitor}" } ###route tableの確認 function AWS_ROUTE_CHECK() { aws ec2 describe-route-tables |grep -q -w ${INSTANCE_ID} case "$?" in 0) rc=${OCF_SUCSESS} ;; *) rc=${OCF_NOT_RUNNING} ;; esac return ${rc} } ###route tableの追加・書換 function AWS_ROUTE_CHANGE() { AWS_ROUTE_CHECK if [ ${rc} == 0 ];then return ${OCF_SUCSESS} else aws ec2 create-route --route-table-id ${ROUTE_TABLE_ID} --destination-cidr-block ${CIDER_BLOCK} --instance-id ${INSTANCE_ID} if [ $? == 0 ];then Logger_Cmd "create route --route-table-id ${ROUTE_TABLE_ID} --destination-cidr-block ${CIDER_BLOCK} --instance-id ${INSTANCE_ID}" return ${OCF_SUCSESS} else aws ec2 replace-route --route-table-id ${ROUTE_TABLE_ID} --destination-cidr-block ${CIDER_BLOCK} --instance-id ${INSTANCE_ID} Logger_Cmd "replace route --route-table-id ${ROUTE_TABLE_ID} --destination-cidr-block ${CIDER_BLOCK} --instance-id ${INSTANCE_ID}" return ${OCF_SUCSESS} fi fi } ###route tableの削除 function AWS_ROUTE_DELETE() { AWS_ROUTE_CHECK case "${rc}" in "${OCF_NOT_RUNNING}") Logger_Cmd "No route table or Delete route table" return ${OCF_SUCSESS} ;; "${OCF_SUCSESS}") aws ec2 delete-route --route-table-id ${ROUTE_TABLE_ID} --destination-cidr-block ${CIDER_BLOCK} if [ $? == 0 ];then Logger_Cmd "delete route --route-table-id ${ROUTE_TABLE_ID} --destination-cidr-block ${CIDER_BLOCK}" return ${OCF_SUCSESS} else Logger_Cmd "delete route-table fail" return ${OCF_ERR_GENERIC} fi ;; esac } ### function RT_VALIDATE() { return ${OCF_SUCSESS} } #### case "$1" in 'start') AWS_ROUTE_CHANGE ;; 'stop') AWS_ROUTE_DELETE ;; 'monitor') AWS_ROUTE_CHECK ;; 'validate-all') RT_VALIDATE ;; *) RT_USAGE exit ${OCF_ERR_UNIMPLEMENTED} ;; esac
リソースの設定を作成します。
# pcs cluster cib vip_change #pcs -f vip_change resource create virtual_ip ocf:heartbeat:IPaddr2 params ip=10.0.0.10 cidr_netmask=32 nic=lo:0 op monitor interval=30s #pcs -f vip_change resource create route-change ocf:heartbeat:route-change params ip=10.0.0.10 op start timeout=10s op stop timeout=10s op monitor interval=20s --force #pcs -f vip_change resource group add ip_grp virtual_ip route-change # pcs cluster cib-push vip_change CIB updated # pcs status Cluster name: aws-cluster Last updated: Mon Apr 20 10:18:44 2015 Last change: Mon Apr 20 10:18:39 2015 Stack: corosync Current DC: ip-192-168-3-10.ap-northeast-1.compute.internal (2) - partition with quorum Version: 1.1.12-a14efad 2 Nodes configured 2 Resources configured Online: [ ip-192-168-2-10.ap-northeast-1.compute.internal ip-192-168-3-10.ap-northeast-1.compute.internal ] Full list of resources: Resource Group: ip_grp virtual_ip (ocf::heartbeat:IPaddr2): Started ip-192-168-2-10.ap-northeast-1.compute.internal route-change (ocf::heartbeat:route-change): Started ip-192-168-2-10.ap-northeast-1.compute.internal PCSD Status: ip-192-168-2-10.ap-northeast-1.compute.internal: Online ip-192-168-3-10.ap-northeast-1.compute.internal: Online Daemon Status: corosync: active/disabled pacemaker: active/disabled pcsd: active/enabled</pre> <pre>
route-changeがstartedになると、10.0.0.10/32へのルーティング設定が追加されます。
待機サーバへ切り替えてみます。
# pcs cluster standby ip-192-168-2-10.ap-northeast-1.compute.internal # pcs status Cluster name: aws-cluster Last updated: Mon Apr 20 10:22:55 2015 Last change: Mon Apr 20 10:22:49 2015 Stack: corosync Current DC: ip-192-168-3-10.ap-northeast-1.compute.internal (2) - partition with quorum Version: 1.1.12-a14efad 2 Nodes configured 2 Resources configured Node ip-192-168-2-10.ap-northeast-1.compute.internal (1): standby Online: [ ip-192-168-3-10.ap-northeast-1.compute.internal ] Full list of resources: Resource Group: ip_grp virtual_ip (ocf::heartbeat:IPaddr2): Started ip-192-168-3-10.ap-northeast-1.compute.internal route-change (ocf::heartbeat:route-change): Started ip-192-168-3-10.ap-northeast-1.compute.internal PCSD Status: ip-192-168-2-10.ap-northeast-1.compute.internal: Online ip-192-168-3-10.ap-northeast-1.compute.internal: Online Daemon Status: corosync: active/disabled pacemaker: active/disabled pcsd: active/enabled
10.0.0.10/32へのルーティング設定が変更されてます。
別サーバからping してると、次のような感じになります。 切替が完了するまで、パケットロスが発生してます。
64 bytes from 10.0.0.10: icmp_seq=20 ttl=64 time=0.656 ms 64 bytes from 10.0.0.10: icmp_seq=21 ttl=64 time=0.461 ms 64 bytes from 10.0.0.10: icmp_seq=22 ttl=64 time=0.543 ms 64 bytes from 10.0.0.10: icmp_seq=24 ttl=64 time=2.36 ms 64 bytes from 10.0.0.10: icmp_seq=25 ttl=64 time=2.25 ms 64 bytes from 10.0.0.10: icmp_seq=26 ttl=64 time=2.36 ms 64 bytes from 10.0.0.10: icmp_seq=27 ttl=64 time=2.36 ms --- 10.0.0.10 ping statistics --- 27 packets transmitted, 26 received, 3% packet loss, time 26004ms rtt min/avg/max/mdev = 0.392/0.807/2.367/0.654 ms
駆け足気味になりましたが、route tableを変更することで異なるAZ間で仮想IPを設定できました。
EIPを使える環境ならEIPを使った方が楽ですね。