AWS OpsWorks 使ってRailsアプリを動作させる環境作ってみた。
Stackを作成
まず、Stackを作成する。StackはEC2のインスタンスや他のAWSリソースのコンテナ。
Layerを追加
続いてStackにLayerを追加する。Stackには複数のLayerが定義可能。基本的にWeb ServerとかApplication ServerとかDBとか役割ごとにLayerを切ってくようになる。現状、OpsWorksがデフォで提供しているLayerは↓
- HAProxy
- Static Web Server(Nginx)
- Rails App Server(Apache+Passenger or Nginx+Unicorn)
- PHP App Server(Apache+PHP)
- Node.js App Server
- MySQL
- Memcached
- Ganglia
今回は↑のRails App Serverを利用。
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の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だとさらにツラそう。
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リンクを押すとインスタンスが起動する。
EC2のインスタンスが起動してからChefのレシピが順次適用されてくので、普通にEC2のインスタンスをlaunchするのに比べると結構時間かかる。
Statusがonlineになると使える状態になり、Public IPのリンククリックすると起動したRailsアプリにアクセスできる。EC2のインスタンスにログインすることなく、アプリ公開までできちゃうのは便利〜。
ちなみに起動されるインスタンスのroot deviceはinstance storeでEBSベースではない。なので永続化が必要なデータに関しては、予めLayerの設定でEBSをマウントするようにして、そのEBSボリュームにデータを格納するよう設定しておく必要がある。
↑はシンプルな構成だけど、実際の運用環境作る場合は、Chefのレシピもカスタマイズする必要があると思う。あとOpsWorksを利用することでChefのプラットフォーム部分を意識しなくてすむ(Chef-SoloやChef-Serverの設定とか本質とは関係ないどーでもいいところを考えなくて済む)のでレシピを作るのに集中できるのは地味に便利。