ようへいの日々精進XP

よかろうもん

今更だけど capistrano と chef-solo を組み合わせて...シリーズのまとめ

はじめに

前回前々回の記事で capistranoChef-Solo を組み合わせたのをきっかけに AWS SDK for Ruby を使って EC2 インスタンスに対応させたツール的な物を作ったり serverspec を個人的に拡張したりしながら色々と学ぶことが多かったので、ツールで出来ることの棚卸しと学んだことについてメモる。


capistrano と Chef-Solo と AWS SDK for Ruby を組み合わせたツールについて

ソースコード

こちら

イメージ

f:id:inokara:20140202111657p:plain

使い方

以下は README に反映させる予定。

EC2 のインスタンスを作成する

cap aws-setup ec2:launch

EC2 のインスタンスの一覧を取得する

cap aws-setup ec2:list

また、ec2:listall で稼働中、停止中合わせて全てのインスタンスの一覧が表示される。

EC2 のインスタンスのタグを設定する

cap aws-setup ec2:settag -s _set_host="${Public_DNS}" -s _set_tag="${New_Tag}"

${Public_DNS} でタグを設定するインスタンスを指定して、${New_Tag} にて新しいタグを設定する。

ホスト(EC2 インスタンス、その他のサーバー)に Chef-Solo が利用出来るようにする

cap aws-setup chef:init

以下は EC2 インスタンスにかぎらず ssh でログイン出来るホストであれば使える。

ホスト(EC2 インスタンス、その他のサーバー)に cookbook をアップロードする

cap aws-setup chef:sync

ホスト(EC2 インスタンス、その他のサーバー)で Chef-Solo を実行して cookbook を適用する

cap aws-setup chef:deploy

aws-setup という名前だと AWS に特化した感じになりそうなので将来的には名前を分けよう。


serverspec へのちょっとした拡張

ソースコード

こちら

イメージ

f:id:inokara:20140202113954p:plain

使い方

以下は README に反映させる予定。

テスト対象となるホストの spec ファイルを作る

rake genspec

上記を実行すれば AWS SDK for Ruby を経由してインスタンスのホスト名を取得して spec ファイルのフォルダをテンプレートからコピーする。


ツールを作る過程で学んだこと

capistrano での #{sudo} と #{try_sudo} の違い

こちらに詳しく書かれていてとても参考になった。手元で試してみると以下のような違いが見られた。

set :use_sudo sudo の書き方 展開されるコマンド結果
false #{try_sudo} chef-solo -j /tmp/chef/chef-repo/nodes/localhost.json -c /tmp/chef/chef-repo/solo.rb
true #{try_sudo} sudo -p 'sudo password: ' chef-solo -j /tmp/chef/chef-repo/nodes/localhost.json -c /tmp/chef/chef-repo/solo.rb
false #{sudo} sudo -p 'sudo password: ' chef-solo -j /tmp/chef/chef-repo/nodes/localhost.json -c /tmp/chef/chef-repo/solo.rb
true #{sudo} sudo -p 'sudo password: ' chef-solo -j /tmp/chef/chef-repo/nodes/localhost.json -c /tmp/chef/chef-repo/solo.rb

上記の結果からすると set :use_sudofalse にしておいて #{sudo} と書くのが EC2 インスタンスでは良さそう。

pry によるデバッグ

これもタイトル通り今更感満載だがツールを作る過程でデバッグと言えば、毎回 cap コマンドを叩くという非効率なことをやっていたが、pry を利用することでずいぶん効率化が図れた。起動はとても簡単。コマンドラインから pry と打つだけ。

pry

起動すると以下のようなプロンプトになる。

f:id:inokara:20140202075507p:plain

AWS SDK for Ruby と pry

pry から AWS SDK for Ruby を使う場合の最初の手続き的なものとして...

  1. require 'aws-sdk'
  2. AWS.config(:access_key_id => "AK******************", :secret_access_key => "****************************************", :region => "ap-northeast-1")

上記のように AWS SDK for Rubyrequire してからアクセスキー等の設定を行う。

f:id:inokara:20140202080311p:plain

上記では 1. と 2. を実行した後で dns_name で指定したインスタンスの情報を取得しようとしているところ。結果は配列に入ったオブジェクトとして返ってくる。

配列に入ったオブジェクトからインスタンスの情報を取り出す

上記のように配列に入ったインスタンス情報のオブジェクトからインスタンス情報の詳細(インスタンスの ID や PublicDNS 等...)を取り出す場合には...

instance = AWS.ec2.instances.select {|i| i.status == :running && i.dns_name == "ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com"}

上記の instance には [<AWS::EC2::Instance id:i-xxxxxxxx>] が入るので以下のようにした。

instance[0].instance_id
instance[0].dns_name

以下はデモ。

f:id:inokara:20140202081846p:plain

dns_nameinstance_id はメソッド。methodsどんなメソッドがあるかを確認出来る。

Rakefile に纏めるとすっきりする

前回の記事EC2 インスタンスに対して servespecspec ファイルを生成する方法について別途でスクリプトを作って対応したが、この spec ファイルを生成するスクリプトRakefile に統合してしまった方が美しそうなのでやってみた

require 'fileutils'
require 'aws-sdk'
require 'yaml'
#
task :genspec do
  config = YAML.load(File.read("#{ENV['HOME']}/path/to/config/deploy/config.yml"))
  AWS.config(config)
  #
  ORIG = "./spec_template"
  SPEC = "./spec"
  #
  servers = AWS.ec2.instances.select {|i| i.tags[:Name] == 'setup' && i.status == :running}.map(&:dns_name)
  servers.each do |server|
    puts "Created #{SPEC}/#{server}/check_spec.rb"
    FileUtils.cp_r("#{ORIG}","#{SPEC}""/""#{server}") unless FileTest.exist?(server)
  end
end

上記のように Rakefile に纏めることで手順としても以下のように rake コマンドに集約することが出来た。

rake genspec

を実行すると spec ファイルが生成(テンプレートからコピー)される。


さいごに

  • 車輪の再発明感は否めないがやりたいことを形に出来たのは楽しかった
  • 悲しいくらい Ruby 力が足りてない
  • とりあえずこれを社内で公開してみたいと思ったり