ちょっと話題の記事

オートスケール時のデプロイを User Data と Capistrano を使って行う(BootStrap パターン)

2014.07.16

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Auto Scaling を使った構成の場合、EC2 へのデプロイはどうやっているでしょうか?

AWS を使ってる方はご存知の方も多いと思いますが、EC2 には User Data という仕組みがあります。
User Data は、インスタンス起動時にタスクやスクリプトを実行する仕組みです。
今回この User Data を使って、自分自身のインスタンスから最新のソースを GitHub から取得してデプロイする方法についてご紹介したいと思います。

図で表すと以下のイメージですかね。

Untitled

ssh localhost?

デプロイツールには Capistrano を使いますが、Capistrano は、デプロイ対象のサーバーに対してまず ssh で login を行います。 その後、サーバー上でデプロイ対象のコードの取得や、サービスの再起動をしたりしますが、 AutoScaling は自動でインスタンスが起動するので、どうやってデプロイさせるかがポイントです。
トリガーなどで外のインスタンスからデプロイしてもいいのですが、なるべく疎結合にすべきだと思うので、 自分自身(localhost)からデプロイを行うようにしてみます。

アプリケーション実行ユーザとして、deploy という名前のユーザを作って、localhost から ssh 出来るようにします。

# useradd -m deploy
# su - deploy
$ ssh-keygen
$ cd .ssh && mv id_rsa.pub authorized_keys
$ chmod 600 authorized_keys

上記の設定が済んだら、localhost にログイン出来るか試してみましょう。

[ec2-user@ip-xxx-xxx-xxx-xxx ~]$ ssh localhost
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ECDSA key fingerprint is xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.
Last login: Tue Jul  8 13:05:16 2014 from localhost

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2014.03-release-notes/
[ec2-user@ip-xxx-xxx-xxx-xxx ~]$

フィンガープリントの確認後、無事ログイン出来ましたね。

しかしここで 1 点注意点があります。EC2 は AMI から起動すると毎回ホスト鍵が変わるため、Capistrano からログインを行う際に、再度フィンガープリントの確認が対話的に行われてしまい、デプロイが上手くいかないのです。

これを解決するために、~/.ssh/config に以下を追記しておきましょう。

Host *
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null

これでフィンガープリントのチェックを行わなくなります。

Capistrano

デプロイするサンプルは Rails のアプリケーションです。 Gemfile の一部を抜粋すると、以下の通りです。

source 'https://rubygems.org'
gem 'rails', '4.1.2'

group :development do
  gem 'capistrano', require: false
  gem 'capistrano-rbenv', require: false
  gem 'capistrano-bundler', require: false
  gem 'capistrano-rails', require: false
end

localhost からのデプロイ用に config/deploy 以下に local.rb というファイルを作りました。

# config/deploy/local.rb
server 'localhost', user: 'deploy', roles: %i(web app db)

set :branch, 'master'
set :rails_env, :production

そして、EC2上のデプロイ実行用のコードとアプリケーション実行元の場所はそれぞれ以下のようにしました。

  • デプロイ実行用のコード: /home/deploy/my_rails_app
  • アプリケーション実行元(デプロイ先): /data/my_rails_app

EC2 上からデプロイできる事を確認しておきましょう。

$ cd ~/my_rails_app
$ bundle install --path vendor/bundle --without production staging
$ bundle exec local deploy
...
INFO [b47eea5f] Finished in 0.037 seconds with exit status 0 (successful).

デプロイ用シェル

デプロイの確認が上手く行ったら、User Data から呼び出すシェルを作成します。
折角なので、staging と production をパラメータで切り替えられるようにしておきます。 *1

#!/bin/bash
#
# /data/bin/startup.sh
#
#######################

app_root=/data/my_rails_app/current/
source_path=$1
rails_env=$2

cd $source_path

git fetch --all
git reset --hard origin/master

bundle install --path vendor/bundle --without production staging --quiet -j8

bundle exec cap local-$rails_env deploy

Capistrano のファイルも、以下のように production と staging 用で分けました。 *2

local-production.rb

# config/deploy/local-procution.rb
server 'localhost', user: 'deploy', roles: %i(web app db)

set :branch, 'master'
set :rails_env, :production

local-staging.rb

# config/deploy/local-staging.rb
server 'localhost', user: 'deploy', roles: %i(web app db)

set :branch, 'master'
set :rails_env, :staging

これによって以下の指定でデプロイ出来るようになりました。

$ /data/bin/startup.sh /home/deploy/my_rails_app/ production|staging

User Data からシェルを呼び出す

マネージメントコンソールを開いて、User Data を指定します。

140709-0002

2 行目はログ出力用の指定です。
User Data は root ユーザとして実行されるので、su で deploy ユーザを指定しています。

実行結果を見てみる

インスタンスを AMI から起動したら、実行結果を確認してみましょう。
ログは、/var/log/user-data.log に書かれています。

+ su - deploy /data/bin/startup.sh /home/deploy/my_rails_app/ production
...
INFO[9fdf606a] Finished in 0.041 seconds with exit status 0 (successful).

無事デプロイが終わったようです!

AutoScaling で実行するには?

Auto Scaling で User Data を実行するには、launch config の作成時に指定が必要です。
以下は、aws cli を使って指定する例になります。

$ aws autoscaling create-launch-configuration \
> --launch-configuration-name "my-lc" \
> --image-id "ami-xxxxxxxx" \
> --user-data "/path/to/user-data.txt" \
> --instance-type "t2.micro"

まとめ

User Data を使って自動でデプロイする方法を紹介しました。一般的に BootStrap パターンと呼ばれたりします。
要点を掻い摘んで紹介しましたが、実際には Web サーバの設定や AMI の作成など他の準備も必要です。
こちらで紹介したパターン以外にも、稼働している EC2 とは別で新しいインスタンス群を用意して、DNS の向き先を切り替えるパターンなどもあります。 実際に production 環境で使う際は、更新しているソースが多かったりすると、デプロイに時間が掛かったりするので、その辺りは工夫が必要かと思います。

脚注

  1. こうすることで AMI も 1 つで、共用出来ますね。
  2. 事前に Rails アプリケーションに staging 環境を追加しておく必要があります。