前書き
高可用性はシステム設計の機能であり、障害が発生した場合にアプリケーションが自動的に再起動するか、作業を別の対応システムに再ルーティングできるようにします。 サーバーに関しては、可用性の高いシステムをセットアップするために必要なテクノロジーがいくつかあります。 作業をリダイレクトできるコンポーネントが必要です。また、障害を監視し、中断が検出された場合にシステムを移行するメカニズムが必要です。
keepalived
デーモンを使用して、サービスまたはシステムを監視し、問題が発生した場合にスタンバイに自動的にフェイルオーバーすることができます。 このガイドでは、keepalived
を使用して高可用性Webサービスをセットアップする方法を示します。 2つの対応するWebサーバー間で移動できるfloating IP addressを構成します。 プライマリサーバーがダウンした場合、フローティングIPは自動的に2番目のサーバーに移動され、サービスを再開できます。
前提条件
このガイドを完了するには、DigitalOceanアカウントに2つのUbuntu 14.04サーバーを作成する必要があります。 両方のサーバーは同じデータセンター内に配置する必要があり、プライベートネットワーキングを有効にする必要があります。
これらの各サーバーでは、sudo
アクセスで構成されたroot以外のユーザーが必要になります。 これらのユーザーを設定する方法については、Ubuntu 14.04 initial server setup guideをフォローしてください。
開始する準備ができたら、root以外のユーザーで両方のサーバーにログインします。
Nginxのインストールと構成
keepalived
はロードバランサーの監視とフェイルオーバーによく使用されますが、運用の複雑さを軽減するために、このガイドではNginxを単純なWebサーバーとして使用します。
各サーバーのローカルパッケージインデックスを更新することから始めます。 その後、Nginxをインストールできます。
sudo apt-get update
sudo apt-get install nginx
ほとんどの場合、可用性の高いセットアップでは、両方のサーバーでまったく同じコンテンツを提供する必要があります。 ただし、わかりやすくするために、このガイドではNginxを使用して、2つのサーバーのどちらがいつでもリクエストを処理していることを示します。 これを行うには、各ホストのデフォルトのindex.html
ページを変更します。 今すぐファイルを開きます。
sudo nano /usr/share/nginx/html/index.html
最初のサーバーで、ファイルの内容を次のものに置き換えます。
プライマリサーバーの/usr/share/nginx/html/index.html
Primary
2番目のサーバーで、ファイルの内容を次のように置き換えます。
セカンダリサーバーの/usr/share/nginx/html/index.html
Secondary
完了したら、ファイルを保存して閉じます。
Keepalivedのビルドとインストール
次に、サーバーにkeepalived
デーモンをインストールします。 Ubuntuのデフォルトリポジトリにはkeepalived
のバージョンがありますが、それは古く、構成が機能しないいくつかのバグがあります。 代わりに、ソースから最新バージョンのkeepalived
をインストールします。
開始する前に、ソフトウェアのビルドに必要な依存関係を取得する必要があります。 build-essential
メタパッケージは必要なコンパイルツールを提供し、libssl-dev
パッケージにはkeepalived
が構築する必要のあるSSLライブラリが含まれています。
sudo apt-get install build-essential libssl-dev
依存関係が設定されたら、keepalived
のtarballをダウンロードできます。 this pageにアクセスして、ソフトウェアの最新バージョンを見つけてください。 最新バージョンを右クリックして、リンクアドレスをコピーします。 サーバーに戻り、ホームディレクトリに移動し、wget
を使用してコピーしたリンクを取得します。
cd ~
wget http://www.keepalived.org/software/keepalived-1.2.19.tar.gz
tar
コマンドを使用してアーカイブを展開し、結果のディレクトリに移動します。
tar xzvf keepalived*
cd keepalived*
次を入力して、デーモンをビルドおよびインストールします。
./configure
make
sudo make install
これでデーモンがシステムにインストールされました。
Keepalived Upstartスクリプトを作成する
keepalived
のインストールにより、すべてのバイナリとサポートファイルがシステム上の所定の場所に移動しました。 ただし、Ubuntu 14.04システム用のUpstartスクリプトは含まれていませんでした。
keepalived
サービスを処理できる非常に単純なUpstartスクリプトを作成できます。 開始するには、/etc/init
ディレクトリ内のkeepalived.conf
というファイルを開きます。
sudo nano /etc/init/keepalived.conf
内部では、keepalived
が提供する機能の簡単な説明から始めることができます。 含まれているman
ページの説明を使用します。 次に、サービスを開始および停止するランレベルを指定します。 このサービスは、すべての通常の状態(ランレベル2〜5)でアクティブになり、他のすべてのランレベル(たとえば、再起動、電源オフ、シングルユーザーモードが開始されたとき)で停止します。
/etc/init/keepalived.conf
description "load-balancing and high-availability service"
start on runlevel [2345]
stop on runlevel [!2345]
このサービスはWebサービスを引き続き利用できるようにするために不可欠なので、障害が発生した場合にこのサービスを再起動する必要があります。 次に、サービスを開始する実際のexec
行を指定できます。 Upstartがpid
を正しく追跡できるように、--dont-fork
オプションを追加する必要があります。
/etc/init/keepalived.conf
description "load-balancing and high-availability service"
start on runlevel [2345]
stop on runlevel [!2345]
respawn
exec /usr/local/sbin/keepalived --dont-fork
完了したら、ファイルを保存して閉じます。
Keepalived構成ファイルを作成する
Upstartファイルを配置したら、keepalived
の構成に進むことができます。
サービスは、/etc/keepalived
ディレクトリで構成ファイルを探します。 両方のサーバーでそのディレクトリを作成します。
sudo mkdir -p /etc/keepalived
サーバーのプライベートIPアドレスを収集する
構成ファイルを作成する前に、両方のサーバーのプライベートIPアドレスを見つける必要があります。 DigitalOceanサーバーでは、次のように入力して、メタデータサービスからプライベートIPアドレスを取得できます。
curl http://169.254.169.254/metadata/v1/interfaces/private/0/ipv4/address && echo
Output10.132.7.107
これは、iproute2
ツールで次のように入力することでも確認できます。
ip -4 addr show dev eth1
探している値は次のとおりです。
Output3: eth1: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 10.132.7.107/16 brd 10.132.255.255 scope global eth1
valid_lft forever preferred_lft forever
両方のシステムからこの値をコピーします。 以下の構成ファイル内でこれらのアドレスを参照する必要があります。
プライマリサーバーの構成の作成
次に、プライマリサーバーで、メインのkeepalived
構成ファイルを作成します。 デーモンは、/etc/keepalived
ディレクトリ内でkeepalived.conf
というファイルを探します。
sudo nano /etc/keepalived/keepalived.conf
内部では、vrrp_script
ブロックを開いて、Nginxサービスのヘルスチェックを定義することから始めます。 これにより、keepalived
がWebサーバーの障害を監視できるようになり、プロセスがダウンしていることを通知して、対策の回復を開始できます。
チェックは非常に簡単です。 2秒ごとに、nginx
というプロセスがまだpid
を要求していることを確認します。
プライマリサーバーの/etc/keepalived/keepalived.conf
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
次に、vrrp_instance
というブロックを開きます。 これは、keepalived
が高可用性を実装する方法を定義する主要な構成セクションです。
まず、keepalived
に、プライベートインターフェイスであるeth1
を介してピアと通信するように指示します。 プライマリサーバーを構成しているので、state
構成を「MASTER」に設定します。 これは、デーモンがピアに接続して選択を行うことができるまで、keepalived
が使用する初期値です。
選出中、priority
オプションを使用して、選出されるメンバーを決定します。 決定は、どのサーバーがこの設定の最大数を持っているかに基づいています。 プライマリサーバーには「200」を使用します。
プライマリサーバーの/etc/keepalived/keepalived.conf
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
vrrp_instance VI_1 {
interface eth1
state MASTER
priority 200
}
次に、両方のノードで共有されるこのクラスターグループにIDを割り当てます。 この例では「33」を使用します。 unicast_src_ip
を、前に取得したprimaryサーバーのプライベートIPアドレスに設定する必要があります。 unicast_peer
をsecondaryサーバーのプライベートIPアドレスに設定します。
プライマリサーバーの/etc/keepalived/keepalived.conf
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
vrrp_instance VI_1 {
interface eth1
state MASTER
priority 200
virtual_router_id 33
unicast_src_ip primary_private_IP
unicast_peer {
secondary_private_IP
}
}
次に、keepalived
デーモンが相互に通信するための簡単な認証を設定できます。 これは、問題のサーバーが正当であることを確認するための基本的な手段にすぎません。 authentication
サブブロックを作成します。 内部で、auth_type
を設定してパスワード認証を指定します。 auth_pass
パラメータには、両方のノードで使用される共有シークレットを設定します。 残念ながら、重要なのは最初の8文字のみです。
プライマリサーバーの/etc/keepalived/keepalived.conf
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
vrrp_instance VI_1 {
interface eth1
state MASTER
priority 200
virtual_router_id 33
unicast_src_ip primary_private_IP
unicast_peer {
secondary_private_IP
}
authentication {
auth_type PASS
auth_pass password
}
}
次に、ファイルの先頭に作成したchk_nginx
というラベルの付いたルーチンを使用して、ローカルシステムの状態を判断するようにkeepalived
に指示します。 最後に、このノードがペアの「マスター」になるたびに実行されるnotify_master
スクリプトを設定します。 このスクリプトは、フローティングIPアドレスの再割り当てをトリガーします。 このスクリプトを一時的に作成します。
プライマリサーバーの/etc/keepalived/keepalived.conf
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
vrrp_instance VI_1 {
interface eth1
state MASTER
priority 200
virtual_router_id 33
unicast_src_ip primary_private_IP
unicast_peer {
secondary_private_IP
}
authentication {
auth_type PASS
auth_pass password
}
track_script {
chk_nginx
}
notify_master /etc/keepalived/master.sh
}
上記の情報を設定したら、ファイルを保存して閉じます。
セカンダリサーバーの構成の作成
次に、セカンダリサーバーでコンパニオンスクリプトを作成します。 セカンダリサーバーの/etc/keepalived/keepalived.conf
でファイルを開きます。
sudo nano /etc/keepalived/keepalived.conf
内部では、使用するスクリプトは主サーバーのスクリプトとほぼ同等です。 変更する必要がある項目は次のとおりです。
-
state
:選択が行われる前にノードがバックアップ状態に初期化されるように、これをセカンダリサーバーで「BACKUP」に変更する必要があります。 -
priority
:これはプライマリサーバーよりも低い値に設定する必要があります。 このガイドでは、値「100」を使用します。 -
unicast_src_ip
:これはsecondaryサーバーのプライベートIPアドレスである必要があります。 -
unicast_peer
:これにはprimaryサーバーのプライベートIPアドレスが含まれている必要があります。
これらの値を変更すると、セカンダリサーバーのスクリプトは次のようになります。
セカンダリサーバーの/etc/keepalived/keepalived.conf
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
vrrp_instance VI_1 {
interface eth1
state BACKUP
priority 100
virtual_router_id 33
unicast_src_ip secondary_private_IP
unicast_peer {
primary_private_IP
}
authentication {
auth_type PASS
auth_pass password
}
track_script {
chk_nginx
}
notify_master /etc/keepalived/master.sh
}
スクリプトを入力して適切な値を変更したら、ファイルを保存して閉じます。
フローティングIP移行スクリプトを作成する
次に、ローカルkeepalived
インスタンスがマスターサーバーになるたびに、フローティングIPアドレスを現在のドロップレットに再割り当てするために使用できるスクリプトのペアを作成する必要があります。
フローティングIP割り当てスクリプトをダウンロードする
まず、DigitalOcean APIを使用してフローティングIPアドレスをドロップレットに再割り当てするために使用できる汎用Pythonスクリプト(DigitalOcean community managerで記述)をダウンロードします。 このファイルを/usr/local/bin
ディレクトリにダウンロードする必要があります。
cd /usr/local/bin
sudo curl -LO http://do.co/assign-ip
このスクリプトを使用すると、次を実行して既存のフローティングIPを再割り当てできます。
python /usr/local/bin/assign-ip floating_ip droplet_ID
これは、DO_TOKEN
という環境変数がアカウントの有効なDigitalOceanAPIトークンに設定されている場合にのみ機能します。
DigitalOcean APIトークンを作成する
上記のスクリプトを使用するには、アカウントにDigitalOcean APIトークンを作成する必要があります。
コントロールパネルで、上部の[API]リンクをクリックします。 APIページの右側で、「新しいトークンを生成」をクリックします。
次のページで、トークンの名前を選択し、「トークンの生成」ボタンをクリックします。
APIページに、新しいトークンが表示されます:
トークンnowをコピーします。 セキュリティのため、このトークンを後で表示する方法はありません。 このトークンを紛失した場合、それを破棄して別のトークンを作成する必要があります。
インフラストラクチャにフローティングIPを構成する
次に、サーバーで使用するフローティングIPアドレスを作成して割り当てます。
DigitalOceanコントロールパネルで、「ネットワーク」タブをクリックし、「フローティングIP」ナビゲーション項目を選択します。 「プライマリ」サーバーとして割り当てたリストからドロップレットを選択します。
アカウントに新しいフローティングIPアドレスが作成され、指定されたドロップレットに割り当てられます。
WebブラウザでフローティングIPにアクセスすると、「プライマリ」サーバーのindex.html
ページが表示されます。
フローティングIPアドレスをコピーします。 以下のスクリプトでこの値が必要になります。
ラッパースクリプトを作成する
これで、正しい資格情報を使用して/usr/local/bin/assign-ip
スクリプトを呼び出すラッパースクリプトを作成するために必要な項目ができました。
次のように入力して、bothサーバーにファイルを作成します。
sudo nano /etc/keepalived/master.sh
内部では、作成したAPIトークンを保持するDO_TOKEN
という変数を割り当ててエクスポートすることから始めます。 その下に、フローティングIPアドレスを保持するIP
という変数を割り当てることができます。
/etc/keepalived/master.sh
export DO_TOKEN='digitalocean_api_token'
IP='floating_ip_addr'
次に、curl
を使用して、現在使用しているサーバーのドロップレットIDをメタデータサービスに要求します。 これは、ID
という変数に割り当てられます。 また、このDropletに現在フローティングIPアドレスが割り当てられているかどうかを尋ねます。 そのリクエストの結果をHAS_FLOATING_IP
という変数に保存します。
/etc/keepalived/master.sh
export DO_TOKEN='digitalocean_api_token'
IP='floating_ip_addr'
ID=$(curl -s http://169.254.169.254/metadata/v1/id)
HAS_FLOATING_IP=$(curl -s http://169.254.169.254/metadata/v1/floating_ip/ipv4/active)
これで、上記の変数を使用してassign-ip
スクリプトを呼び出すことができます。 フローティングIPがドロップレットに関連付けられていない場合にのみ、スクリプトを呼び出します。 これにより、API呼び出しが最小限に抑えられ、マスターステータスがサーバー間で急速に切り替わる場合に、APIへの競合する要求が防止されます。
フローティングIPですでに進行中のイベントがある場合を処理するために、assign-ip
スクリプトを数回再試行します。 以下では、各呼び出しの間に3秒間隔で、スクリプトを10回実行しようとします。 フローティングIPの移動が成功すると、ループはすぐに終了します。
/etc/keepalived/master.sh
export DO_TOKEN='digitalocean_api_token'
IP='floating_ip_addr'
ID=$(curl -s http://169.254.169.254/metadata/v1/id)
HAS_FLOATING_IP=$(curl -s http://169.254.169.254/metadata/v1/floating_ip/ipv4/active)
if [ $HAS_FLOATING_IP = "false" ]; then
n=0
while [ $n -lt 10 ]
do
python /usr/local/bin/assign-ip $IP $ID && break
n=$((n+1))
sleep 3
done
fi
完了したら、ファイルを保存して閉じます。
ここで、keepalived
がスクリプトを呼び出せるように、スクリプトを実行可能にする必要があります。
sudo chmod +x /etc/keepalived/master.sh
Keepalivedサービスの起動とフェールオーバーのテスト
これで、keepalived
デーモンとそのすべてのコンパニオンスクリプトが完全に構成されます。 次のように入力して、両方のマシンでサービスを開始できます。
sudo start keepalived
サービスは各サーバーで起動し、ピアに接続して、構成した共有シークレットで認証する必要があります。 各デーモンはローカルのNginxプロセスを監視し、リモートのkeepalived
プロセスからのシグナルをリッスンします。
両方のサーバーが正常な場合、WebブラウザーでフローティングIPにアクセスすると、プライマリサーバーのNginxページに移動する必要があります。
これで、構成のフェイルオーバー機能をテストする準備が整いました。
次のいずれかの条件が発生すると、フェールオーバーが発生します。
-
When the Nginx health check on the primary server indicates that Nginx is no longer running.この場合、プライマリサーバーの
keepalived
デーモンは「障害」状態になります。 セカンダリサーバーに、マスター状態に移行し、フローティングIPを要求する必要があることを通知します。 -
When the secondary server loses its
keepalived
connection to the primary server。 セカンダリサーバーが何らかの理由でプライマリサーバーに到達できない場合、「マスター」状態に移行し、フローティングIPを要求しようとします。
プライマリサーバーが後で回復した場合、マスターサーバーは新しい選択を開始するため、フローティング状態のIPを回収します(最高の優先順位番号を保持します)。
Nginxの障害のテスト
プライマリサーバーでNginxサービスを停止することにより、最初の条件をテストできます。
sudo service nginx stop
Webブラウザを更新すると、最初にページが利用できないことを示す応答を受け取る場合があります。
ただし、数秒後にページを数回更新すると、セカンダリサーバーがフローティングIPアドレスを要求したことがわかります。
プライマリサーバーでNginxデーモンを再起動することで、障害から回復できます。
sudo service nginx start
数秒後、ページを更新すると、プライマリサーバーが再びフローティングIPの所有権を取り戻したことがわかります。
サーバー障害のテスト
テストする必要があるもう1つのシナリオは、プライマリサーバーに接続できない場合にセカンダリがマスター状態に正しく移行するかどうかです。 これをテストするためにマスターサーバーを再起動できます。
sudo reboot
繰り返しますが、最初はフローティングIPアドレスでサービスの中断が発生するはずです。
数秒後、セカンダリサーバーがリクエストを取得します。
しばらくして、プライマリサーバーが再起動を完了すると、IPアドレスを再利用します。
これにより、2番目の障害シナリオが検証されます。
結論
このガイドでは、keepalived
、DigitalOcean API、およびフローティングIPアドレスを使用して高可用性Webサーバー環境を構成しました。 実際のインフラストラクチャはかなり単純でしたが、この概念は、サービスの可用性と稼働時間が重要なあらゆるタイプのインフラストラクチャに適用できます。