AWS Multi-AZにおける Pacemaker + Corosync による Elastic IP の付け替え

概要

Pacemaker & Corosync による
AWS での Multi-AZ 間のEIP付け替えによる
フェイルオーバーについて実装したのでまとめます。

以下イメージです。

  • 通常状態

Normal

  • Avalavility Zone A に配置された Instance A で障害が発生した場合
    Avalavility Zone B に配置された Instance B に EIPを付け替え

Accident occured

ToDo

  • VPC, Subnet 設定
  • Pacemaker & Corosync インストール / 設定
  • Cluster 構築
  • EIP付け替えスクリプト作成
  • フェイルオーバー試験

環境

  • CentOS 7 (x86_64) with Updates HVM (t2.micro)
    ※ 検証用の為、 t2.microで実施しています。

VPC, Subnet 構築

以下記事にて非常によくまとめて頂いているので参考にしていただき
この設定を以降そのまま利用します。

0から始めるAWS入門①:VPC編

念のため、以下 VPC, Subnet 設定です。
  • VPC 設定
項目
Name tag 任意
CIDR 10.0.0.0/16
tenancy Default
  • Subnet 設定
項目 Subnet 1 Subnet 2
Name tag 任意(VPCのタグ名と関連付けたほうが管理しやすい) 任意(VPCのタグ名と関連付けたほうが管理しやすい)
VPC 上記で作成したVPCを選択する 上記で作成したVPCを選択する
Availability Zone ap-northeast-1a ap-northeast-1c
CIDR 10.0.0.0/24 10.0.1.0/24

上記VPC設定に基づき以下設定していきます。

構築するイメージは以下になります。

セキュリティグループ作成

今回作成するインスタンス2つにアタッチするセキュリティグループを事前に作成します。

マイIPからのSSHログイン許可

項目 設定値
セキュリティグループ名 VPC-for-EIP(任意)
説明 VPC-for-EIP(任意)
VPC 上記で作成したVPCを選択する

作成したセキュリティグループ編集

  • フィルターで検索

※以下は環境により変更してください。

  • 送信元を作成したグループIDとし以下追加し保存
タイプ プロトコル ポート範囲 送信元 用途
すべてのTCP TCP 0 - 65535 作成したセキュリティグループID 今回は検証用の為、全解放。適宜設定変更してください。
すべてのICMP ICMP 0 - 65535 作成したセキュリティグループID ping疎通確認用。今回は検証用の為、全解放 適宜設定変更してください。
すべてのUDP UDP 0 - 65535 作成したセキュリティグループID corosyncで必要なポートはデフォルトで 5404 - 5405。 環境により設定変更する場合は注意が必要です。今回は検証用の為、全解放。適宜設定変更してください。
SSH TCP 20 マイIP 自PC端末からSSHログイン用。実環境で設定する必要はありません。
HTTP TCP 80 マイIP FailOver検証用。実環境で設定する必要はありません。

以上でインスタンスに適用するセキュリティグループの作成が完了しました。


ポリシー作成

今回、以下コマンドを実行する必要があります。

コマンド 用途
aws ec2 associate-address ElasticIPをインスタンスに関連付ける
aws ec2 disassociate-address ElasticIPをインスタンス関連付け解除
aws ec2 describe-addresses IPアドレスについて詳細取得
Identity & Access Management ページにアクセス
「ポシリー作成」クリック
独自ポリシー作成
独自ポリシー情報入力
  • ポリシー名(任意)

floatingElasticIP

  • ポリシードキュメント
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"ec2:DisassociateAddress",
"ec2:AssociateAddress"
],
"Resource": [
"*"
]
}
]
}
確認

IAMロール作成

ElasticIPの付け替え権限を持ったロールを作成します。

新しいロールの作成 をクリック
ロール名の設定
ロールタイプの選択

Amazon EC2 の「選択」ボタンをクリック

ポリシーのアタッチ
登録内容を確認しロールの作成
作成されたか確認

以上でインスタンスに適用するIAMロールの作成が完了しました。

ユーザ作成

Identity & Access Management ページにアクセス
メニューからユーザクリック & 新規ユーザの作成 ボタンクリック
ユーザ名入力し作成ボタンクリック
認証情報をダウンロードクリック

Access Key IdSecret Access Key が記載されたCSVがダウンロードされます。
大切に保管しましょう。

作成されたユーザーにアクセス
ポリシーのアタッチ開始
ポリシーにチェックを入れアタッチ

