Railsアプリケーションを動かすサーバ作ろうとすると、
- Rubyのセットアップ
- Rackサーバ(PassengerとかUnicornとか)のセットアップ
- Webサーバ(ApacheとかNingxとか)のセットアップ
- DBのセットアップ
- アプリケーションのデプロイ用設定ファイル作成(Capistranoとか)
といった、アプリケーションの開発自体とは関係ない諸々の作業が必要な訳で、そんな作業しなくてもデプロイ以降の作業をお任せできるHerokuはとても便利。
そんなHerokuのようなPaaSをEC2上に立ててみようとdokkuを使ってオレオレHeroku環境作ってみる。(そんなの構築しなくてもAWSにはBeanstalkがあるじゃないか?というツッコミもあるけど)
dokkuは内部でdockerを使用しており、docker自体は、LXC(Linux Container)というLinuxのコンテナ技術を使用して(最近LXC非依存になったけど)サーバ上に独立したユーザー空間を確保しその中で仮想OSのプロセスやネットワークを動作させる仮想環境。
コンテナベースの仮想化を行うことで、1つのカーネル上で複数のコンテナをユーザープロセスを分けて運用できる点で、Virtual Boxみたいなゲスト用のカーネルが別に立ち上がることが無いのでオーバーヘッドが少なくすごく軽量に動作する。(確かHerokuのdynoも同様のLXCベースのアーキテクチャを採用してるんじゃなかろうか。)
AWSのEC2上にdokkuをセットアップ
dokkuのREADMEにUbuntu 13.10推奨とあったのでAmazon Linuxではなく64bit版のUbuntu Server 13.10を選択してインスタンスを起動する。続いて以下のコマンドでdokkuをインストールする。
$ wget -qO- https://raw.github.com/progrium/dokku/v0.2.1/bootstrap.sh | sudo DOKKU_TAG=v0.2.1 bash ...
↑のスクリプトで、dockerのインストールも一緒に行われ、dokkuユーザが作成される。
ドメインの設定
/home/dokku/VHOST にドメインを設定する(デフォでホスト名が設定されてる)。もしファイルが存在しない場合は手動で作成する。今回はdokku.haw.bizと設定。
今後デプロイするアプリケーションのURLにここで設定したドメインが使われる。
(http://アプリケーション名.dokku.haw.biz/みたいに)
尚、立ち上げたインスタンスのIPに対してここで設定したドメインでアクセスできるように別途Route53とかで名前解決できるようにしておく。
鍵の設定
続いてデプロイする際に鍵認証が発生するので、公開鍵をdokkuのサーバに登録する。デプロイマシンで以下のコマンドを実行して鍵を登録する。
$ cat ~/.ssh/id_rsa.pub | ssh dokku.haw.biz -l ubuntu -i dokkuのインスタンスにアクセスする際の鍵 "sudo sshcommand acl-add dokku oreore"
成功すると/home/dokku/.ssh/authrized_keysにデータが追加される。
以上で環境の準備は終わり。意外とあっさりできる。続いていよいよデプロイ。
node.jsアプリのデプロイ
Hedokuで公開されてるnode.jsのアプリをデプロイしてみる。手元のマシンで
$ git clone https://github.com/heroku/node-js-sample.git Cloning into 'node-js-sample'... ...
続いて、push先にdokkuのサーバを指定
$ cd node-js-sample $ git remote add oreore dokku@dokku.haw.biz:node-js-sample
そしていよいよpush!
$ git push oreore master Counting objects: 319, done. Delta compression using up to 4 threads. Compressing objects: 100% (272/272), done. Writing objects: 100% (319/319), 201.33 KiB | 0 bytes/s, done. Total 319 (delta 19), reused 319 (delta 19) -----> Building node-js-sample ... Node.js app detected -----> Resolving engine versions Using Node.js version: 0.10.21 Using npm version: 1.3.11 -----> Fetching Node.js binaries -----> Vendoring node into slug -----> Installing dependencies with npm ... npnで依存ライブラリのインストール ... -----> Building runtime environment -----> Discovering process types Procfile declares types -> web -----> Releasing node-js-sample ... -----> Deploying node-js-sample ... -----> Cleaning up ... =====> Application deployed: http://node-js-sample.dokku.haw.biz To dokku@dokku.haw.biz:node-js-sample * [new branch] master -> master $
とアプリが起動する。表示されたURLにアクセスすると「Hello World!」画面が表示される。
(デプロイするとdokkuのサーバの/home/dokku/以下にデプロイしたアプリのgitリポジトリができてる。)
dokku側はこのdeployの際にnode.jsやnpnといったツールをインストールする。今回はnode.jsだったけど、実際にビルドできる言語は
でサポートされてる言語になる。RubyやJava、PHPといったメジャーどころにはしっかり対応してる。
Railsアプリケーションのデプロイ
node.jsのアプリケーションだけだと味気ないのでRailsのアプリケーションもデプロイしてみる。アプリは同じくHerokuのサンプルを利用。
PostgreSQL Pluginのインストール
RailsアプリではDBのインストールが必要になる。dokkuでこういったDBや他のミドルウェアを使いたい場合は、別途公開されているPluginをインストールすることになる。
今回はPostgreSQL Pluginを利用する。Pluginのインストール自体はdokkuのインスタンス上で行う。インストール自体は簡単で以下のステップで実行するだけ。
cd /var/lib/dokku/plugins
$ git clone https://github.com/Kloadut/dokku-pg-plugin postgresql
$ dokku plugins-install
...
Successfully built 95a893eae17b
$
これ以降は、手元のマシンで実行できる。まず、DBの作成
$ ssh dokku@dokku.haw.biz postgresql:create rails-sample-pg
-----> PostgreSQL container created: postgresql/rails-sample-pg
Host: 172.17.42.1
Port: 49168
User: 'root'
Password: '3bGybchOvHjDmC6I'
Database: 'db'
Url: 'postgres://root:3bGybchOvHjDmC6I@172.17.42.1:49168/db'
$
実行するとDBのコンテナが作成されアクセス情報が返される。
ちなみにpostgresql:createで作成したDBはそれぞれ別のユーザープロセスとして動作するようになる。↑のrails-sample-pg以外のDB例えばrails-sample-pg2というDBを作成すると2つのPostgreSQLプロセスが起動している状態になる。
Railsアプリのデプロイ
サンプルアプリを取ってきてpushする。
$ git clone https://github.com/heroku/ruby-rails-sample.git
...
$ cd ruby-rails-sample
$ git remote add oreore dokku@dokku.haw.biz:ruby-rails-sample
$ git push oreore master
Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 372 bytes | 0 bytes/s, done.
Total 4 (delta 3), reused 0 (delta 0)
-----> Building ruby-rails-sample ...
Ruby app detected
-----> Compiling Ruby/Rails
-----> Using Ruby version: ruby-2.1.1
-----> Installing dependencies using Bundler version 1.3.2
Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin --deployment
...
gemのインストール処理
...
Your bundle is complete! It was installed into ./vendor/bundle
Bundle completed (0.64s)
Cleaning up the bundler cache.
-----> Writing config/database.yml to read from DATABASE_URL
-----> Preparing app for Rails asset pipeline
Running: rake assets:precompile
Asset precompilation completed (2.45s)
Cleaning assets
-----> Discovering process types
Procfile declares types -> web
Default process types for Ruby -> rake, console, web, worker
-----> Releasing ruby-rails-sample ...
-----> Deploying ruby-rails-sample ...
-----> Cleaning up ...
=====> Application deployed:
http://ruby-rails-sample.dokku.haw.biz
To dokku@dokku.haw.biz:ruby-rails-sample
7dfd643..37601b0 master -> master
$
このままではさっき作ったDBとのリンクはできてないので、続いて、以下のコマンドでRailsアプリと接続先のDBのコンテナをリンクする。(なのでdatabase.ymlを編集する必要は無い)
$ ssh dokku@dokku.haw.biz postgresql:link ruby-rails-sample rails-sample-pg
-----> Creating /home/dokku/ruby-rails-sample/ENV
-----> Setting config vars and restarting ruby-rails-sample
DATABASE_URL: postgres://root:3bGybchOvHjDmC6I@172.17.42.1:49168/db
-----> Releasing ruby-rails-sample ...
-----> Release complete!
-----> Deploying ruby-rails-sample ...
-----> Deploy complete!
-----> ruby-rails-sample linked to postgresql/rails-sample-pg database
これで完成! pushした際に表示されるURLアクセスするとHello World画面が表示される。
dokkuのインスタンス上ではさっきのnode.jsのサンプルとRailsのサンプルとそのDBの計3つのコンテナがそれぞれ別のユーザー空間で動作している。
少しスペックの良いEC2のインスタンスを1台立てて、その上で複数のサイトをVPSみたいに運用するような、誰でもVPSビジネスができる環境がわりと簡単にできつつある。(まぁサービスとして提供するにはクリアすべき課題は多いと思うけど)