hyoromoのブログ

最近はVRSNS向けに作ったものについて書いています

JRuby on Rails を GAE/J 上へデプロイ

一週間遅れなので、情報多くが出回ってて苦戦しない...と思ってたけど結構苦戦した。
ほとんどはここを参照すれば分かるし、ほとんど同じことを書いていくけど、自分でよく分からなかったところを(自分へ)補足しながら書く。

JRuby インストール

home 直下の bin ディレクトリに JRuby をインストールします。

$ cd ~/bin
$ svn co http://svn.codehaus.org/jruby/trunk/jruby jruby
$ cd jruby
$ mvn

JRuby 環境変数設定

Mac なので、bash_profile に書いておく。もしファイルがなければ新規作成。

$ vi .bash_profile
export JRUBY_HOME=~/bin/jruby
export PATH=$JRUBY_HOME/bin:$PATH

これでパスが通るかの確認。

$ jruby -v
jruby 1.3.0 (ruby 1.8.6p287) (2009-04-16 r6586) (Java HotSpot(TM) Client VM 1.5.0_16) [i386-java]

Rails インストール

オプション付けなくても大丈夫だと思うけど、参考サイトをマネしてそのまま実行。

$ jruby/bin/gem install rails -y --no-ri --no-rdoc

Rails 実装

$ GEM_HOME=$JRUBY_HOME/lib/ruby/gems/1.8/gems jruby $JRUBY_HOME/bin/rails hello_appengine -f
$ cd hello_appengine
$ jruby -S ./script/generate controller hello index

とりあえずメッセージを出力させる。

$ vi app/controllers/hello_controller.rb
class HelloController < ApplicationController
  def index
    render :text => "Hello, JRuby on Rails on Google App Engine !"
  end
end

ルートを変更。

$ vi config/routes.rb
map.root :controller => "hello"

protect_from_forgery が現状では動かないらしいのでコメントアウト

$ vi app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  helper :all # include all helpers, all the time
  #protect_from_forgery # See ActionController::RequestForgeryProtection for details
end

GAE へのファイルアップロード数が 1000 までらしいので、不要ファイルの削除。

$ rm -rf test/
$ rm -rf doc/
$ rm -rf vendor/rails/activerecord/
$ rm -rf vendor/rails/activeresource/
$ rm -rf vendor/rails/actionmailer/
$ 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/actionpack/test/
$ rm public/index.html

削除ファイルが使われないよう config 修正。

$ vi config/environment.rb
config.frameworks -= [ :active_record, :active_resource, :action_mailer ]

appengine-web.xml を $RAILS_HOME に作成。
hello 部分は GAE に登録したアプリ名。

$ vi appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- appengine-web.xml -->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <application>hyoromo-hello</application>
    <version>1</version>

    <system-properties>
        <property name="jruby.management.enabled" value="false" />
        <property name="os.arch" value="" />
    </system-properties>
</appengine-web-app>

AppEngine Java SDK インストール

ここより、最新版をダウンロードしてくる。
最新がインストール済みならダウンロードしてこなくていい。

cp appengine-java-sdk-1.2.0/lib/user/appengine-api-1.0-sdk-1.2.0.jar $RAILS_HOME/lib/

JRuby-Rac 最新版インストール。

$ git clone git://github.com/nicksieger/jruby-rack.git
$ cd jruby-rack
$ jruby -S rake SKIP_SPECS=true
$ mv target/jruby-rack-0.9.4.jar ../lib/
$ cd ..
$ rm -rf jruby-rack

デプロイ準備

jruby-complete.jarをlibにコピー。

cp $JRUBY_HOME/lib/jruby-complete.jar $RAILS_HOME/lib/

適当な名前をつけた shell を作成。

$ vi lib/hoge.sh

#!/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

shell を実行。

$ cd lib
$ chmod +x hoge.sh
$ hoge.sh
$ rm -rf hoge.sh

プラグイン化させます。

$ jruby -S gem install warbler  #これは一回インストールすればOK
$ jruby -S warble pluginize
$ jruby -S warble config

作成されたファイルを編集します。

$ vi 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

warble コマンド実行

$ warble war

tmp/war 以下にファイルが配備される。

GAE 上へのデプロイ

$ ~/bin/appengine-java-sdk-1.2.0/bin/appcfg.sh update tmp/war

