Develop with pleasure!

福岡でCloudとかBlockchainとか。

OpsWorksでRailsな環境作ってみた。

AWS OpsWorks 使ってRailsアプリを動作させる環境作ってみた。

Stackを作成

まず、Stackを作成する。StackはEC2のインスタンスや他のAWSリソースのコンテナ。
f:id:techmedia-think:20130409171621p:plain,w600

Layerを追加

続いてStackにLayerを追加する。Stackには複数のLayerが定義可能。基本的にWeb ServerとかApplication ServerとかDBとか役割ごとにLayerを切ってくようになる。現状、OpsWorksがデフォで提供しているLayerは↓

今回は↑のRails App Serverを利用。

f:id:techmedia-think:20130409175837p:plain,w600

Layerを登録すると各Layerの画面でそのLayerで適用されるBuilt-in Chef recipesや(今回は特に用意してないけど)Custom Chef recipesが確認できる。OpsWorksはインスタンスを起動するとインスタンス内部でChef-Soloが動作しBuilt-in Chef recipes、Custom Chef recipesで設定されてるレシピが適用される。
(Build-in Chef recipesで定義されるChefのレシピの実装はOpsWorksが提供してるaws/opsworks-cookbooks · GitHub で確認できる。)

アプリケーションの登録

続いてデプロイするアプリケーションを登録する。RailsアプリのリポジトリのURLとリポジトリからソース取得する際に必要なSSHの鍵を設定する。

f:id:techmedia-think:20130409182340p:plain,w600

レシピの設定値のカスタマイズ

↑のRailsのLayerを適用するとデフォで使われるDBのAdapterがMySQLなので、DBにsqlite3を使う場合はsqlite3を使うようレシピのattributesを設定する必要がある。この設定はStackの設定画面のCustom Chef JSONという項目で設定できる。今回設定したのは↓

{
  "deploy": {
    "sample": { ← アプリケーション名を設定 
      "database": {
        "adapter": "sqlite3"
      },
      "migrate": true ← trueにすることでデプロイ時にdb:migrateが実行される
    }
  }
}

↑の設定はChefのattributesに↓のように定義したのと同様の設定になる。

default[:deploy][:sample][:database][:adapter] = 'sqlite3'
default[:deploy][:sample][:migrate] = true

この設定ってLayerでできたほうが良いんじゃないの?と思うけど、現状Stackにしか設定できない。

インスタンスの追加

↑で定義したLayerにインスタンを追加する。現状ではマイクロインスタンが使えないのが残念‥
まぁでもm1.smallでもChefのレシピの適用に結構時間かかるからt1.microだとさらにツラそう。
f:id:techmedia-think:20130409221329p:plain,w600

Railsアプリのデプロイ時assets:precompileの実行

↑で一応Railsアプリをデプロイして起動する環境自体はできあがってるんだけど、この状態だとassets:precompile タスクが実行されてない状態なので、通常のRailsのproduction環境だとassetsリソースへのアクセスができない。なので、デプロイ後にassets:precompileのRakeタスクを実行する必要がある。
OpsWorksが提供してるRailsのデプロイ用のレシピを見るとデプロイするRailsプロジェクトのソースにdeploy/before_migrate.rbというファイルを配置しておくと、migrateタスクの実行前にbefore_migrate.rbに記述されてる処理が実行される。なので、before_migrate.rbに↓のような処理を書いておくと、migrateタスクが実行される前にassets:precompileタスクが実行される。

Chef::Log.info("Running deploy/before_migrate.rb in myapp app...")
current_release = release_path

execute "rake assets:precompile" do
  cwd current_release
  command "bundle exec rake assets:precompile"
  environment "RAILS_ENV" => 'production'
end

インスタンス起動

インスタンスを追加したのでいよいよ実際に定義した構成でRailsアプリのインスタンスを起動してみる。起動するインスタンスのstartリンクを押すとインスタンスが起動する。

f:id:techmedia-think:20130409221544p:plain

EC2のインスタンスが起動してからChefのレシピが順次適用されてくので、普通にEC2のインスタンスをlaunchするのに比べると結構時間かかる。

f:id:techmedia-think:20130410140702p:plain,w600

Statusがonlineになると使える状態になり、Public IPのリンククリックすると起動したRailsアプリにアクセスできる。EC2のインスタンスにログインすることなく、アプリ公開までできちゃうのは便利〜。
ちなみに起動されるインスタンスのroot deviceはinstance storeでEBSベースではない。なので永続化が必要なデータに関しては、予めLayerの設定でEBSをマウントするようにして、そのEBSボリュームにデータを格納するよう設定しておく必要がある。

↑はシンプルな構成だけど、実際の運用環境作る場合は、Chefのレシピもカスタマイズする必要があると思う。あとOpsWorksを利用することでChefのプラットフォーム部分を意識しなくてすむ(Chef-SoloやChef-Serverの設定とか本質とは関係ないどーでもいいところを考えなくて済む)のでレシピを作るのに集中できるのは地味に便利。