Cloud Foundry V2系サービス(Cloudn PaaS, Bluemix)にRailsアプリをデプロイする

NTT Communicationsが提供する[Cloudn PaaS](http://www.ntt.com/cloudn/data/paas.html) や、IBMの提供する[Bluemix](http://www.ibm.com/developerworks/jp/bluemix/)は、どちらもCloud FoundryをベースにしたPaaSです。
Cloud Foundryは、アンチベンダーロックインを掲げ、同じCFであれば同じように使えるという点をウリにしています。であれば、Cloudn PaaSも、Bluemixも同じように利用できるはず！
今回はRailsアプリをCloudn PaaSとBluemix、それぞれにデプロイして本当に両者の互換性が保たれているのか、確認してみます。

## Railsアプリの準備

今回はrails newした後に、scaffoldと必要な設定をしただけの、シンプルなRailsアプリを使って実験します。
バージョンは、これを執筆している時点で最新のものを利用します。

````
Rails version: 4.1.4
Ruby version: 2.1.1
````

### scaffoldでベースを作る
````
rails new cf-rails-sample
cd cf-rails-sample
rails g scaffold item name:string description:string
rake db:migrate
rails s
````
![Cursor_と_CfRailsTest.jpg](https://qiita-image-store.s3.amazonaws.com/0/17840/60506a0f-5477-5564-7e33-e938c1dd3ed5.jpeg "Cursor_と_CfRailsTest.jpg")

よくある画面が出来ました。

### Gemfileを編集する
今回はMySQLを使いたいので、次の行をGemfileに追加します。

````
group :production do
  gem 'mysql2'
  gem 'rails_12factor'
  gem 'rails_stdout_logging'
end
````

rails_12factorは、元々Heroku向けの調整を行うgemですが、Cloud Foundryでも利用できるので入れておきます。また、cf logsコマンドでRailsのログを取得できるように、rails_stdout_loggingも入れておきます

編集が終わったらbundle updateしておきます

````
bundle update
````

### .cfignoreの追加
.cfignoreファイルを作成し、以下の内容を記述します。

````
vendor/bundle
````

このファイルに記述されたファイル/ディレクトリは、cfコマンドでpushする際に無視されます。
ローカルで動かす際にbundle install --path=vendor/bundleされる方は多いと思いますが、デプロイ時には改めてCF内部でbundle installされるので、このディレクトリをアップロードしても意味がありません。なので、アップロードを高速に行うためにも、この記述の追加をお勧めします。(必須ではありません)

## Cloudn PaaSの準備
![Cursor_と_クラウド・エヌ（PaaS）｜NTT_Com_法人のお客さま.jpg](https://qiita-image-store.s3.amazonaws.com/0/17840/48a776d3-e91c-ceb8-742c-89f909b2469b.jpeg "Cursor_と_クラウド・エヌ（PaaS）｜NTT_Com_法人のお客さま.jpg")


Railsの準備ができたら、Cloudn PaaSの準備を行います。
CloudnやCloudn PaaSの申し込みは、ここでは解説しません。[マニュアル等](http://info.cloudn-service.com/documents/JP/ejp/paas-v2/prepare/index.html)を参考に申し込みしておいてください。

### cfコマンドのインストール

Cloudn PaaSでは独自コマンドのgudを提供しているようですが、今回は使用しません。代わりに、Cloud Foundry標準のcfコマンドをインストールしておきます。

[cfコマンドのREADMEにあるDownload](https://github.com/cloudfoundry/cli)から、自分の環境用のcfをダウンロードしてインストールしておきます。

### Cloudn PaaSへのログイン

cfコマンドでCloudn PaaSへログインします。
Cloudn PaaSの場合、APIアクセスキーとシークレットキーがそのままPaaSのログインユーザー、パスワードになります。APIアクセスキー画面で取得しておきます。

![Cursor_と_APIアクセスキー・秘密鍵管理___ポータルサイト.jpg](https://qiita-image-store.s3.amazonaws.com/0/17840/b9c1f823-d348-24c5-b184-990b673d2b11.jpeg "Cursor_と_APIアクセスキー・秘密鍵管理___ポータルサイト.jpg")


そしてcf api、cf loginコマンドでログイン。

````bash
$ cf api api.paas.jp-e1.cloudn-service.com
Setting api endpoint to api.paas.jp-e1.cloudn-service.com...
OK


API endpoint:   https://api.paas.jp-e1.cloudn-service.com (API version: 2.0.0)
Not logged in. Use 'cf login' to log in.

$ cf login
API endpoint: https://api.paas.jp-e1.cloudn-service.com

Email> <APIアクセスキー>

Password> <シークレットキー>
Authenticating...
OK

Targeted org clnxxxxxxxx

Select a space (or press enter to skip):
1. default
2. development
3. production

Space> 1
Targeted space default



API endpoint:   https://api.paas.jp-e1.cloudn-service.com (API version: 2.0.0)
User:           clnxxxxxxxxx@cloudnpaas.com
Org:            clnxxxxxxxxx
Space:          default
````

### MySQL Serviceの作成
無料のMySQL DBを作成します。

````
cf create-service mysql default cf-rails-sample-mysql
````

### manifest.ymlの作成
manifest.ymlを作成し、以下のように記述します

````
applications:
- name: cf-rails-sample
  command: bundle exec rake db:migrate && bundle exec rails s --port=$PORT
  services:
  - cf-rails-sample-mysql
  env:
    SECRET_KEY_BASE: hogehogefugafuga
````

name: デプロイするアプリケーション名
command: デプロイ後、実行したいコマンド
services: アプリに結びつけたいservice名(ここでは、作成したMySQLサービスの名前を指定)
env: アプリケーションに渡したい環境変数を指定

### デプロイ！
準備ができたら、以下のコマンドでpushします

````
cf push
````

最後にこんなメッセージができたらデプロイ成功です。

````
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: cf-rails-sample.paas.jp-e1.cloudn-service.com

     state     since                    cpu    memory           disk
#0   running   2014-07-16 10:09:40 PM   0.0%   151.3M of 256M   91.4M of 1G
````

urlsに、自動で割り振られたURL名が表示されているので、ブラウザでアクセスします。

![Cursor_と_CfRailsTest.jpg](https://qiita-image-store.s3.amazonaws.com/0/17840/d23dbdc8-8578-3eb8-fdfa-fdc201dbb613.jpeg "Cursor_と_CfRailsTest.jpg")

問題なさそうですね！

## 同じものをBluemixにデプロイ
![Cursor_と_IBM_developerWorks_日本語版___IBM_Bluemix.jpg](https://qiita-image-store.s3.amazonaws.com/0/17840/9a2dfd8c-74b0-0a09-8d94-43c72f32e462.jpeg "Cursor_と_IBM_developerWorks_日本語版___IBM_Bluemix.jpg")

さて、それでは同じものをBluemixにデプロイしてみましょう。
Bluemixの登録方法はここでは解説しないので、[このあたり](http://www.ibm.com/developerworks/jp/bluemix/registration.html)を参考に登録しておきましょう。

Cloudnで下準備は既にできているはず。CF間の互換性とやらを見せて貰いましょう。

### ログイン

IBM IDを使ってログインします。

````
$ cf api api.ng.bluemix.net
Setting api endpoint to api.ng.bluemix.net...
OK


API endpoint:   https://api.ng.bluemix.net (API version: 2.2.0)
Not logged in. Use 'cf login' to log in.

$ cf login
API endpoint: https://api.ng.bluemix.net

Email> <IBM ID>

Password> <password>
Authenticating...
OK

Targeted org xxxxxxxx

Targeted space dev



API endpoint:   https://api.ng.bluemix.net (API version: 2.2.0)
User:           xxxxxxx
Org:            xxxxxxx
Space:          dev
````

### MySQL Serviceの作成

無料のMySQL Serviceを作成します。CloudnとはPlanの指定が少し違うので、間違えないように。(Cloudn:default, Bluemix:100)

````
cf create-service mysql 100 cf-rails-sample-mysql
````

### デプロイ！
Cloudn側でmanifest.ymlも作成したので、もうこれだけでデプロイできちゃいます。

````
cf push
````

````
requested state: started
instances: 1/1
usage: 1G x 1 instances
urls: cf-rails-sample.mybluemix.net

     state     since                    cpu    memory         disk
#0   running   2014-07-16 10:26:30 PM   0.0%   160.5M of 1G   101.9M of 1G
````

![Cursor_と_CfRailsTest.jpg](https://qiita-image-store.s3.amazonaws.com/0/17840/548c595c-1824-357c-fbf1-067bac5441fb.jpeg "Cursor_と_CfRailsTest.jpg")

動きました！

## 総評

試してみたところ、Cloudn PaaS、Bluemixともに同じコード、同じ操作でデプロイすることができました。
コードを全く変更することなく、cfコマンドの向き先を変えるだけで同じアプリがデプロイできるのは、ベンダーロックインされないという意味でも良さそうです。

## QA

### database.ymlの設定は要らないの？

CFでMySQLやPostgreSQLをbindすれば、自動でdatabase.ymlが生成されますので、予め指定しておく必要はありません。

### ほんとうにコードの変更なしに両方で同じように動くの？

必ず両方で動くと保証はできませんが、いくつかのポイントに注意すれば、高い確率で同じように動くのではないかと思います。
例えば、設定項目はファイルに書くのではなく、環境変数で渡すなどの工夫をしたほうが良いです。そうすれば、コードベースを変更することなく、CF間でアプリの移行を行うことができます。
もっとも、これはCFというより、クラウドネイティブなアプリの作成に共通する話ですが。(12 factor appsに書かれている話ですね)