AWS ELB配下にあるインスタンスに対しserverspecでテスト・管理する方法
serverspecはよく使っているのですが、ある状態をチェックしたいとき、その自動化に役立ちます。
例としてcrondやnginxのステータス確認などがそれにあたるかと思います。
これまでは
ssh '対象ホスト' /etc/init.d/crond status
のようにやっていました。
これもサーバーが1台であったり、確認することが1つであればそこまでめんどくさくはないのですが、複数台で、複数のことがらをチェックするのは結構大変です。
なので自動化したい!っていうことなのですが、単純な使い方ならこちらの記事を参考に
一番参考になるのはなんだかんだで公式ドキュメント!DevOpsのためにチェックすべきドキュメント3選! - nigoblog
serverspec - Home
serverspecは基本的に
~/.ssh/config
の内容を参考に動きます。
その際、ELB配下で固定IPをつけていない場合、いちいちIPを見に行かなければなりません。
今回そのめんどくさい部分を解決したserverspecの使い方をしているのでその紹介をします。
流れとしては
このような流れとなります。
aws-sdkで動的にインスタンスのIPを取得
これはよくcapistranoでELB配下のインスタンスにデプロイをする際によく使われます。
これの使い方は簡単で
Ruby - CapistranoでELB配下のEC2インスタンスを取得してデプロイ - Qiita [キータ]
こちらの記事を参考にしました。
serverspecで使う場合、
cd serverspec bundle init
でserverspecディレクトリにGemfileを作成
Gemfileには
gem 'aws-sdk'
と追加し
bundle install
を行う。
次にspec/spec_helper.rbを開いて
require 'serverspec' require 'pathname' require 'net/ssh' require 'aws-sdk'
これでaws-sdkを読み込み、
RSpec.configure do |c| AWS.config({ :access_key_id => '<アクセスキー>', :secret_access_key => '<シークレットキー>', :ec2_endpoint => 'ec2.ap-northeast-1.amazonaws.com', :elb_endpoint =>'elasticloadbalancing.ap-northeast-1.amazonaws.com' }) elb = AWS::ELB.new.load_balancers['<ELBの名前>'] instances = elb.instances.select {|i| i.exists? && i.status == :running}.map(&:dns_name)
するとinstancesにELB配下インスタンスのIPが配列として代入されます。
まず第一段階のELB配下インスタンスのIPを動的に取得しました。
ssh/configで各インスタンス共通のログイン情報を作成
次のステップは一旦serverspecとは離れ、ssh/configの設定を行います。
vim ~/.ssh/config
を次のように編集します。
Host ELBの名前 User <sshで入るユーザー名> IdentityFile <鍵のパス>
一応ELBの名前としておりますが、実際はなんでも構いません。
第二段階もこれでオッケー
各インスタンスのspecを作成
ここはまずひとつはベタで作成し、それをコピーしていく形が理想です。
最終的にはspecディレクトリが
spec/ spec_helper.rb ELBの名前_0/ ELBの名前_1/ ... ELBの名前_N-1/
のようになっていると良いでしょう。(Nはインスタンスの数)
まずELBの名前_0というディレクトリに基本のspecを書きます。
次にどんどんコピーしていきます。(ここだけ手動でイケてないので改善していこうかと)
cp -r ELBの名前_0 ELBの名前_1 ... cp -r ELBの名前_0 ELBの名前_N-1
これで第三段階も終了
serverspecでELBの場合どうするか記述する
というわけで最後にもう一回spec_helper.rbを編集します。
host = File.basename(Pathname.new(file).dirname) if c.host != host c.ssh.close if c.ssh c.host = host options = Net::SSH::Config.for(c.host) user = options[:user] || Etc.getlogin c.ssh = Net::SSH.start(c.host, user, options) end
まずデフォルトのserverspecはこのようになっております。
ここに先ほど取得したインスタンス情報を反映させます。
host = File.basename(Pathname.new(file).dirname) if c.host != host c.ssh.close if c.ssh # ELB対応 if host =~ /<ELBの名前>*/ host_num = File.basename(Pathname.new(file).dirname)[-1].to_i c.host = "<ELBの名前>" options = Net::SSH::Config.for(c.host) options[:host_name] = instances[host_num] else c.host = host options = Net::SSH::Config.for(c.host) end c.ssh = Net::SSH.start(c.host, user, options) end
すると自動でELB配下のインスタンスIPが取得され、serverspecのテストを実行することができます。
というわけで以上ELB配下のインスタンスにserverspecを適用する方法でした!
いろいろ改善点はありますが、ひとまず動くところまで!