月が変わり、「Cloud Foundry 百日行」も本日第20回を迎えることとなりました。本日取り上げるのは、Ruby on Rails 製の家計簿ソフト Expense です。
基本情報
-
公式サイト
なし
ソースコードの取得と確認
$ git clone https://github.com/tristandunn/expense.git
$ cd expense/
$ ls
app config config.ru db doc features Gemfile Gemfile.lock lib LICENSE log public Rakefile README.markdown script spec
Gemfile
がありますので、まずはその中身を確認しましょう。
$ cat Gemfile
source "https://rubygems.org"
gem "bcrypt-ruby", "3.1.2"
gem "dynamic_form", "1.1.4"
gem "rails", "4.0.3"
gem "sqlite3", "1.3.8"
group :assets do
gem "sass-rails", "4.0.1"
gem "yui-compressor", "0.12.0"
end
group :development, :test do
gem "rspec-rails", "2.14.1"
end
group :test do
gem "cucumber-rails", "1.4.0", require: false
gem "database_cleaner", "1.2.0"
gem "factory_girl_rails", "4.4.0"
gem "timecop", "0.7.1"
end
rails
、それから、 sqlite3
も使われるようです。
Rails アプリで DB が使われる場合は、 config/database.yml
に設定内容が記載されるので、そのファイルも見ておきましょう。
$ cat config/database.yml
# SQLite version 3.x
# gem install sqlite3-ruby (not necessary on OS X Leopard)
development:
adapter: sqlite3
database: db/development.sqlite3
pool: 5
timeout: 5000
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
adapter: sqlite3
database: db/test.sqlite3
pool: 5
timeout: 5000
production:
adapter: sqlite3
database: db/production.sqlite3
pool: 5
timeout: 5000
development
, test
, production
のそれぞれの環境において、 adapter: sqlite3
が使われており、その DB のパスが設定されています。
このデフォルトの sqlite3
を使うと簡便にデプロイできそうですが、ただし、その場合は DB がファイルとして作られるので、アプリを停止したり再起動すると、DB のファイルがリセットされてしまう、という欠点があります。
そこで、本日は、 sqlite3
でまずデプロイして確認した後、built-in の MySQL をバインドしてデプロイし、登録データが永続的になることを確認してみることにします。
SQLite を使ったデプロイ
https://github.com/tristandunn/expense のインストール手順では、ソースコードを取得した後、 bundle install
、そして、 rake db:create db:migrate
を実行することとなっています。
しかし今回は、ローカルではなく、Cloud Foundry へデプロイしようとしているので、 bundle install
の実行は、ruby-buildpack の適用時に行われるため不要になります。
次に、 rake db:create db:migrate
ですが、これはDBを作成してデータを投入するコマンド。今回はローカルではなく、デプロイ先の Cloud Foundry 上にて DB を作成するため、デプロイ時にコマンド実行する必要がありますね。
第14回 の時にも、Ruby のアプリのデプロイ時にコマンド指定してましたので、 そちら も参考にしてください。
アプリの push
今回のアプリの push は、 -c
のオプションで、 bundle exec rake db:create db:migrate
のコマンド実行を指定します。なお今回は、 Gemfile
で指定された環境でコマンドを実行するため、コマンドの前に、 bundle exec
を付けます。
さらに、もう一つ。Cloud Foundry で利用する場合はポートを動的に設定する必要があります。そこで、環境変数 PORT
を使い、動的ポートに対応してRails サーバが起動するようにします。
環境はデフォルトでは production
としてデプロイされます。
$ cf push expense -c 'bundle exec rake db:create db:migrate ; bundle exec rackup --port $PORT'
:
0 of 1 instances running, 1 down
0 of 1 instances running, 1 down
0 of 1 instances running, 1 down
0 of 1 instances running, 1 down
0 of 1 instances running, 1 down
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 down
0 of 1 instances running, 1 down
0 of 1 instances running, 1 down
0 of 1 instances running, 1 down
0 of 1 instances running, 1 down
0 of 1 instances running, 1 down
0 of 1 instances running, 1 down
0 of 1 instances running, 1 down
0 of 1 instances running, 1 failing
FAILED
Start unsuccessful
TIP: use 'cf logs expense --recent' for more information
失敗したのでログを見ると、以下のように Invalid DATABASE_URL
と出ています。
2015-06-30T18:00:47.46+0900 [App/0] ERR Invalid DATABASE_URL
ローカルでは、上述した database.yml に記載された DB ファイルへのパス情報にて DB 接続されるのですが、Cloud Foundry にデプロイしようとしたら、環境変数 DATABASE_URL
に間違った値が入ってしまい、DB へ接続できなくなったようなので、 DATABASE_URL
に明に設定します。
sqlite3
の DB の URL のフォーマットは、 sqlite3:////full/path/to/file.sqlite3
のようになります。
今回使う DB の情報は、上述した config/database.yml
によると、 production
環境の場合は、 db/production.sqlite3
。
それを Cloud Foundry にデプロイすると、フルパスは、 /home/vcap/app/db/production.sqlite3
となります。
従って、設定したい URL は、 sqlite3:////home/vcap/app/db/production.sqlite3
。
これを次のように Cloud Foundry での環境変数 DATABASE_URL
に設定します。
$ cf set-env expense DATABASE_URL sqlite3:////home/vcap/app/db/production.sqlite3
確認は、以下のように env
コマンドで。
$ cf env expense
:
User-Provided:
DATABASE_URL: sqlite3:////home/vcap/app/db/production.sqlite3
:
さて、 DATABASE_URL
の設定ができたところで、アプリを restage
します。
$ cf restage expense
Restaging app expense in org ueno / space test1 as ueno...
:
App expense was started using this command `bundle exec rake db:create db:migrate ; bundle exec rackup --port $PORT`
Showing health and status for app expense in org ueno / space test1 as ueno...
OK
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: expense.10.244.0.34.xip.io
last uploaded: Tue Jun 30 08:57:38 +0000 2015
stack: lucid64
state since cpu memory disk details
#0 running 2015-06-30 06:11:09 PM 0.0% 110.2M of 256M 0 of 1G
デプロイ成功し、アプリが起動しました。
動作確認
http://expense.10.244.0.34.xip.io
にアクセスすると、初期画面が現れますので、まずは “sign up” のリンクを辿ります。

