2015-07-28

Smalruby を Cloud Foundry で動かす

「Cloud Foundry 百日行」第38日目は、Web上でRubyのビジュアルプログラミングができるツール Smalruby です。

基本情報

手順の概要は以下の通りです。

  • 1) ソースコードの取得
  • 2) データベースの準備
  • 3) コードの修正
  • 4) Cloud Foundry 環境へのプッシュ
  • 5) 動作確認

1. ソースコードの取得

$ git clone https://github.com/smalruby/smalruby-editor/
$ cd smalruby-editor/
smalruby-editor$ ls
app     config.ru  Gemfile       LEGAL    log       Rakefile                 spec
bin     db         Gemfile.lock  lib      Procfile  README.rdoc              vendor
config  demos      Guardfile     LICENSE  public    smalruby-editor.gemspec

Rubyのアプリです。
公式ドキュメントにも インストール手順 が記載されているので、これを参考に進めていきましょう。

2. データベースの準備

まずはデータベースの準備です。

アプリを起動無しモードでPush。

smalruby-editor$ cf push smalruby --no-start
Creating app smalruby in org ukaji / space default as ukaji...
OK

Creating route smalruby.10.244.0.34.xip.io...
OK

Binding smalruby.10.244.0.34.xip.io to smalruby...
OK

Uploading smalruby...
Uploading app files from: /home/ukaji/workspace/smalruby-editor
Uploading 1.5M, 519 files
Done uploading               
OK

MySQLのサービスを作成し、アプリとバインド。

smalruby-editor$ cf marketplace
Getting services from marketplace in org ukaji / space default as ukaji...
OK

service      plans                     description
PostgreSQL   Basic PostgreSQL Plan*    PostgreSQL on shared instance.
p-mysql      100mb, 1gb                MySQL databases on demand
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.
smalruby-editor$ cf create-service p-mysql 100mb smalruby-db
Creating service instance smalruby-db in org ukaji / space default as ukaji...
OK
smalruby-editor$ cf bind-service smalruby smalruby-db
Binding service smalruby-db to app smalruby in org ukaji / space default as ukaji...
OK
TIP: Use 'cf restage smalruby' to ensure your env variable changes take effect

3. コードの修正

Cloud Foundryへデプロイするにあたり、少々コードを修正します。
まずはデータベースとの接続部分から。

先ほどバインドしたサービスへの接続情報を $ cf env smalruby で参照しつつ記載します。

smalruby-editor$ cf env smalruby
Getting env variables for app smalruby in org ukaji / space default as ukaji...
OK

System-Provided:
{
 "VCAP_SERVICES": {
  "p-mysql": [
   {
    "credentials": {
     "hostname": "10.244.7.6",
     "jdbcUrl": "jdbc:mysql://10.244.7.6:3306/cf_0e3058cc_91dd_4738_91a1_21f93e41ad0d?user=eYUkO8eGA2neWOKm\u0026password=hHCDD1A5vLFsXzAO",
     "name": "cf_0e3058cc_91dd_4738_91a1_21f93e41ad0d",
     "password": "hHCDD1A5vLFsXzAO",
     "port": 3306,
     "uri": "mysql://eYUkO8eGA2neWOKm:hHCDD1A5vLFsXzAO@10.244.7.6:3306/cf_0e3058cc_91dd_4738_91a1_21f93e41ad0d?reconnect=true",
     "username": "eYUkO8eGA2neWOKm"
    },
    "label": "p-mysql",
    "name": "smalruby-db",
    "plan": "100mb",
    "tags": [
     "mysql"
    ]
   }
  ]
 }
}

{
 "VCAP_APPLICATION": {
  "application_name": "smalruby",
  "application_uris": [
   "smalruby.10.244.0.34.xip.io"
  ],
  "application_version": "6040512d-4671-4101-89a7-73d36c5732b4",
  "limits": {
   "disk": 1024,
   "fds": 16384,
   "mem": 256
  },
  "name": "smalruby",
  "space_id": "03bf316f-df9e-442e-b127-589e673a5652",
  "space_name": "default",
  "uris": [
   "smalruby.10.244.0.34.xip.io"
  ],
  "users": null,
  "version": "6040512d-4671-4101-89a7-73d36c5732b4"
 }
}

No user-defined env variables have been set

No running env variables have been set

No staging env variables have been set

書き換え箇所はこちら。

smalruby-editor$ cp config/database.yml.mysql2 config/database.yml
smalruby-editor$ vi config/database.yml
# MySQL.  Versions 4.1 and 5.0 are recommended.
#
# Install the MYSQL driver
#   gem install mysql2
#
# Ensure the MySQL gem is defined in your Gemfile
#   gem 'mysql2'
#
# And be sure to use new-style password hashing:
#   http://dev.mysql.com/doc/refman/5.0/en/old-client.html
development:
  adapter: mysql2
  encoding: utf8
  database: smalruby-editor_development
  pool: 5
  username: eYUkO8eGA2neWOKm
  password: hHCDD1A5vLFsXzAO
  host: 10.244.7.6

# 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: mysql2
  encoding: utf8
  database: smalruby-editor_test
  pool: 5
  username: eYUkO8eGA2neWOKm
  password: hHCDD1A5vLFsXzAO
  host: 10.244.7.6