以上で
AmazonEC2FullAccess 権限を持ったユーザ floatingIP ユーザが作成されました。

上記ユーザの認証情報は 手順 aws-cli インストール で利用します。


インスタンスの作成

  • 上記で作成したVPCのSubnet (ap-northeast-1a)にインスタンス (以降Instance A)を作成します。

「インスタンスの作成」をクリック

マシンイメージ選択

今回は CentOS 7 (x86_64) with Updates HVM を選択します。

インスタンスタイプ選択

今回は検証用で無料枠として利用したいので t2.micro を選択します。

インスタンスの詳細の設定

ap-northeast-1a に作成する Instance A のプライマリIPを
10.0.0.20 とします。

ストレージの追加

特に変更することなく次の手順へ

インスタンスのタグ付け

Name タグに Instance A と指定します。
※ 任意なのでわかりやすいテキストであれば良いです。

セキュリティグループの設定

  • 事前に作成したセキュリティグループを選択

インスタンス作成の確認

以上で Insntace A の作成が完了しました。

同様に Instance B 作成

Instance A との主な変更点
  • Subnet 10.0.1.0/24 を選択
  • インスタンスのタグは Instance B とする
Instance B 設定時注意点
  • セキュリティグループInstance B でも同様 Instance A で設定した
    セキュリティグループ を選択する。

送信元/送信先の変更チェックを無効化

※上記 Instance A, B 共に Source/Destination Check (ネットワーク > 送信元/送信先の変更チェック) を Disabled (無効) に設定する必要があります。

インスタンス SSHログイン後まずやること

最低限必要なモジュールインストール

※ git は ElasticIP付け替え時のシェルをインストールする際に必要になります。

1
2
3
4
5
[Instance A & B ]# yum install -y git

[Instance A & B ]# git --version

git version 1.8.3.1

Fail Over 検証用に httpd, php インストール

あくまで Fail Over 時の動きを見る為の確認用にインストールし起動しています。
※必須工程ではありません。

1
2
3
4
5
6
[Instance A & B ]# yum --disableexcludes=main install -y gcc
[Instance A & B ]# yum install -y gmp gmp-devel
[Instance A & B ]# yum install -y php php-mysql httpd libxml2-devel net-snmp net-snmp-devel curl-devel gettext
[Instance A & B ]# echo '<?php print_r($_SERVER["SERVER_ADDR"]); ?>' > /var/www/html/index.php
[Instance A & B ]# systemctl start httpd
[Instance A & B ]# systemctl enable httpd

system clock 調整 JST設定

OS内の時間が現実の時間とずれていると
aws-cliが正常に動作しない可能性があるので
念の為、調整しておきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
# バックアップ確保
[Instance A & B ]# cp /etc/sysconfig/clock /etc/sysconfig/clock.org

# 再起動しても設定維持する様にする。
[Instance A & B ]# echo -e 'ZONE="Asia/Tokyo"\nUTC=false' > /etc/sysconfig/clock

# バックアップ確保
[Instance A & B ]# cp /etc/localtime /etc/localtime.org

# Asia/Tokyo を localtime に設定
[Instance A & B ]# ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

[Instance A & B ]# date

Elastic IP作成

Elastic IPを作成し Server A に関連付けます。

新しいアドレスを割り当てる
確認ポップアップで「関連付ける」をクリック
成功確認
インスタンスに関連付け
関連するインスタンス選択
確認

以上で Instance A に ElasticIP が関連付けされました。

Instance A & B に SSHログイン

  • Instance A に SSHログイン

    1
    [Local PC]# ssh -i aws.pem centos@<Instance AのPublic IP>
  • Instance B に SSHログイン

    1
    [Local PC]# ssh -i aws.pem centos@<Instance BのPublic IP>

/etc/hosts設定

1
2
[Instance A ]# uname -n
ip-10-0-0-10.ap-northeast-1.compute.internal
1
2
[Instance B ]# uname -n
ip-10-0-1-10.ap-northeast-1.compute.internal
1
2
3
4
5
6
7
[Instance A & B ]# vi /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6

# 以下追加
10.0.0.20 ip-10-0-0-20.ap-northeast-1.compute.internal
10.0.1.20 ip-10-0-1-20.ap-northeast-1.compute.internal

Pacemaker & Corosync インストール

  • pcsは旧来のcrmshに代わるPacemakerクラスタ管理ツールであり、RHEL/CentOS7においてはpcsの使用が推奨されている。