ちゃんとメッセージが表示されているか確認する。
http://hyoromo-hello.appspot.com/

まとめ

予想以上にエラーが出て、結構苦戦する結果になりました。
最初は JRuby だから大変なのかと思ったけど、これが Java であろうが、フレームワークを使ったときのデプロイが大変なのかも知れない。
あと、今回は参考サイトの通りに作業を進めたので削除するファイルは迷わなかったが、自分で実装したときにキチンと削除できるか心配。

作業時のトラブル

ここ以降は作業中に発生したトラブルをまとめたモノ。
上の手順とは少し違ったやり方をしたために発生したものなので、上の方法を見ながら作業したら発生はしない(一部するかも)と思う。

デプロイ 5% でエラーになる

シェルを $RAILS_HOME で間違えて実行していたときのゴミが残っていたのが原因。
作成されたゴミを削除し、tmp/war をディレクトリごと削除、再度 tmp/war を作り直す事で解決。

デプロイ 52% でエラーになる
$ ~/bin/appengine-java-sdk-1.2.0/bin/appcfg.sh update tmp/war
Reading application configuration data...
2009-04-17 23:42:27.788::INFO:  Logging to STDERR via org.mortbay.log.StdErrLog
Beginning server interaction for hyoromo-hello...
0% Creating staging directory
5% Scanning for jsp files.
20% Scanning files on local disk.
25% Scanned 250 files.
28% Scanned 500 files.
31% Scanned 750 files.
33% Scanned 1000 files.
34% Scanned 1250 files.
35% Scanned 1500 files.
36% Initiating update.
37% Cloning 11 static files.
37% Cloning 1647 application files.
37% Cloned 100 files.
37% Cloned 200 files.
37% Cloned 300 files.
37% Cloned 400 files.
37% Cloned 500 files.
37% Cloned 600 files.
37% Cloned 700 files.
37% Cloned 800 files.
37% Cloned 900 files.
37% Cloned 1000 files.
37% Cloned 1100 files.
37% Cloned 1200 files.
37% Cloned 1300 files.
37% Cloned 1400 files.
37% Cloned 1500 files.
37% Cloned 1600 files.
40% Uploading 76 files.
52% Rolling back the update.
java.io.IOException: Error posting to URL: http://appengine.google.com/api/appversion/addfile?path=WEB-INF%2Fappengine-web.xml&app_id=hyoromo-hello&version=1&
400 Bad Request
Max number of files and blobs is 1000.

Unable to upload app: Error posting to URL: http://appengine.google.com/api/appversion/addfile?path=WEB-INF%2Fappengine-web.xml&app_id=hyoromo-hello&version=1&
400 Bad Request
Max number of files and blobs is 1000.

Please see the logs [/tmp/appcfg55264.log] for further information.

ファイル数が 1000 超えるな!ってことなので、ファイルを削除。
どうやら、不要ファイルの削除に失敗していたことが原因。

デプロイできたけど、ブラウザ上でエラーになる
#ブラウザ上
Error: Server Error
The server encountered an error and could not complete your request.

If the problem persists, please report your problem and mention this error message and the query that caused it.

ここから log を参照してみよう。
http://appengine.google.com/

failed com.google.apphosting.utils.jetty.RuntimeAppEngineWebAppContext@f6f1b6{/,/base/data/home/apps/hyoromo-hello/1.332856192093661973}
java.lang.NoClassDefFoundError: org/jruby/exceptions/RaiseException
	at org.jruby.rack.rails.RailsServletContextListener.newApplicationFactory(RailsServletContextListener.java:30)
	at org.jruby.rack.RackServletContextListener.contextInitialized(RackServletContextListener.java:36)
(以下略)

RaiseException がなくてエラーになってるようですね。
原因は jruby-complete.jar を jrbuy-core.jar と ruby-stdlib.jar に分割するのに失敗していたみたい。
なぜ失敗したかは不明だが、再度分割し直したらエラーは出なくなった。

Application名が変更不可能(delete/create不可能)

Application名は後で変えられると思ったのに、変えられない!
hyoromo-hello とか言うダサイ名前が消せないとは...これが一番の問題だ。

参考サイト(どうもありがとうございました!)

JRuby on Rails on GAE/J 動いた
JRuby on Rails on Google App Engine