簡単極小構成でFailoverを体験してみよう! 〜 Vagrant+Chef を使って 〜 #vgadvent2013
こんにちは!@at_grandpa です。
この記事はVOYAGE GROUP エンジニアブログ : Advent Calendar 2013の19日目の記事になります。
今年ももうあと10日前後となりました。みなさんいかがお過ごしでしょうか。
さて、何を書こうかな
エンジニアの Advent Calendar 界隈では、「年末年始を安心して過ごすように」系記事も多数投稿されていますね。
私もそれ系を書こうと思いましたが、インフラはド素人なのでどうしたものかと。
で、以下の本を読んだ時にテーマが決まりました。
[24時間365日] サーバ/インフラを支える技術 ?スケーラビリティ、ハイパフォーマンス、省力運用 (WEB+DB PRESS plusシリーズ)
- 作者: 安井真伸,横川和哉,ひろせまさあき,伊藤直也,田中慎司,勝見祐己
- 出版社/メーカー: 技術評論社
- 発売日: 2008/08/07
- メディア: 単行本(ソフトカバー)
- 購入: 133人 クリック: 2,270回
- この商品を含むブログ (289件) を見る
この冒頭に、簡単なFailoverの仕組みが書いてありました。ですので今回は、簡単極小構成で実際にFailoverを体験してみようと思います。
「Failoverって言葉は知っているけど、実際どういうことが行われているの?」
という方は、簡単ですのでぜひやってみてください。
簡単極小構成
構成は以下です。物理的に必要なのはMacのみです。物理サーバーもケーブルも何もいりません。良い世の中ですね。お財布にも優しいです。
Vagrant と Chef については、以下のサイトが優しく解説されていると思います。
今っぽい Vagrant + Chef Solo チュートリアル
Berkshelfの記事の直前まで読めば、今回の構成は実行できるかと思います。
その他、個人的にVagtrantのインストール方法などもまとめたので、以下もご参照ください。
Vagrant のインストールから仮想環境立ち上げまでを、オプションなどと共にちょっと細かく追ってみた
Failoverの流れ
では実際にどう処理が流れていくのかを見てみましょう。
実運用中はこのような動作をしています。Terminal.appではpingコマンドで接続を常に確認します。 server1とserver2の間では、お互いにヘルスチェックをします。↓
そして、ひとつのサーバー(server2)を潰します。すると、server1の health check が障害を検知し、Failoverの処理が走ります。↓
server1によるIPアドレスの引き継ぎと、引き継ぎの報告がなされます。↓
無事、両IP共、接続が可能となります。↓
たった一つのコマンドで環境構築
今回の環境を構築するには、Vagrantfile、recipe、シェルスクリプトの3つを編集します。1つずつ見ていきましょう。
Vagrantfile
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # common setting config.vm.box = "cent_os" # server1 config.vm.define "server1" do |server| server.vm.network :private_network, ip: "192.168.1.11" end # server2 config.vm.define "server2" do |server| server.vm.network :private_network, ip: "192.168.1.12" end # chef-solo config.vm.provision :chef_solo do |chef| chef.cookbooks_path = "./chef-repo/site-cookbooks" # 自作の[httpd]というcookbookを作成し、ここで指定(後述) chef.add_recipe "httpd" end # provision :shell config.vm.provision :shell do |sh| sh.path = "failover.sh" end end
クックブック "httpd" のrecipe
# cookbook:httpd service "iptables" do action [:stop, :disable] end package "httpd" do action :install end service "httpd" do action [ :enable, :start ] end template "/var/www/html/index.html" do source "index.html.erb" mode 0644 end
failover.sh
#!/bin/sh VIP="192.168.1.20 192.168.1.21" DEV="eth0" healthcheck() { # VIPのループを回る for i in $VIP;do # 自分のVIP以外の場合はtrueで中の処理へ if [ -z "`ip addr show $DEV | grep $i`" ]; then # レスポンスを格納 RES=`curl -s -I http://${i}/| head -n 1 | cut -f 2 -d ' '` # レスポンスが何もない場合 if [ -z "${RES}" ]; then CIP="$i" return 1 fi # レスポンスはあるが200以外の時 if [ "200" -ne "${RES}" ]; then CIP="$i" return 1 fi fi done return 0 } ip_takeover() { # 障害のあったVIPを自分のサーバーに加える ip addr add $CIP/24 dev $DEV # arpを送信(IPを引き継いだことを報告) arping -A -I $DEV -c 1 $CIP } # 1秒間隔で health check while healthcheck; do echo "health ok!" sleep 1 done # failover処理を実行 echo "failover!" ip_takeover
このシェルスクリプトは、1回目の実行と2回目の実行で動作が異なります。
failover.shの1回目実行の動作
- まずはChef Soloによってserver1でスクリプトが走る
- server1にて、healthcheck()が走る
- 192.168.1.20のIPは存在しないのでhealthcheck()を抜け、ip_takeover()が実行される
- server1にVIP : 192.168.1.20 が付与される
- 次に立ち上がったserver2でスクリプトが走る
- server2にて、healthcheck()が走る
- 192.168.1.20のIPは存在しているので(server1)レスポンスが返ってくるため、次の 192.168.1.21 をチェックする
- 192.168.1.21のIPは存在しないのでhealthcheck()を抜け、ip_takeover()が実行される
- server2にVIP : 192.168.1.21 が付与される
これで、2つのVIPのサーバーが生きている状態になりました。
failover.shの2回目の実行の動作
- server1でもう一度、手動で実行した場合を考える
- for文内のif文
if [ -z "ip addr show $DEV | grep $i" ]; then
は、自分のIP以外はtrueとなるので、レスポンスの有無をチェックするのは常に相手(server2)のIPとなる- これで、server1は「server2の health check をしている状態」になる
- server2の場合はIPが逆になるだけで、全く同じ動き
- これでお互いにhealth checkしている
- 常に1秒おきに health check をし、相手の反応がなかったら、相手のIPを自分に引き継ぐ
さて、いよいよサーバーを立ち上げます。
vagrant up !!
必要なコマンドは、vagrant up
のみです。
Vagrantfileのあるディレクトリに移動して、コマンドを実行しましょう。
実行結果↓
Bringing machine 'server1' up with 'virtualbox' provider... Bringing machine 'server2' up with 'virtualbox' provider... [server1] Importing base box 'cent_os'... ... 【省略】サーバー立ち上げのもろもろの処理 ... [server1] The guest additions on this VM do not match the installed version of VirtualBox! In most cases this is fine, but in rare cases it can cause things such as shared folders to not work properly. If you see shared folder errors, please update the guest additions within the virtual machine and reload your VM. Guest Additions Version: 4.1.18 VirtualBox Version: 4.2 ← ■■■ サーバーが立ち上がった ■■■ [server1] Configuring and enabling network interfaces... [server1] Mounting shared folders... [server1] -- /vagrant [server1] -- /tmp/vagrant-chef-1/chef-solo-1/cookbooks [server1] Running provisioner: chef_solo... ← ■■■ ここからchefの実行 ■■■ Generating chef JSON and uploading... load: 1.67 cmd: VBoxManage 1401 waiting 0.04u 0.03s Running chef-solo... [2013-12-19T01:54:03+01:00] INFO: *** Chef 10.12.0 *** [2013-12-19T01:54:04+01:00] INFO: Setting the run_list to ["recipe[httpd]"] from JSON [2013-12-19T01:54:04+01:00] INFO: Run List is [recipe[httpd]] [2013-12-19T01:54:04+01:00] INFO: Run List expands to [httpd] [2013-12-19T01:54:04+01:00] INFO: Starting Chef Run for localhost [2013-12-19T01:54:04+01:00] INFO: Running start handlers [2013-12-19T01:54:04+01:00] INFO: Start handlers complete. [2013-12-19T01:54:04+01:00] INFO: service[iptables] stopped ← ■■■ iptables ■■■ [2013-12-19T01:54:04+01:00] INFO: service[iptables] disabled [2013-12-19T01:54:34+01:00] INFO: package[httpd] installing httpd-2.2.15-29.el6.centos from base repository ← ■■■ apacheインストール ■■■ [2013-12-19T01:54:42+01:00] INFO: package[httpd] installed version 2.2.15-29.el6.centos [2013-12-19T01:54:42+01:00] INFO: service[httpd] enabled [2013-12-19T01:54:42+01:00] INFO: service[httpd] started ← ■■■ apache起動 ■■■ [2013-12-19T01:54:42+01:00] INFO: template[/var/www/html/index.html] mode changed to 644 ← ■■■ index.htmlの設置 ■■■ [2013-12-19T01:54:42+01:00] INFO: template[/var/www/html/index.html] updated content [2013-12-19T01:54:42+01:00] INFO: Chef Run complete in 38.139665 seconds [2013-12-19T01:54:42+01:00] INFO: Running report handlers [2013-12-19T01:54:42+01:00] INFO: Report handlers complete [server1] Running provisioner: shell... ← ■■■ シェルの実行 ■■■ [server1] Running: /var/folders/q5/c85lqfy57t7f1sw5lsh6nzn4wnj0pf/T/vagrant-shell20131219-1258-162e2hz failover! ← ■■■ ip_takeover()の実行 ■■■ ARPING 192.168.1.20 from 192.168.1.20 eth0 ← ■■■ VIPの付与 ■■■ Sent 1 probes (1 broadcast(s)) Received 0 response(s) ... 【省略】同様の動作をserver2でも実行 ...
このような流れになっています。
立ち上がると、Terminal.appからの2つのpingが通るようになります。
health check の起動
vagrant up
だけでは、まだ1回しかfailover.shは実行されていないので、VIPの付与は終わっていますが health check は動作していません。
vagrant ssh server1
を打ち、server1内でシェルスクリプトを実行しましょう。
Let's 障害発動
障害を起こしましょう。こんな経験あまりないですよ。おもいっきり障害を起こしてください。
では、sever2を停止しましょう。コマンドはクライアント上でvagrant halt server2
です。
停止したあとのTerminal.appでのping結果は以下です。↓
Failover!帰ってきた192.168.1.21!
無事以下の状態になっていますね。
server2は殉職しましたが、サービスは継続しています。( ゚Д゚ノノ"☆パチパチパチパチ
課題
この構成は、簡単が故にまだまだ課題が残っています。
- 3台あったらどうなるの?
- シェルスクリプトをいちいち起動しないといけない
- 一回のfailoverしか対応していない
などなどです。それらを解決するために、ロードバランサなどの機器が用いられています。
詳しくはここでは割愛しますが、[24時間365日] サーバ/インフラを支える技術 ?スケーラビリティ、ハイパフォーマンス、省力運用 (WEB+DB PRESS plusシリーズ) に書かれていますので、まだの方はご一読をば。
最後に
知識として知ってはいても、実際に自分で動かしてみると、これまた違った知識として定着しますね。
やはり手を動かすことは大切!みなさんもぜひ体験してみてください。
明日のAdventCalendarは、我らがアイドル@saya_223nです。 アイドルっぽい記事で心を癒してくれることでしょう!