1
[Instance A & B ]# yum -y install pcs fence-agents-all
  • バージョン確認
1
2
3
4
5
6
7
8
9
10
[Instance A & B ]# pcs --version
0.9.143

[Instance A & B ]# pacemakerd --version
Pacemaker 1.1.13-10.el7
Written by Andrew Beekhof

[Instance A & B ]# corosync -v
Corosync Cluster Engine, version '2.3.4'
Copyright (c) 2006-2009 Red Hat, Inc.

hacluster パスワード設定

corosyncパッケージインストール時に自動で hacluster ユーザが追加される。
その hacluster のパスワードを設定する。

1
2
3
4
5
[Instance A & B ]# passwd hacluster
ユーザー hacluster のパスワードを変更。
新しいパスワード:
新しいパスワードを再入力してください:
passwd: すべての認証トークンが正しく更新できました。

pcsd 起動

cluster監視を実施する為

1
2
3
[Instance A & B ]# systemctl start pcsd
[Instance A & B ]# systemctl enable pcsd
[Instance A & B ]# systemctl status pcsd

cluster認証

クラスタを組む各ホストへのアクセス認証を検証します。

どちらか一方のInstanceから実行します。
以下はInstance Aから実行しています。

1
2
3
4
5
[Instance A ]# pcs cluster auth ip-10-0-0-20.ap-northeast-1.compute.internal ip-10-0-1-20.ap-northeast-1.compute.internal
Username: hacluster
Password:
ip-10-0-1-20.ap-northeast-1.compute.internal: Authorized
ip-10-0-0-20.ap-northeast-1.compute.internal: Authorized

上記のように Authorized (認証済み) と出力されていれば問題ありませんが
以下のような Unable to Communicate というエラーが出力されている場合は
各Instance の設定を見直してください。

  • 認証エラーの例
    1
    2
    3
    [Instance A ]# pcs cluster auth ip-10-0-0-20.ap-northeast-1.compute.internal ip-10-0-1-20.ap-northeast-1.compute.internal -u hacluster -p ruby2015
    Error: Unable to communicate with ip-10-0-0-20.ap-northeast-1.compute.internal
    Error: Unable to communicate with ip-10-0-1-20.ap-northeast-1.compute.internal

cluster設定

クラスタ設定をします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Instance A ]# pcs cluster setup --name aws-cluster ip-10-0-0-20.ap-northeast-1.compute.internal ip-10-0-1-20.ap-northeast-1.compute.internal --force

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-10-0-0-20.ap-northeast-1.compute.internal: Succeeded
ip-10-0-1-20.ap-northeast-1.compute.internal: Succeeded
Synchronizing pcsd certificates on nodes ip-10-0-0-20.ap-northeast-1.compute.internal, ip-10-0-1-20.ap-northeast-1.compute.internal...
ip-10-0-0-20.ap-northeast-1.compute.internal: Success
ip-10-0-1-20.ap-northeast-1.compute.internal: Success

Restaring pcsd on the nodes in order to reload the certificates...
ip-10-0-0-20.ap-northeast-1.compute.internal: Success
ip-10-0-1-20.ap-northeast-1.compute.internal: Success

cluster起動

全ホストに向け クラスタ起動します。

1
2
3
4
[Instance A ]# pcs cluster start --all

ip-10-0-1-20.ap-northeast-1.compute.internal: Starting Cluster...
ip-10-0-0-20.ap-northeast-1.compute.internal: Starting Cluster...

aws-cli インストール

手順: ユーザ作成 でダウンロードした credentials.csv に記載された
Access Key Id Secret Access Key を使用します。

1
2
3
4
5
6
7
8
9
10
11
[Instance A & B ]# rpm -iUvh http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
[Instance A & B ]# yum -y install python-pip
[Instance A & B ]# pip --version
pip 7.1.0 from /usr/lib/python2.7/site-packages (python 2.7)

[Instance A & B ]# pip install awscli
[Instance A & B ]# aws configure
AWS Access Key ID [None]: *********************
AWS Secret Access Key [None]: **************************************
Default region name [None]: ap-northeast-1
Default output format [None]: json

EIP 付け替えリソース作成

heartbeat で問題検知した際に起動するリソースとして登録します。

OCF_ROOT が定数として指定されているが、存在しない為

