share facebook facebook2 twitter menu hatena pocket slack

2014.07.21 MON

pacemaker と corosync を使って複数の EIP 切り替える試み

川原 洋平

WRITTEN BY川原 洋平

cloudpack の 自称 Sensu芸人 の かっぱこと 川原 洋平@inokara)です。

はじめに

あまりニーズがあるか判りませんが pacemaker と corosync を使って複数の EIP の付け替えを試行錯誤してみたいと思います。ちなみに切り替えにあたっての条件は下記の通りです。

  • インスタンスには仮想ネットワークカードを付与して二つのプライベート IP を付与
  • プライベート IP は設定ファイル等には静的に設定を行わずインスタンス内部から取得する

尚、下記はあくまでも検証中の内容となっておりますので安定動作にはまだ試行錯誤が必要ですのでそのあたりは大目に見て頂ければ幸いです。


切り替えのイメージ

以下のようなイメージ。

01

EC2 壱号機に障害が発生したら EC2 弐号機に複数の EIP が遷移する(はず)です。


ポイント

pacemaker と corosync を使った EIP を切り替えに関しては下記のように先人の方々の努力により解決されています。

suz-lab さんや切り替えスクリプトを参考にさせて頂いている @moomindani さんに感謝です。これらの記事を参考にさせて頂きつつ、自分でも同じようにやってみたりしながら…切り替えの条件を照らしあわせた上で試行錯誤した結果、以下のような点に注意が必要なことが判りました。

  • 複数の EIP を付け替える場合にはプライベート IP と EIP を関連付けることが必要
  • 切り替えにスクリプトを使う場合にはスクリプト内でプライベート IP の取得が必要
  • その他、各種 ID の取得や排他処理的なことも必要

途端にハードルが上がって泣きそうです。ただ、プライベート IP を固定出来ればも少し簡単に出来そうな気がしてます…。

ちなみに、以下は AWS CLI を利用して EIP を割り当てる際の実行例です。(※以下の例は EC2-VPC のみ対応しております)

一つのインターフェースに一つの EIP を付ける場合

インターフェース ID と EIP の アロケーション ID が必要です。以下のように設定します。

/usr/bin/aws ec2 associate-address 
                 --allocation-id ${EIP のアロケーション ID} 
                 --network-interface-id ${インターフェース ID} 


一つのインターフェースに複数の EIP を付ける場合

インターフェース ID と EIP の アロケーション ID が必要です。さらに関連付けるプライベート IP の設定が必要です。以下のように設定します。

/usr/bin/aws ec2 associate-address 
                 --allocation-id ${EIP のアロケーション ID} 
                 --network-interface-id ${インターフェース ID} 
                 --private-ip-address ${Private IP}

上記にもあるようにプライベート IP をどのように取得するか、また、各種 ID をどのように取得するかがポイントとなりそうです。


まあ、とりあえずやってみる

やること

既に Corosync による EC2 インスタンスの HA 構成が出来ているという前提で…

  • Pacemaker の設定
  • Pacemaker が利用するスクリプトを作成と設置

pacemaker の設定

pacemaker の設定はあらかじめ以下のように設定でファイルを作成しておきます。

property 
    no-quorum-policy="ignore" 
    stonith-enabled="false" 
    crmd-transition-delay="0s"

primitive eip1 ocf:heartbeat:eip 
    params 
        elastic_ip="${EIP01}" 
        eip_if="eth1" 
    op start   timeout="60s" interval="0s"  on-fail="stop" 
    op stop    timeout="60s" interval="0s"  on-fail="block"

primitive eip2 ocf:heartbeat:eip 
    params 
        elastic_ip="${EIP02}" 
        eip_if="eth1" 
    op start   timeout="60s" interval="0s"  on-fail="stop" 
    op stop    timeout="60s" interval="0s"  on-fail="block"

group eip_groups 
    eip1 
    eip2

作成したファイルを以下のようにして読み込みます。

