AWSでの冗長化② Pacamakerとcorosyncを使用したAZ間の仮想IPアドレス変更

こんにちは。
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

 

構成はこんな感じです。

aws構成

 

AMIからサーバを作成していきます。
CentOS7を利用したいので、[AWS Marketplace]でCentOSで検索します。
今回は赤枠で囲っているAMIを使用します。

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を追加します。

routetable

 

下記のようなスクリプトを作成して、/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へのルーティング設定が追加されます。

routetable02

待機サーバへ切り替えてみます。

# 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へのルーティング設定が変更されてます。

routetable03

別サーバから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を使った方が楽ですね。

 

 

 

アプリケーション開発バナー