Capistrano3でEC2インスタンス新規作成から初期設定までのデプロイ(まとめ)

ここまでAWSのEC2インスタンスを新規作成して、そのインスタンスに対しての初期設定までを、Capistrano3でタスク化することをやって来ました。難儀したものの、ようやくEC2インスタンスの準備が出来て、あとはミドルウェアやアプリケーションをインストールするだけ──というところまでたどり着きました。そこで今回は、これまでのデプロイの流れを一度総括してまとめてみようかと思います。

まず、Capistrano3を稼動させるデプロイサーバの準備から。公式のAmazon Linux環境などのEC2インスタンスをAWSマネージメントコンソール等からラウンチして、ログインしたら、Capistrano3をインストールします1

# yum update -y
# yum groupinstall -y "Development Tools"
# openssl version
OpenSSL 1.0.1h-fips 5 Jun 2014
# openssl version -d
OPENSSLDIR: "/etc/pki/tls"
# curl -L https://get.rvm.io | bash -s stable
# source /etc/profile.d/rvm.sh
# rvm list
(※ rvm rubies と表示されればインストール完了)
# ruby -v
ruby 2.0.0p451 (2014-02-24 revision 45167) [x86_64-linux]
# rvm install 2.0.0 -- --with-openssl-dir=/etc/pki/tls
# ruby -v
ruby 2.0.0p481 (2014-05-08 revision 45883) [x86_64-linux]
# gem install rails --no-ri --no-rdoc
# gem install capistrano
# gem install capistrano_colors
# gem install capistrano-ext
# gem install railsless-deploy
# cap --v
 (※ cap aborted! ~と表示されればインストール完了)
# gem install aws-sdk

デプロイサーバにてデプロイプロジェクトを実行するユーザを作成しておきます。デプロイタスクの内容にもよるのですが、対象のユーザはsudo権限を持っていた方が都合が良いかと思います。ユーザを作成したら、そのユーザで再ログインして、ホームディレクトリで、Capistrano3用のプロジェクトを作成します。

$ sudo useradd -G wheel deploy-user
$ sudo passwd deploy-user
$ sudo su - deploy-user
$ mkdir -m 755 cap3-project
$ cd cap3-project
$ cap install STAGES=test

次に、デプロイプロジェクト「cap3-project」の設定を行います。 まず、デプロイプロジェクト共通で利用するグローバル設定cap3-project/Capfileの編集します。

Capfile

# Load DSL and Setup Up Stages
require 'capistrano/setup'

# Includes default deployment tasks
require 'capistrano/deploy'

# Includes tasks from other gems included in your Gemfile
#
# For documentation on these, see for example:
#
#   https://github.com/capistrano/rvm
#   https://github.com/capistrano/rbenv
#   https://github.com/capistrano/chruby
#   https://github.com/capistrano/bundler
#   https://github.com/capistrano/rails
#
# require 'capistrano/rvm'
# require 'capistrano/rbenv'
# require 'capistrano/chruby'
# require 'capistrano/bundler'
# require 'capistrano/rails/assets'
# require 'capistrano/rails/migrations'

# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

Rake::Task[:test].invoke
invoke :test

今回のデプロイではタスクにてrvmやrails等を利用しないので、オプションモジュールのインクルードは不要です。一応、デフォルトのデプロイ環境が「test」であることのみ指定しておきます。

次に、デプロイ環境ファイルcap3-project/config/deploy/test.rbの設定です。

config/deploy/test.rb

# Simple Role Syntax
# ==================
# Supports bulk-adding hosts to roles, the primary server in each group
# is considered to be the first unless any hosts have the primary
# property set.  Don't declare `role :all`, it's a meta role.

#role :app, %w{deploy@example.com}
#role :web, %w{deploy@example.com}
#role :db,  %w{deploy@example.com}


# Extended Server Syntax
# ======================
# This can be used to drop a more detailed server definition into the
# server list. The second argument is a, or duck-types, Hash and is
# used to set extended properties on the server.

