Google App Engine で Rails を動かしてみる

Google App Engine (以下 GAE) で Java が使えるようになったため、 JRuby が動作するようになりました。
JRuby on GAE で Rails を動かせる!ということで、あちこちで試みがなされています。

ってことで、先達の記事はいっぱいあるけど、手を動かさないとわからないので自分でやってみました。
案の定色々引っかかったのでメモメモ。

概要

まず、動いている (たぶん) サンプルは以下の URL 。
デモ: http://hello-gae-gom.appspot.com/
ソース: http://github.com/gom/hello-gae-gom/tree/master


こんにちわ!とか表示されたら動いてると思います。
動かない状態になってたらごめんなさい。
データは何も保存・読み出しせず、 Controller からテキストを出力しているだけです。

制限

GAE にはいくつかの制限があります。

  • ファイル数は 1000 まで
  • ファイルサイズも上限がある

これらの制限をクリアして Rails を動かす必要があります。

何すればいいの?

やることはこれくらい。 8 割くらいは Rails Templete がやってくれます。
なお、今回は DataStore は行ってません。

  1. ソフトの準備
    1. jruby (jar の作成・分割)
    2. jruby-rack
    3. warbler (rubygems)
    4. google app engine java sdk
  2. Rails アプリの作成
    1. 普通にアプリを作成
    2. GAE 用に設定を変更
    3. lib を用意
  3. Rails の不要なファイルを削除
  4. GAE 用の XML ファイルを作成
  5. Warbler でサーブレット化
  6. デプロイ

というわけで、以下で簡単に手順を紹介。

ソフトの準備

jruby インストール

github より jruby を git clone し、ビルドします。
あとで lib として使う jar ファイル生成も行います。

$git clone git://github.com/jruby/jruby.git
$cd jruby
$ant
$ant jar-complete #=> lib/jar-complete.jar が生成

また、コマンドを簡略化するために、 jruby の PATH を設定しておきます。

#.zshrc
export $JRUBY_PATH=/path/to/bin/jruby
jruby を分割した jar を作成する

下記のスクリプトで jar ファイルを分割します。
jruby-core.jar と jruby-stdlib.jar が生成されます。
via:ぽかぽか陽気 - ずっと君のターン

#!/bin/sh

rm -rf jruby-core.jar
rm -rf ruby-stdlib.jar
rm -rf tmp_unpack
mkdir tmp_unpack
cd tmp_unpack
jar xf ../jruby-complete.jar
cd ..
mkdir jruby-core
mv tmp_unpack/org jruby-core/
mv tmp_unpack/com jruby-core/
mv tmp_unpack/jline jruby-core/
mv tmp_unpack/jay jruby-core/
mv tmp_unpack/jruby jruby-core/
cd jruby-core
jar cf ../jruby-core.jar .
cd ../tmp_unpack
jar cf ../ruby-stdlib.jar .
cd ..
rm -rf jruby-core
rm -rf tmp_unpack
rm -rf jruby-complete.jar
jruby-rack の用意

jruby-rack-x.x.x.jar を作成します。

$ git clone git://github.com/nicksieger/jruby-rack.git
$ cd jruby-rack
$ jruby -S rake SKIP_SPECS=true
warbler のインストール

Rails アプリを Java アプリケーションサーバにデプロイするための gem をインストールします。
*1

$jruby -S gem install warbler
google app engine java sdk をダウンロード

Google 様の言う通りにすると落とせると思います。
appengine-api.jar とデプロイスクリプトを使う。

Rails アプリの作成

Rails インストール

ri や rdoc はファイル数が増えるだけなのでいらない

$jruby -S gem install rails --no-ri --no-rdoc
アプリの作成

コントローラから render :text するだけ

$jruby -S rails hello-gae-gom
$cd hello-gae-gom
$jruby -S script/generate controller index
$vim app/controllers/index_controller.rb

アプリ設定

ルータを設定
$vim config/routes.rb
 map.root :controller => 'index'
protect_from_forgery をコメントアウト

なんだか使えないらしいので、コメントアウト。

$vim app/controllers/apprication_controller.rb
 #protect_from_forgery # See ActionController::RequestForgeryProtection for details
active record は使わない
$vim config/environment.rb
config.frameworks -= [ :active_record]

lib を用意

これまでの手順で作成した jar をまとめて$RAILS_ROOT/lib に入れる

Rails の不要なファイルを削除

rm -rf test/
rm -rf doc/
rm -rf vendor/rails/railties/doc
rm -rf vendor/rails/railties/html
rm -rf vendor/rails/railties/bin
rm -rf vendor/rails/railties/builtin
rm -rf vendor/rails/railties/environments
rm -rf vendor/rails/railties/dispatches
rm -rf vendor/rails/activerecord/
rm -rf vendor/rails/actionmailer/test
rm -rf vendor/rails/actionpack/test
rm -rf vendor/rails/activeresource/test
rm -rf vendor/rails/activesupport/test
rm -rf vendor/rails/railties/test

XML を作成

# appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <application>#{app_name}</application>
  <version>2</version>

  <static-files />
  <resource-files />
  <sessions-enabled>true</sessions-enabled>
  <system-properties>
    <property name="jruby.management.enabled" value="false" />
    <property name="os.arch" value="" />
    <property name="jruby.compile.mode" value="JIT"/> <!-- JIT|FORCE|OFF -->
    <property name="jruby.compile.fastest" value="true"/>
    <property name="jruby.compile.frameless" value="true"/>
    <property name="jruby.compile.positionless" value="true"/>
    <property name="jruby.compile.threadless" value="false"/>
    <property name="jruby.compile.fastops" value="false"/>
    <property name="jruby.compile.fastcase" value="false"/>
    <property name="jruby.compile.chainsize" value="500"/>
    <property name="jruby.compile.lazyHandles" value="false"/>
    <property name="jruby.compile.peephole" value="true"/>
  </system-properties>
</appengine-web-app>

warble の準備

$jruby -S warble config
$jruby -S warble pluginize
$vim config/warble.rb

Warbler::Config.new do |config|
  config.dirs = %w (app config lib log vendor tmp)
  config.includes = FileList["appengine-web.xml"]
  config.java_libs = []
  config.gem_dependencies = true
  config.webxml.jruby.min.runtimes = 1
  config.webxml.jruby.max.runtimes = 1
  config.webxml.jruby.init.serial = true
end

デプロイ実行

ファイル数のチェック
$find . -type f | wc -l
アップロード
$ appengine-java-sdk/bin/appcfg.sh udpate tmp/war

動作確認

http://hello-gae-gom.appspot.com/
*2

まとめ

以上、 JRuby on Rails on GAE をやってみました。
Rails2.3.2 以降なら、アプリ作成時にテンプレートを適用することで、作業を簡略化できます。

$jruby -S rails -m template.rb APPNAME

上記で作成したサンプルのアプリとテンプレートを下記に置いてます。
よかったら参考にしてください。
http://github.com/gom/hello-gae-gom/tree/master

追記 2009/04/27 08:20

デモがエラーになっていましたが、再アップしたら直りました。
エラーログにはrackがエラー吐いてたようだけど、今のところ原因がよくわからず。

時間経ってからまた見れなくなってたら、その時にじっくり調べよう。

*1:この gem が何をしてるのかは不明・・・

*2:再確認したが、動かなくなっている。なぜだ。