- 作者: 宮下剛輔
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/01/17
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る
Serverspec本を読んだので実践してみた。
EC2インスタンスはPublic IPが変わる可能性がある。 新しいインスタンスを増やしたり減らしたりもする。 サービスは複数あり、サーバーも複数だ。
そんな状況でServerspecでテストしていきたい場合、何ができるのだろうか。
ド素人ながら本気出して考えてみた*1
ユーザーの問題
Serverspecを誰が流すのか。
Serverspec用のユーザーを用意する
Serverspec用ユーザーにServerspec用鍵を持たせてServerspec(くどい)すればいいんじゃね?
- 色んなサービス色んなサーバー全部に入れるユーザーと鍵ができることになる
- しかもsudoしないとテストできない項目もあるのでできればsudo権限が必要
- その鍵が盗まれれば全サーバーの死。リスキーな状態になる。
- パスワードつけたりが意外とめんどくさい。。。
- 結局ec2-userと同等の権限を持った全サーバーにログイン可能な神ユーザーが誕生。
といろいろ問題がある。
本気出した結論:
ec2-userでいいんじゃね。Serverspec本にもec2-userで紹介されているし。
秘密鍵問題
ec2-userでいいとして鍵はどうするのか。
Serverspec用マスターキーをもつ => 却下
ssh_optionにすべての鍵を列挙しておく => ssh的に5つまでしかダメ
本気出した結論
インスタンス作った時に指定した最初の鍵をつかう。名前はAPIから取る。
EC2のdescribe_instances APIからインスタンスの情報を取り、key_nameから鍵の名前を取得可能。秘密鍵名もだいたい "#{key_name}.pem"なので鍵置き場を固定すればいくつでも対応できるし、ばらばらでいいし、既に鍵は存在する。
IPどうやってとるの問題
基本describe_instances APIで取ればよし。
踏み台
踏み台サーバーから入らないといけない場合はProxyCommand相当を個々のサーバーごとに設定する必要がある。
本気出した結論
いわゆるName(タグ)の命名規則をちゃんと揃え、命名規則からProxyCommandを組み立てられるようにしておく。Nameの命名規則がととのっているとCapistoranoとかでも便利。
ssh_config問題
ssh_configに依存すると多人数で開発するとき「これ書いといてな」としか言えないしめっちゃめんどくさい。
本気出した結論
ssh_configを一切使わない。Serverspecのホスト指定もIPアドレスで行う。
specをホストごとに書いてられへんで問題
spec/app01.example.com/nginx_spec.rb
なんてやっていると当然流動的なサーバー群に対し無力。
本気出した結論
EC2のタグを使う。
"Roles"タグを用意し、','区切りで複数のロールを割り当てられるようにする。*2
さらにロール毎のspecディレクトリをきってロールに対するspecを書く。
specを走らせるときはdescribe_instances APIで取得したRolesタグからそのままディレクトリを指定して走らせるようにしておく
まとめ
まとめるとRakefileはこんな感じになる。
hosts = (aws-sdkを使ったすごいコード) desc "Run serverspec to all instances" task :spec => hosts.map{|h| "spec:#{h.public_ip_address}"} task :default => :spec namespace :spec do hosts.each do |host| desc "Run serverspec to #{host.name}" RSpec::Core::RakeTask.new(host.public_ip_address) do |t| ENV['TARGET_HOST'] = "#{host.name}:#{host.public_ip_address}" # specが失敗した時に表示されて便利 ENV['TARGET_IP'] = host.public_ip_address ENV['TARGET_KEY'] = File.expand_path("~/.ssh/aws/#{host.key_name}.pem") t.pattern = "spec/{base,#{host.roles.join(',')}}/**/*_spec.rb" end end end
require 'serverspec' puts "\nHost: #{ENV['TARGET_HOST']}" set :backend, :ssh set :request_pty, true set :env, :LANG => 'en_US.UTF-8' set :host, ENV['TARGET_IP'] set :ssh_options, :user => 'ec2-user', :keys => [ENV['TARGET_KEY']]
まーなんか、このへんが妥協点な気がする。