#server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value


# Custom SSH Options
# ==================
# You may pass any option but keep in mind that net/ssh understands a
# limited set of options, consult[net/ssh documentation](http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start).
#
# Global options
# --------------
#  set :ssh_options, {
#    keys: %w(/home/rlisowski/.ssh/id_rsa),
#    forward_agent: false,
#    auth_methods: %w(password)
#  }
#
# And/or per server (overrides global)
# ------------------------------------
# server 'example.com',
#   user: 'user_name',
#   roles: %w{web app},
#   ssh_options: {
#     user: 'user_name', # overrides user setting above
#     keys: %w(/home/user_name/.ssh/id_rsa),
#     forward_agent: false,
#     auth_methods: %w(publickey password)
#     # password: 'please use keys'
#   }

今回のデプロイでは、デプロイ環境へのロール設定やSSH設定は、実際のタスク中で都度々動的に行うため、初期設定値は全てコメントアウトしています。

そして、デプロイタスクの実体を設定します。

config/deploy.rb

# config valid only for Capistrano 3.1
lock '3.2.1'

## AWS 関連の各種設定 ------------------------------------------------

# AWS SDK for Ruby を読み込む
require 'aws-sdk'

# AWS SDK用の設定
AWS.config({
  :access_key_id => '<AWS_ACCESS_KEY_ID>', 
  :secret_access_key => '<AWS_SECRET_ACCESS_KEY>', 
  :region => 'ap-northeast-1',
})

# AMIのimage_id
# Amazon Linux AMI 2014.03.2 (HVM)
set :ami_image_id, 'ami-29dc9228'

# 作成するInstance数
set :instance_count, 2

# 作成するInstanceタイプ
set :ec2_instance_type, 't2.micro'

# 作成先のAvailability Zones
set :availability_zones, [ 'ap-northeast-1a', 'ap-northeast-1c' ]

# 作成先のsubnet_id
set :subnet_ids, [ 'subnet-********', 'subnet-********' ]

# 設定するキーペア名
set :key_pair_name, 'deploy-test'

# キーペアのプライベートキーファイル
set :private_key_file, 'deploy-test.pem'

# プライベートキーファイルの格納パス(ローカル側)
# ※事前に /home/deploy-user/deploy-test.pem をアップロードしておくこと
set :private_key_local_path, '/home/deploy-user/'

# 利用するセキュリティグループID
set :security_groups, [ 'sg-********', 'sg-********', 'sg-********' ]

# カーネルID
set :kernel_id_name, 'aki-********'

# タグ情報
set :module, 'deploy'
set :env, 'test'
set :version, '1.0.0'

# 初期ユーザアカウント情報(パスワードは新たに設定するもの)
set :def_account, 'ec2-user'
set :def_password, 'PassWord'

# 保守ユーザアカウント情報
set :user_account, 'deploy-user'
set :user_password, 'password'

## デプロイプロジェクトの共通設定 ------------------------------------------------

# デプロイするアプリケーション名
set :application, 'application name'

# Default value for :format is :pretty
set :format, :pretty

# ログ出力レベル
set :log_level, :info

# Default value for :pty is false
set :pty, true


## タスク初期化(Capistranoデフォルトのタスクを削除する)

framework_tasks = [:starting, :started, :updating, :updated, :publishing, :published, :finishing, :finished]
framework_tasks.each do |t|
  Rake::Task["deploy:#{t}"].clear
end
Rake::Task[:deploy].clear

## プロジェクト用デプロイタスク

