CapistranoとJGitを使ったS3からEC2へのデプロイ

デプロイ時の負荷対策の一解決策になる、、、かも。

JGitのインストール

ローカルマシンとデプロイ対象のホームディレクトリに『~/.jgit_s3』を作成。

accesskey: hoge
secretkey: fuga
acl: private

リポジトリの作成

参考: http://d.hatena.ne.jp/winebarrel/20110206/p1

ローカルマシンで適当なリポジトリを作成して、S3にpushしておく。

s3cmd mb s3://my.git.repos
mkdir myapp
cd myapp/
git init
touch hello.c
git add hello.c 
git commit -m 'first commit'
git remote add origin amazon-s3://.jgit_s3@my.git.repos/myapp.git/
git config branch.master.remote origin
git config branch.master.merge refs/heads/master
jgit push

Capistranoプロジェクトの作成

Rubyのライブラリ探索パスに『capistrano/recipes/deploy/scm/jgit.rb』を置く。
(プロジェクトの直下にディレクトリを作成する、、、とか)

require 'capistrano/recipes/deploy/scm/git'

module Capistrano
  module Deploy
    module SCM

      class Jgit < Git
        default_command "jgit"

        def checkout(revision, destination)
          jgit = command

          execute = []
          execute << "#{jgit} clone #{variable(:repository)} #{destination} 2> /dev/null"
          execute << "cd #{destination} && #{jgit} checkout #{revision}"

          execute.compact.join(" && ").gsub(/\s+/, ' ')
        end # of checkout

        # リモートでのリビジョン取得にちょっと難あり、、、
        # デプロイ対象が複数の場合、リビジョンを統一するようにしないと
        # ローカルで実行するようにすれば大丈夫かな?
        def query_revision(revision)
          jgit = command

          result = nil
          tmp_dir = "/tmp/#{variable(:application)}.#{Time.now.to_i}"

          configuration.run(<<-EOS) {|conn, out, res| result = res}
            #{jgit} clone #{variable(:repository)} #{tmp_dir};
            cd #{tmp_dir};
            git log -1 | awk '/^commit /{print $2}';
            cd ..;
            rm -rf "#{tmp_dir}";
          EOS

          result
        end # of query_revision

      end # of class Jgit

    end
  end
end

Capfileはこんな感じ。

load 'deploy' # おまじない

set :application, 'myapp'
set :scm, :jgit
set :user, 'ec2-user'
set :repository, 'amazon-s3://.jgit_s3@my.git.repos/myapp.git/'
set :deploy_to, '/home/ec2-user/myapp'

role :app, 'ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com'

# Railsプロジェクトではない場合は、以下を無効化
namespace :deploy do
  task(:restart) {}
  task(:finalize_update) {}
end

実行結果


~/work/cap-proj-jgit$ cap deploy
* executing `deploy'
* executing `deploy:update'
** transaction: start
* executing `deploy:update_code'
* executing "jgit clone amazon-s3://.jgit_s3@my.git.repos/myapp.git/ /tmp/myapp.1335282762;\\\n cd /tmp/myapp.1335282762;\\\n git log -1 | awk '/^commit /{print $2}';\\\n cd ..;\\\n rm -rf \"/tmp/myapp.1335282762\";"
servers: ["ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com"]
[ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com] executing command
command finished in 5702ms
* executing "jgit clone amazon-s3://.jgit_s3@my.git.repos/myapp.git/ /home/ec2-user/myapp/releases/20120424155249 2> /dev/null && cd /home/ec2-user/myapp/releases/20120424155249 && jgit checkout 93dac3617fd6fddd578306c81a96b3569c520ad8 && (echo 93dac3617fd6fddd578306c81a96b3569c520ad8 > /home/ec2-user/myapp/releases/20120424155249/REVISION)"
servers: ["ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com"]
[ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com] executing command
** [ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com :: out] Initialized empty Git repository in /home/ec2-user/myapp/releases/20120424155249/.git
** [ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com :: out] From amazon-s3://.jgit_s3@my.git.repos/myapp.git/
** * [new branch] master -> origin/master
command finished in 5931ms
* executing `deploy:finalize_update'
* executing `deploy:create_symlink'
* executing "rm -f /home/ec2-user/myapp/current && ln -s /home/ec2-user/myapp/releases/20120424155249 /home/ec2-user/myapp/current"
servers: ["ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com"]
[ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com] executing command
command finished in 94ms
** transaction: commit
* executing `deploy:restart'


[ec2-user@ip-XX-XX-XX-XX ~]$ ls -R myapp/
myapp/:
current releases

myapp/releases:
20120424155249

myapp/releases/20120424155249:
hello.c REVISION