crm configure load update /${path}/${to}/${設定ファイル}

また、crm コマンドを利用すれば独自のコマンドラインツールで設定が可能です。

スクリプト

以下のスクリプトを fork させて頂いてこちらのように作成しました。

有難うございます。尚、拙作のこちらのスクリプトはまだエラー処理等が適切で無いのでご注意下さい。

スクリプトパス

以下のパスに切り替えスクリプトを置きます。

/usr/lib/ocf/resource.d/heartbeat/

スクリプトのデバッグ

シェル関数

以下のスクリプトをシェル関数として読み込んでおく必要があります。

/usr/lib/ocf/lib/heartbeat/ocf-shellfuncs
デバッグ時
--- /root/aws-eip-resource-agent/eip    2014-07-04 01:51:26.629662008 +0000
+++ eip 2014-07-09 01:15:14.231793442 +0000
@@ -28,8 +28,10 @@
 #######################################################################
 # Initialization:

-: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
-. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
+#: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
+#. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
+
+. /usr/lib/ocf/lib/heartbeat/ocf-shellfuncs

 #######################################################################

で、どうなの?

表現し辛い感じですが、マスターノードの Corosync を止めるとスレーブノードの IP が切り替わっている様子を…

正常な状態

通信はマスターノードで受け付けている状態。

02

マスターノードが停止した状態

マスターノードの corosync を停止した場合、IP が切り替わる間は通信が途切れしまうが数秒以内に通信が復旧する。

03

何度か試行しているとまれに切り替えに失敗してしまうことがあったり、切り替えまでに時間が掛かったりするので pacemaker の設定やスクリプトの調整が必要かなと思っています。


メモ、諸々困った時は…

必要そうなコマンド

プライベート IP を取得する

EC2 インスタンスの良いところはインスタンス内部のメタ情報を以下のように wget で取得出来ることですね。

wget -q -O - http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC_ADDRESS}/local-ipv4s

上記を実行すると ${MAC_ADDRESS} にアサインされているプライベート IP が取得されます。

172.xx.xx.xx1
172.xx.xx.xx2
EIP からプライベート IP を確認する

EIP が割り当てられているプライベート IP を確認します。

aws ec2 describe-addresses --public-ips ${EIP} --query 'Addresses[*].PrivateIpAddress' --output text

以下のように ${EIP} が付けられているプライベート IP が返ってきます。

172.xx.xx.xx1
プライベート IP が割り当てられていない EIP を確認する

ブライベート IP が割り当てられていない EIP は以下のようにして確認出来ます。

aws ec2 describe-addresses --filters "Name=domain,Values=vpc" --query 'Addresses[?PrivateIpAddress==`null`].[PublicIp]' --output text

また、?PrivateIpAddress==null の null をプライベート IP に置き換えれば該当するプライベート IP が割り当てられている EIP を取得することが可能です。

設定とかで困った場合には…

pacemaker の挙動が不安定

以下のパスに保存されているファイルをサクッと削除

/var/lib/heartbeat/crm
うっかり EC2 の PublicDNS が消えてしまったら
  1. 追加している NIC をデタッチする
  2. 追加している IP を削除する
  3. インスタンスを一旦 stop して start する(リブートではダメ)
crm コマンド
  • crm でコマンドラインツールを起動
  • configure で設定モードへ移行
  • configure モードで show を実行すると読み込まれている設定を確認することが出来る
  • configure モードで edit を実行すると読み込まれている設定を直接編集することが出来る(環境次第ですが vi がしました)
  • edit モードで編集後に設定を反映させる場合には configure モードにて commit を実行する

他にも幾つかオプションがあるので configure モードで help を実行しましょう。


引き続き

  • 切り替えのスクリプトをブラッシュアップしていきたいと思います
  • あと、プライベート IP アドレスを設定に固定した場合も試してみたいと思います(こっちはも少し楽かも)

元記事は、こちら