namespace :deploy do

    ## デプロイ時の共通処理関数を定義

    def get_created_instances(info_type=nil) 
        # ラウンチされた新規EC2インスタンスの情報取得関数(デフォルトでインスタンスIDを返す)
        created_instances_list = "CREATED_INSTANCES"
        target_instances = []

        ec2 = AWS::EC2.new
        AWS.memoize do
            if File.exist?( File.expand_path("~") + "/#{created_instances_list}" ) then
                created_instances = File.read(File.expand_path("~") + "/#{created_instances_list}").chomp
                ci = created_instances.gsub(/(\[|\s|\])/, "").split(",")
                if info_type == "private_ip_address" then
                    target_instances = ec2.instances.select { |i| i.exists? && i.status == :running && ci.include?(i.id) }.map(&:private_ip_address)
                elsif info_type == "dns_name" then
                    target_instances = ec2.instances.select { |i| i.exists? && i.status == :running && ci.include?(i.id) }.map(&:dns_name)
                else
                    target_instances = ec2.instances.select { |i| i.exists? && i.status == :running && ci.include?(i.id) }.map(&:id)
                end
                  return target_instances
            else
                return nil
            end
        end
    end

    def set_ssh_options(current_task="init") 
        # デプロイ対象クライアント用のSSH接続情報を設定する(デフォルトは初回アクセス専用)
        target_instances = get_created_instances("dns_name")
        if current_task == "init" then
            key_file_path = fetch(:private_key_local_path) + fetch(:private_key_file)
            ssh_user = fetch(:def_account)
            role :first_time, target_instances
            target_instances.each { |host| 
                server host, user: ssh_user, roles: %w{first_time}, ssh_options: { keys: key_file_path, forward_agent: true }
            }
        else
            key_file_path = File.expand_path("~")+"/.ssh/#{fetch(:user_account)}_rsa"
            ssh_user = fetch(:user_account)
            role :web, target_instances
            target_instances.each { |host| 
                server host, user: ssh_user, roles: %w{web}, ssh_options: { keys: key_file_path, forward_agent: false }
            }
        end
    end

    ## デプロイタスク

    desc "Launch an EC2 instance to each availability zone different."
    task :create_instances do
        run_locally do
            ec2 = AWS::EC2.new

            created_instances = []
            cnt = 0
            while cnt < fetch(:instance_count) do
                if cnt.even? then
                    current_az = fetch(:availability_zones)[0]
                    current_sn = fetch(:subnet_ids)[0]
                else
                    current_az = fetch(:availability_zones)[1]
                    current_sn = fetch(:subnet_ids)[1]
                end
                info ": Instances launch start."
                i = ec2.instances.create(
                    :image_id => fetch(:ami_image_id),
                    :monitoring_enabled => false,
                    :availability_zone => current_az,
                    :subnet => current_sn,
                    :key_name => fetch(:key_pair_name),
                    :security_group_ids => fetch(:security_groups),
                    :disable_api_termination => false,
                    :instance_type => fetch(:ec2_instance_type),
                    :count => 1,
                    :associate_public_ip_address => true
                )
                sleep 3 while i.status == :pending
                i.tags["ModuleName"] = fetch(:module)
                i.tags["EnviromentName"] = fetch(:env)
                i.tags["Version"] = fetch(:version)
                i.tags["Name"] = [ fetch(:module), fetch(:env), format("%02d", cnt+1) ].join("-")
                created_instances << i.id
                cnt += 1
            end
            execute "echo -n #{created_instances} > ~/CREATED_INSTANCES"

        end
    end

    desc "Check the activation status of new instances."
    task :check do
        run_locally do
            def check_instance_status(instance_ids=[]) 
                ec2 = AWS::EC2.new
                AWS.memoize do
                    ec2info = ec2.client.describe_instance_status({"instance_ids" => instance_ids})
                    sys_status = ec2info.instance_status_set.map { |i| i.system_status.details[0].status }
                    ins_status = ec2info.instance_status_set.map { |i| i.instance_status.details[0].status }
                    status = sys_status + ins_status
                    return status.include?("initializing") ? false : true
                end
            end

            begin
                target_instances = get_created_instances("id")
                raise ": Is not still created all instances" if target_instances.length < fetch(:instance_count)
                if target_instances.length == fetch(:instance_count) then
                    # 全インスタンス起動後
                    chk_retry = 0

                    while !check_instance_status(target_instances) do
                        # インスタンスステータスが全てOKでない場合は15秒待つ(※30回リトライ)
                        info ": In preparation of the instance: Status check " + (chk_retry > 0 ? "(retry #{chk_retry + 1} times)" : "")
                        sleep 15
                        if check_instance_status(target_instances) then
                            break
                        end
                        chk_retry += 1
                        raise ": Instance is not still ready. Please run the task again after waiting for a while." if chk_retry >= 30
                    end

                    info ": Completed ready to deploy all instances."
                end
            rescue => e
                info e
                exit
            end
        end
    end

    desc "Does initial setting on new instances."
    task :init => :check do
        # SSHオプション設定
        set_ssh_options("init")

        run_locally do
            # 公開鍵認証用のキーペアを作成する
            target_dir = "~/.ssh"
            if !test "[ -f #{target_dir}/#{fetch(:user_account)}_rsa ]"
                if !test "[ -d #{target_dir} ]"
                    execute "mkdir -m 700 #{target_dir}"
                end
                execute "cd #{target_dir}; ssh-keygen -t rsa -N \"\" -f #{target_dir}/#{fetch(:user_account)}_rsa"
            end
            set :public_key_content, capture("cat #{target_dir}/#{fetch(:user_account)}_rsa.pub").chomp
            set :new_private_key_path, "#{target_dir}/#{fetch(:user_account)}_rsa"
        end

        on roles(:first_time) do
            # 初期設定(ユーザ作成時に.sshコンテナを自動作成する)
            if !test "[ -d /etc/skel/.ssh/ ]"
                execute :sudo, "mkdir -m 700 /etc/skel/.ssh/; sudo touch /etc/skel/.ssh/authorized_keys; sudo chmod 600 /etc/skel/.ssh/authorized_keys"
            end

            # 保守用の新規ユーザを作成
            is_user = capture(:sudo, "cut -d: -f1 /etc/passwd").chomp.gsub(/(\r\n)/, ",").split(",")
            if !is_user.include?(fetch(:user_account)) then
                execute :sudo, "useradd -G wheel #{fetch(:user_account)}"
                execute :sudo, "echo \"#{fetch(:user_account)}:#{fetch(:user_password)}\" | sudo chpasswd"
            end

            # 新規ユーザに公開鍵認証によるSSH権限を与える
            auth_keys = "/home/#{fetch(:user_account)}/.ssh/authorized_keys"
            if capture(:sudo, "cat #{auth_keys}").chomp != fetch(:public_key_content) then
                execute :sudo, "echo \"#{fetch(:public_key_content)}\" | sudo tee #{auth_keys}"
            end

            # 新インスタンスのホスト名を変更
            ec2 = AWS::EC2.new
            AWS.memoize do
                current_private_ip = capture(:sudo, "ifconfig | grep 'inet addr' | cut -d ':' -f 2 | awk 'NR==1 { print $1 }'").chomp
                instance_ids = ec2.instances.select { |i| i.exists? && i.status == :running && i.private_ip_address == current_private_ip }.map(&:id)
                host_basename = ec2.instances[instance_ids[0]].tags["Name"]
                if capture(:sudo, "hostname").chomp != host_basename.chomp then
                    execute :sudo, "echo \"#{host_basename}\" | sudo tee /proc/sys/kernel/hostname"
                    execute :sudo, "sed -i 's/\\(^HOSTNAME=\\).*/\\1#{host_basename}/' /etc/sysconfig/network"
                    execute :sudo, "hostname #{host_basename}"
                end
            end

            # デフォルトユーザ「ec2-user」にパスワードを設定し、sudo権限を剥奪
            # 保守用の新規ユーザにsudo権限を付与
            is_passwd = capture(:sudo, "cut -d: -f1,2 /etc/shadow").chomp.gsub(/(\r\n)/, ',').split(',')
            if is_passwd.include?("ec2-user:!!") then
                execute :sudo, "echo \"ec2-user:#{fetch(:def_password)}\" | sudo chpasswd"
            end
            execute :sudo, "sed -i s/ec2-user/#{fetch(:user_account)}/g /etc/sudoers.d/cloud-init"

            info ": Init task complete."
        end
    end

    desc "Update the yum packages."
    task :update_packages =>:init do
        # SSHオプション設定
        set_ssh_options("update_packages")

        on roles(:web) do
            info ": Updating yum packages."
            deploy_log = capture(:sudo, "yum -y update")
            pkg_updated = deploy_log.each_line.to_a
            info ": " + pkg_updated.first.strip
            info ": " + pkg_updated.last.strip

            info ": Deploy task all completed."
            #info deploy_log
        end
    end

    after :create_instances, :update_packages

    desc "Deploy the application."
    task :main do
        on roles(:web) do
            # 未定義
        end
    end