任意のメールアドレスとパスワードを入力してサインアップ。

メイン画面です。
“Item” に入力してみましょう。

入力した Item が順次表示されていきます。

“Mac” を “Search” すると、ちゃんと検索されて表示されました。

“Settings” のリンクを辿ると、タイムゾーン設定ができる画面に遷移します。

ここでアプリから一旦サインアウトし、アプリを再起動してみましょう。
$ cf restart expense
再起動後のアプリに先ほどと同じアカウントでサインインしようとしても、入れませんね。
入力データも登録アカウントデータも全て消えてしまっています。
その問題の対策のため、今度は Cloud Foundry に built-in された MySQL サービスをバインドして試してみます。
MySQL を使ったデプロイ
デフォルトの SQLite を使ったデプロイが成功したので、今度は予定通り、MySQL を使ったデプロイを試してみます。
今回利用する MySQL サービスは、 cf-mysql-release を利用して構築しています。
Gemfile
と Gemfile.lock
の書き換え
Gemfile
の sqlite3
の登録を削除し、代わりに mysql2
を登録します。
$ vi Gemfile
Gemfile.lock
は、 bundle install
実行によって作成されますが、今回は sqlite3
から mysql2
への変更のみなので、直接ファイルを編集します。
gem search mysql2
で確認し、 mysql2
の gem のバージョン 0.3.18
を指定します。
$ vi Gemfile.lock
Gemfile
と Gemfile.lock
の編集前後の差分を以下、 git diff
の実行結果で示しておきます。
$ git diff
diff --git a/Gemfile b/Gemfile
index 855ae21..8fc993e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -3,7 +3,7 @@ source "https://rubygems.org"
gem "bcrypt-ruby", "3.1.2"
gem "dynamic_form", "1.1.4"
gem "rails", "4.0.3"
-gem "sqlite3", "1.3.8"
+gem "mysql2"
group :assets do
gem "sass-rails", "4.0.1"
diff --git a/Gemfile.lock b/Gemfile.lock
index 33cd2f3..08cf571 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -113,7 +113,7 @@ GEM
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (~> 2.8)
- sqlite3 (1.3.8)
+ mysql2 (0.3.18)
thor (0.18.1)
thread_safe (0.1.3)
atomic
@@ -139,6 +139,6 @@ DEPENDENCIES
rails (= 4.0.3)
rspec-rails (= 2.14.1)
sass-rails (= 4.0.1)
- sqlite3 (= 1.3.8)
+ mysql2
timecop (= 0.7.1)
yui-compressor (= 0.12.0)
アプリの push
アプリを push します。
SQLite の時と異なり、MySQL と後でバインドするので、 --no-start
で push します。
$ cf push expense2 -c 'bundle exec rake db:create db:migrate ; bundle exec rackup --port $PORT' --no-start
MySQL サービス作成とバインド
まず利用できるサービスを確認します。
$ cf marketplace
Getting services from marketplace in org ueno / space test1 as ueno...
OK
service plans description
PostgreSQL Basic PostgreSQL Plan* PostgreSQL on shared instance.
p-mysql 100mb-dev, 1gb-dev A MySQL service for application development and testing
p-redis shared-vm, dedicated-vm Redis service to provide a key-value store
* These service plans have an associated cost. Creating a service instance will incur this cost.
TIP: Use 'cf marketplace -s SERVICE' to view descriptions of individual plans of a given service.
p-mysql
を使って今回の MySQL サービス expense-mysql
を作成します。
$ cf create-service p-mysql 100mb-dev expense-mysql
作成した MySQL サービス expense-mysql
をアプリとバインドします。
$ cf bind-service expense2 expense-mysql
アプリの起動
ではアプリを起動させます。
$ cf start expense2
Starting app expense2 in org ueno / space test1 as ueno...
:
App expense2 was started using this command `bundle exec rake db:create db:migrate ; bundle exec rackup --port $PORT`
Showing health and status for app expense2 in org ueno / space test1 as ueno...
OK
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: expense2.10.244.0.34.xip.io
last uploaded: Tue Jun 30 11:04:11 +0000 2015
stack: lucid64
state since cpu memory disk details
#0 running 2015-06-30 08:05:47 PM 0.0% 113.6M of 256M 0 of 1G
無事起動しました。
MySQL を使ったバージョンの動作確認
では URL にアクセスし、初期画面からサインアップ、Item 登録し、一旦サインアウトします。
そしてアプリを再起動。
$ cf restart expense2
起動後、先ほどのアカウントでサインインしてみると、今度は入れます。
そして、先ほど入力した Item もちゃんと残っています。
バインドした MySQL DB を使うことで、データの永続化が実現できることが確認できます。
まとめ
今回はアプリ自体はデモレベルのシンプルなものでしたが、Rails アプリのデプロイ、そして、SQLite と MySQL のタイプの異なる DB を使うための方法を学びました。
SQLite を使ったデプロイでは、 DATABASE_URL
の環境変数設定にて、正常に DB ファイルへ接続できるようになりました。
MySQL を使ったデプロイでは、サービスをバインドするだけで MySQL DB へ接続できるようになりました。
元々アプリには、 database.yml
があり、SQLite を使う設定がされていましたが、Cloud Foundry で DB サービスをバインドすると、その設定が上書きされるようになっています。そして、Cloud Foundry は、VCAP_SERVICES
環境変数から、バインドされた MySQL DB への接続情報を読み取り、自動で MySQL DB 接続されるようになりました。
今回のアプリは「たった一つの入力しかない家計簿」でしたが、実用として使うには、まず、登録アイテムの修正機能が欲しいですね。そして、集計機能。月別集計以外にも、アイテム種別等の集計、それにグラフ表示等があると便利そうです。以前の百日行記事にも、請求書アプリがありましたが(第16回)、これらのような実用的なアプリが Cloud Foundry 上で簡便にデプロイして使えるようになると便利でいいですね。
今回使用したソフトウェア
- cf-release (v194)
https://github.com/cloudfoundry/cf-release/tree/v194
( https://github.com/cloudfoundry/cf-release/tree/345a8b3e1ea0005a3e9fced13f0bf6fa6f7ad981 ) - bosh-lite
https://github.com/cloudfoundry/bosh-lite/tree/01db9da7b4122f7d02858d92e0fe938e91256649 - CF CLI (v6.11.3-cebadc9-2015-05-20T19:00:58+00:00)
https://github.com/cloudfoundry/cli/releases/tag/v6.11.3 - cf-mysql-release (v16)
https://github.com/cloudfoundry/cf-mysql-release/tree/v16
( https://github.com/cloudfoundry/cf-mysql-release/tree/63f0bc3914914ce469c80df07c9fa49c5b836f11 ) - Expense
https://github.com/tristandunn/expense/tree/d5bed2ee401e22d4817dc10e39dde501f1d388ea