概要
私はAWSへCapistrano 3を使ってCircle CIで自動デプロイしています。
サーバが1台の時はCapistranoの設定ファイルにデプロイ先のサーバIP直書きでも良いのですが(良いのか?)、ここでAutoScalingに対応してELB配下にあるインスタンス全部へ自動デプロイしたいとなりました。(ちなみにインスタンスの立ち上げからの自動デプロイはBootStrapパターンを使用しています)
Gemやらあるかなと思ったのですが、現在のCapistrano 3およびaws-sdk 2に対応していて鉄板なものが見つからず、社内制手工業で依存が少なく安心して使えるものを書きました。
##実際の方法
Gemの設定
2015/03/18現時点で最新のaws-sdk 2系を使います。
group :development do
gem 'aws-sdk'
end
aws-sdkのrequire
そしてちょっとハマりどころなのですが、aws-sdk 2で定義されているメソッドがcapistrano 3で定義されているメソッドとコンフリクトしてエラーが出るので、それを回避するために以下をCapfile冒頭に加えます。(capistrano3とaws-sdk v2を組み合わせるとDefinitionErrorにハマった話に助けられました、ありがとうございます ( _ _))
require 'aws-sdk'
Aws::EC2::Resource
環境変数の設定
で、aws-sdkを使うために以下の環境変数を設定してあげます。
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_access_key
AWS_REGION=ap-northeast-1 (this is for tokyo region)
デプロイ時、ELB配下にあるインスタンスをデプロイ先に設定するコードを追加
最後に任意のdeploy設定ファイルに以下を加え完成です。Capistranoの設定ファイルは言語内DSLなので、こういう作業も楽ちんです。以下のSampleLoadBalancerNameは目的のロードバランサの名前に置き換えてください。環境変数にしてしまうのも良いと思います。
ここではInService状態のインスタンスにのみデプロイするようにしています。
elasticloadbalancing = Aws::ElasticLoadBalancing::Client.new
instance_states = elasticloadbalancing.describe_instance_health(load_balancer_name: 'SampleLoadBalancerName').instance_states
target_instance_ids = []
instance_states.each do |instance_state|
target_instance_ids.push instance_state.instance_id if instance_state.state == 'InService'
end
ec2 = Aws::EC2::Client.new
response = ec2.describe_instances instance_ids: target_instance_ids
ip_addresses = response.reservations.map {|r| r.instances.map {|i| i.public_ip_address } }.flatten
ip_addresses.each do |ip|
server ip.to_s, user: 'deploy', roles: %w{web app db}
end
これはいわゆる以下の代わりです。
server 'under-elb-server1.com', user: 'deploy', roles: %w{web app db}
server 'under-elb-server2.com', user: 'deploy', roles: %w{web app db}
server 'under-elb-server3.com', user: 'deploy', roles: %w{web app db}
...
サーバとの認証についてワンポイント
最後にもう一つ。今回予期できない複数のホストへデプロイするので公開鍵認証で躓く場合があります。設定で秘密鍵の場所を指定してあげると良いかもしれません。
if ENV['DEPLOY_ORIGIN'] == 'local'
set :ssh_options, {
keys: %w(~/.ssh/hogehoge/id_rsa),
auth_methods: %w(publickey)
}
end
ENVで分岐させてるのは、Circle CIでは指定してあげなくても何故か上手くいき(誰か教えて頂けると嬉しいです)、なおかつそれ以前にキーの場所が分からなかったからです。
こちらからは以上です。