production:
  adapter: mysql2
  encoding: utf8
  database: smalruby-editor_production
  pool: 5
  username: eYUkO8eGA2neWOKm
  password: hHCDD1A5vLFsXzAO
  host: 10.244.7.6

standalone:
  adapter: mysql2
  encoding: utf8
  database: smalruby-editor_standalone
  pool: 5
  username: eYUkO8eGA2neWOKm
  password: hHCDD1A5vLFsXzAO
  host: 10.244.7.6
smalruby-editor$ diff config/database.yml.mysql2 config/database.yml
16,18c16,18
<   username: root
<   password:
<   host: localhost
---
>   username: eYUkO8eGA2neWOKm
>   password: hHCDD1A5vLFsXzAO
>   host: 10.244.7.6
28,30c28,30
<   username: root
<   password:
<   host: localhost
---
>   username: eYUkO8eGA2neWOKm
>   password: hHCDD1A5vLFsXzAO
>   host: 10.244.7.6
37,39c37,39
<   username: root
<   password:
<   host: localhost
---
>   username: eYUkO8eGA2neWOKm
>   password: hHCDD1A5vLFsXzAO
>   host: 10.244.7.6
46,48c46,48
<   username: root
<   password:
<   host: localhost
---
>   username: eYUkO8eGA2neWOKm
>   password: hHCDD1A5vLFsXzAO
>   host: 10.244.7.6

ちなみにこのように記述してもOKです。

# MySQL.  Versions 4.1 and 5.0 are recommended.
#
# Install the MYSQL driver
#   gem install mysql2
#
# Ensure the MySQL gem is defined in your Gemfile
#   gem 'mysql2'
#
# And be sure to use new-style password hashing:
#   http://dev.mysql.com/doc/refman/5.0/en/old-client.html

# common
common: &common
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: eYUkO8eGA2neWOKm
  password: hHCDD1A5vLFsXzAO
  host: 10.244.7.6

# development
development:
  <<: *common
  database: smalruby-editor_development
 
# 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:
  <<: *common
  database: smalruby-editor_test
 
production:
  <<: *common
  database: smalruby-editor_production
 
standalone:
  <<: *common
  database: smalruby-editor_standalone

次に、デプロイ時のコマンドが少々複雑になるのでmanifestファイルを作ってしまいましょう。

smalruby-editor$ vi manifest.yml
---
applications:
- name: smalruby
  buildpack: ruby_buildpack
  command: rake db:migrate; rake; touch tmp/standalone; rails server -p $PORT;
  env:
    RAILS_ENV: production
    SECRET_KEY_BASE: atemporarysecretkeyforsmalruby

SECRET_KEY_BASE は30文字以上の適当な文字列でOKです。

4. Cloud Foundry 環境へのプッシュ

準備は整ったのでPushを行いましょう。

smalruby-editor$ cf push
(一部略)
-----> Uploading droplet (47M)

0 of 1 instances running, 1 starting
1 of 1 instances running

App started


OK

App smalruby was started using this command `rake db:migrate; rake; touch tmp/standalone; rails server -p $PORT;`

Showing health and status for app smalruby in org ukaji / space default as ukaji...
OK

requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: smalruby.10.244.0.34.xip.io
last uploaded: Tue Jul 28 01:06:34 UTC 2015
stack: cflinuxfs2
buildpack: ruby_buildpack

     state     since                    cpu    memory           disk      details   
#0   running   2015-07-28 10:08:37 AM   0.0%   143.3M of 256M   0 of 1G 

起動しました。

5. 動作確認

ブラウザーからアプリにアクセスします。

このようにパズルを組み合わせる感覚でプログラミングをすることができ、

裏では自動的にRubyのコードを生成してくれています。

ソースコードは右上のダウンロードボタンからローカルに保存し、実行することも可能です。
小学校3年生でも使えるとだけあって、プログラミングを学んだことのない人でもお手軽にRubyのコードを生成できそうな面白いツールでした。

おまけ

Railsのアプリをデプロイする際などによく登場する rails server コマンド。
Cloud Foundryではよく起動コマンド rails server -p $PORT として登場します。
Cloud Foundryでアプリが動作する際のポート番号を環境変数から取得してRailsサーバを起動するコマンドですね。

さて、このようなRailsアプリをmanifestファイルを使わずに cf push 一行でデプロイを試みようとすると、

$ cf push appname -b ruby_buildpack -c "rails server -p $PORT"

とできそうですが、実はこのコマンド、失敗します。

普段からターミナルをよく操作する方はお分かりかもしれませんが、実は上のケースでダブルクォーテーション " で括った内部にある $PORT は手元のローカル環境で解釈されてしまいます。
ログ等で見える事象としては、 $PORT に想定通りの値が入ってくれない、そもそも値が入らない、などになりますね。

というわけで正解はこちら。

$ cf push appname -b ruby_buildpack -c 'rails server -p $PORT'

シングルクォーテーション ' で括るだけです。
これなら $PORT はローカルで解釈されることなく、Cloud Foundry上での環境変数を読んでくれます。

今回使用したソフトウェア