インフラブログ

とあるWEBサイトのインフラを構築運用するメモ

Capistrano(3.x)でデプロイする

AWS内のステージング環境をセットアップしているとアプリが動くところを早く確認したくなり、過去の案件で使われてたCapistranoの設定を流用してさっさとデプロイしようとしたところ、最近はバージョンが3らしく、書き方も大きく変わっているようです。 Capistrano2.xのまま使おうかとも考えたのですが、プログラム担当で神主の息子でもある御方に「ちゃんと勉強して」と怒られたので3にさせていただきます。 このような記事を参考にしてCapfile、deploy.rbを設定しました。

いつものように設定について解説は網羅しませんが、補足しておきたいことだけ書いておきます。

インターネット越しのデプロイは踏み台サーバを経由して各サーバにSSHする

手元の端末からAWS内の各サーバ一にデプロイする時は、一度踏み台サーバにsshしてそこから各サーバにさらにSSHする方針にします。 専用にVPNはるのも大げさなような気がするし、かといってインターネットから全てのインスタンスに直でSSHできるのもあれなので。

お手元のPC(cap叩く)
|
|
踏み台サーバ
|
|
各サーバ

Capistrano2.xのときは踏み台経由でのデプロイがサポートされていたと思うのですが、3では実装されていないようです。 作業する方には各自クライント端末の.ssh/configに以下のようなproxy設定をしてもらうことにします。

Host fumidai.example.com
    HostName fumidai.example.com
    User ec2-user
    Port 12345

Host 172.31.*(VPC内のネットワークアドレスがこれに収まる)
  User ec2-user
  ProxyCommand nohup ssh fumidai.example.com exec nc %h %p

こうすると手元の端末から$ssh 172.31.1.1と実行した場合、fumidai.example.comsshしてからさらに172.31.1.1にsshすることになります。 もし手元の端末が172.31.なネットワーク環境下にいた場合は正しく動作しないかもしれません。ネットワークがかぶらない前提の設定です。

デプロイ実行時に動的にroleの設定をする

負荷によってec2インスタンスが増減するのでデプロイ時にインスタンスのタグを参照して、条件に該当するipをroleに設定するようにします。 stagingデプロイの際、インスタンスにweb=stagingのタグがあればこのインスタンスのipがrole:webとしてセットされます。 app=stagingがあればrole:appにもセットされます。 インスタンスのipを返すスクリプト自体は:gateway_serverのサーバ上に置いて、デプロイ時にssh越しでそれを叩いています。

  • lib/capistrano/tasks/aws.cap
# -*- coding: utf-8 -*-
#
namespace :aws do
  desc "role設定する"
  task :set_roles do
    on fetch(:gateway_server) do
      ["proxy", "web", "app", "db"].each do |role|
        ips = capture("ec2_roles.rb #{fetch(:stage)} #{role}).to_s.split(/\s+/)
        unless ips.empty?
          role role.to_sym, ips
          puts role
          puts ips
        end
      end
    end
  end
end
  • ec2_roles.rb
require 'aws-sdk'
roles = ARGV.shift
roles ||= "app"
stage = ARGV.shift
stage ||= "staging"

AWS.config(YAML.load(File.read('config.yml')))

ips = []
AWS::EC2.new.instances.tagged("#{stage}:role:#{role}").tagged_values("1").each{|ec2|
  ips << ec2.private_ip_address.to_s if ec2.status.to_s == "running"
}

puts ips