1
2
3
4
5
6
7
[Instance A & B ]# cd /tmp
[Instance A & B ]# git clone https://github.com/moomindani/aws-eip-resource-agent.git
[Instance A & B ]# cd aws-eip-resource-agent
[Instance A & B ]# sed -i 's/\${OCF_ROOT}/\/usr\/lib\/ocf/' eip
[Instance A & B ]# mv eip /usr/lib/ocf/resource.d/heartbeat/
[Instance A & B ]# chown root:root /usr/lib/ocf/resource.d/heartbeat/eip
[Instance A & B ]# chmod 0755 /usr/lib/ocf/resource.d/heartbeat/eip

pacemaker 設定

stonish 無効化
1
[Instance A ]# pcs property set stonith-enabled=false
split-brain (スプリット・ブレイン) が発生しても quorum (クォーラム) が特別な動作を行わないように設定
1
[Instance A ]# pcs property set no-quorum-policy=ignore

split-brain とは
ハートビート通信を行うネットワークに断線などの問題が発生した場合、ホストに障害が起こったと勘違いし、
本来立ち上がってほしくないスタンバイ側のホストがアクティブになってしまうというもの

属性値更新時の待ち時間( crmd-transition-delay )を 0s(秒) 設定
1
[Instance A ]# pcs property set crmd-transition-delay="0s"
自動フェイルバックなし、同一サーバでリソースの再起動を試みる回数を 1 回に設定
1
[Instance A ]# pcs resource defaults resource-stickiness="INFINITY" migration-threshold="1"
EIP切り替え設定

今回作成し Instance A に関連付けした ElasticIP は 52.192.203.215 です。
以下設定に反映させます。

1
2
3
4
5
6
[Instance A ]# pcs resource create eip ocf:heartbeat:eip \
params \
elastic_ip="52.192.203.215" \
op start timeout="60s" interval="0s" on-fail="stop" \
op monitor timeout="60s" interval="10s" on-fail="restart" \
op stop timeout="60s" interval="0s" on-fail="block"

cluster 設定確認

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
[Instance A ]# pcs config

pcs config
Cluster Name: aws-cluster
Corosync Nodes:
ip-10-0-0-20.ap-northeast-1.compute.internal ip-10-0-1-20.ap-northeast-1.compute.internal
Pacemaker Nodes:
ip-10-0-0-20.ap-northeast-1.compute.internal ip-10-0-1-20.ap-northeast-1.compute.internal

Resources:
Resource: eip (class=ocf provider=heartbeat type=eip)
Attributes: elastic_ip=52.192.203.215
Operations: start interval=0s timeout=60s on-fail=stop (eip-start-interval-0s)
monitor interval=10s timeout=60s on-fail=restart (eip-monitor-interval-10s)
stop interval=0s timeout=60s on-fail=block (eip-stop-interval-0s)

Stonith Devices:
Fencing Levels:

Location Constraints:
Ordering Constraints:
Colocation Constraints:

Resources Defaults:
resource-stickiness: INFINITY
migration-threshold: 1
Operations Defaults:
No defaults set

Cluster Properties:
cluster-infrastructure: corosync
cluster-name: aws-cluster
crmd-transition-delay: 0s
dc-version: 1.1.13-10.el7-44eb2dd
have-watchdog: false
no-quorum-policy: ignore
stonith-enabled: false

Fail Over 実行確認

手順 Fail Over 検証用に httpd, php インストール にて
DocumentRoot (/var/www/html/) に
Private IP ($_SERVER["SERVER_ADDR"]) を表示させるindex.phpファイルを
配置しました。

ブラウザから Private IP を元に Instance A or B どちらのInstance に
アクセスしているかがわかります。

ブラウザから ElasticIP にアクセス

ElasticIP 52.192.203.215 にアクセスすると
Private IP 10.0.0.20 が表示されていることがわかります。

現状、ElasticIP は Instance A に関連付いていることがわかります。

Instance A の corosync 停止
1
[Instance A]# systemctl stop corosync
再度ブラウザから ElasticIP にアクセス

先ほど表示させていたブラウザを幾度かリロードすると
Private IP 10.0.1.20 が表示されていることがわかります。

ElasticIP は Instance B に関連付けられたことがわかります。

ElasticIP が Instance A から関連付けが解放され、 Instance B に関連付けされるようになりました。

コンソールページ上でも確認することができます。

以上で簡易的ではありますが
Cloud Design Pattern の floating IP (ElasticIP) が実現できました。

以上です。

参考