end

今回のデプロイでは異なるタスク間で共通的に行われる作成したEC2インスタンスの特定の情報を取得する処理や、SSHアクセス情報を設定する処理などを関数化しています。SSHオプションの設定については初回アクセスと次回以降のアクセスにてroleを変えて設定しています2。また、タスクのafterメソッドを使って、create_instancesタスクを実行するとupdate_packagesタスクまで全自動でデプロイが実行されるようにしてみました3

最後に、EC2インスタンス作成時に利用するキーペアのプライベートキーファイルをデプロイユーザのホームディレクトリにSCP等でアップロードしておきます。 これで、準備完了です。

それでは、実際にデプロイを行ってみます。 デプロイタスクを起動する時は、プロジェクトをインストールしたパスで行います。

$ cd ~/cap3-project
$ cap test deploy:create_instances

デプロイ結果のログは下記の通りです。

INFO: Instances launch start.
INFO: Instances launch start.
INFO[be335092] Running /usr/bin/env echo -n ["i-4dd6ec4b", "i-62ae0a7b"] > ~/CREATED_INSTANCES on localhost
INFO[be335092] Finished in 0.003 seconds with exit status 0 (successful).
INFO: In preparation of the instance: Status check
INFO: In preparation of the instance: Status check (retry 2 times)
INFO: In preparation of the instance: Status check (retry 3 times)
INFO: In preparation of the instance: Status check (retry 4 times)
INFO: In preparation of the instance: Status check (retry 5 times)
INFO: In preparation of the instance: Status check (retry 6 times)
INFO: In preparation of the instance: Status check (retry 7 times)
INFO: In preparation of the instance: Status check (retry 8 times)
INFO: In preparation of the instance: Status check (retry 9 times)
INFO: In preparation of the instance: Status check (retry 10 times)
INFO: In preparation of the instance: Status check (retry 11 times)
INFO: In preparation of the instance: Status check (retry 12 times)
INFO: In preparation of the instance: Status check (retry 13 times)
INFO: In preparation of the instance: Status check (retry 14 times)
INFO: Completed ready to deploy all instances.
INFO[35b9f350] Running /usr/bin/env sudo mkdir -m 700 /etc/skel/.ssh/; sudo touch /etc/skel/.ssh/authorized_keys; sudo chmod 600 /etc/skel/.ssh/authorized_keys on ec2-54-178-167-106.ap-northeast-1.compute.amazonaws.com
INFO[35b9f350] Finished in 0.069 seconds with exit status 0 (successful).
INFO[6443cc90] Running /usr/bin/env sudo useradd -G wheel deploy-user on ec2-54-178-167-106.ap-northeast-1.compute.amazonaws.com
INFO[6443cc90] Finished in 0.222 seconds with exit status 0 (successful).
INFO[b74993eb] Running /usr/bin/env sudo echo "deploy-user:password" | sudo chpasswd on ec2-54-178-167-106.ap-northeast-1.compute.amazonaws.com
INFO[b74993eb] Finished in 0.070 seconds with exit status 0 (successful).
INFO[a3e11615] Running /usr/bin/env sudo echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDgQ31X0qXm/eHXZCIecjv57C66cZ4ikLdprDhHZs+KV5/vK0B+/47cZCXaT7UEHdI+Bm3jNTPJoRE8iPzpkWB9L5Ks13tB7yJ5DGEIbFRe8d3kTa6Uwrj1HpL+i8hSZ7Bzbc4JvF5YULj97NfVAmpNvAqxF1mRWeuzcmevnsVNJ1nF6ePysNjiWmboepWl+MvIJ8xXLYPzrw8mO1kg7WEB0QxqGN5OsVZjjbmEMLliJ+xbOGfxI50FEa+k2445Y3nynBD9krx/1wayurEVn2t8jKWDn6XLSUJ41Ep43QkwFibwtcVBsfDSPIHVm6S3k9RzaAQWpN6qSrUiabk0yAOp deploy-user@devlab-deploy01" | sudo tee /home/deploy-user/.ssh/authorized_keys on ec2-54-178-167-106.ap-northeast-1.compute.amazonaws.com
INFO[a3e11615] Finished in 0.035 seconds with exit status 0 (successful).
INFO[d2f6241f] Running /usr/bin/env sudo echo "deploy-test-02" | sudo tee /proc/sys/kernel/hostname on ec2-54-178-167-106.ap-northeast-1.compute.amazonaws.com
INFO[d2f6241f] Finished in 0.024 seconds with exit status 0 (successful).
INFO[93fa8aa7] Running /usr/bin/env sudo sed -i 's/\(^HOSTNAME=\).*/\1deploy-test-02/' /etc/sysconfig/network on ec2-54-178-167-106.ap-northeast-1.compute.amazonaws.com
INFO[93fa8aa7] Finished in 0.021 seconds with exit status 0 (successful).
INFO[bd5146d3] Running /usr/bin/env sudo hostname deploy-test-02 on ec2-54-178-167-106.ap-northeast-1.compute.amazonaws.com
INFO[bd5146d3] Finished in 0.018 seconds with exit status 0 (successful).
INFO[e8a45be7] Running /usr/bin/env sudo echo "ec2-user:PassWord" | sudo chpasswd on ec2-54-178-167-106.ap-northeast-1.compute.amazonaws.com
INFO[e8a45be7] Finished in 0.116 seconds with exit status 0 (successful).
INFO[e6bbbbda] Running /usr/bin/env sudo sed -i s/ec2-user/deploy-user/g /etc/sudoers.d/cloud-init on ec2-54-178-167-106.ap-northeast-1.compute.amazonaws.com
INFO[e6bbbbda] Finished in 0.019 seconds with exit status 0 (successful).
INFO: Init task complete.
INFO[e078eb47] Running /usr/bin/env sudo mkdir -m 700 /etc/skel/.ssh/; sudo touch /etc/skel/.ssh/authorized_keys; sudo chmod 600 /etc/skel/.ssh/authorized_keys on ec2-54-178-145-90.ap-northeast-1.compute.amazonaws.com
INFO[e078eb47] Finished in 0.065 seconds with exit status 0 (successful).
INFO[ded515dc] Running /usr/bin/env sudo useradd -G wheel deploy-user on ec2-54-178-145-90.ap-northeast-1.compute.amazonaws.com
INFO[ded515dc] Finished in 0.323 seconds with exit status 0 (successful).
INFO[8927f2f0] Running /usr/bin/env sudo echo "deploy-user:password" | sudo chpasswd on ec2-54-178-145-90.ap-northeast-1.compute.amazonaws.com
INFO[8927f2f0] Finished in 0.069 seconds with exit status 0 (successful).
INFO[51ed8060] Running /usr/bin/env sudo echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDgQ31X0qXm/eHXZCIecjv57C66cZ4ikLdprDhHZs+KV5/vK0B+/47cZCXaT7UEHdI+Bm3jNTPJoRE8iPzpkWB9L5Ks13tB7yJ5DGEIbFRe8d3kTa6Uwrj1HpL+i8hSZ7Bzbc4JvF5YULj97NfVAmpNvAqxF1mRWeuzcmevnsVNJ1nF6ePysNjiWmboepWl+MvIJ8xXLYPzrw8mO1kg7WEB0QxqGN5OsVZjjbmEMLliJ+xbOGfxI50FEa+k2445Y3nynBD9krx/1wayurEVn2t8jKWDn6XLSUJ41Ep43QkwFibwtcVBsfDSPIHVm6S3k9RzaAQWpN6qSrUiabk0yAOp deploy-user@devlab-deploy01" | sudo tee /home/deploy-user/.ssh/authorized_keys on ec2-54-178-145-90.ap-northeast-1.compute.amazonaws.com
INFO[51ed8060] Finished in 0.025 seconds with exit status 0 (successful).
INFO[8c5dc231] Running /usr/bin/env sudo echo "deploy-test-01" | sudo tee /proc/sys/kernel/hostname on ec2-54-178-145-90.ap-northeast-1.compute.amazonaws.com
INFO[8c5dc231] Finished in 0.018 seconds with exit status 0 (successful).
INFO[5fc4603c] Running /usr/bin/env sudo sed -i 's/\(^HOSTNAME=\).*/\1deploy-test-01/' /etc/sysconfig/network on ec2-54-178-145-90.ap-northeast-1.compute.amazonaws.com
INFO[5fc4603c] Finished in 0.033 seconds with exit status 0 (successful).
INFO[9cdfbb66] Running /usr/bin/env sudo hostname deploy-test-01 on ec2-54-178-145-90.ap-northeast-1.compute.amazonaws.com
INFO[9cdfbb66] Finished in 0.015 seconds with exit status 0 (successful).
INFO[de94f658] Running /usr/bin/env sudo echo "ec2-user:PassWord" | sudo chpasswd on ec2-54-178-145-90.ap-northeast-1.compute.amazonaws.com
INFO[de94f658] Finished in 0.052 seconds with exit status 0 (successful).
INFO[7ae1cd6c] Running /usr/bin/env sudo sed -i s/ec2-user/deploy-user/g /etc/sudoers.d/cloud-init on ec2-54-178-145-90.ap-northeast-1.compute.amazonaws.com
INFO[7ae1cd6c] Finished in 0.046 seconds with exit status 0 (successful).
INFO: Init task complete.
INFO: Updating yum packages.
INFO: Updating yum packages.
INFO: Loaded plugins: priorities, update-motd, upgrade-helper
INFO: Complete!
INFO: Deploy task all completed.
INFO: Loaded plugins: priorities, update-motd, upgrade-helper
INFO: Complete!
INFO: Deploy task all completed.

デプロイが完了しました。

Capistrano3で新規EC2インスタンスをデプロイした後、特に定常的にデプロイを行わない場合は、デプロイサーバのインスタンスは停止しておくか、AMIを取ってターミネートしておくという運用が良いかと。デプロイサーバはデプロイする時だけ使えれば良いので、このインスタンスに費用が発生するのは無駄になります。


  1. これはRVM経由でインストールする場合の一例です。RubyやCapistrano3などのインストール方法は色んな方法があるので、用途によって変更してください。 

  2. roleを変えずにSSHオプションを定義すると、同roleに異なるユーザとしてのSSHアクセスが追加されて行くため、2回目以降のSSHにもアクセスできなくなった初回SSHの情報が残り、無駄にSSH接続を行いタスクがフリーズしてしまいます。 

  3. 作成したEC2インスタンスの起動チェックのタスクで15秒×30回のウェイト間にインスタンスのステータスが全OKにならなかった場合はそこでタスクは中断します。その場合は、deploy:update_packagesタスクから再デプロイすることでリトライ可能です。