sifue's blog

プログラマな二児の父の日常 ポートフォリオは www.soichiro.org

HerokuにScalatra(ScalaのSinatraクローン)をデプロイする方法

ついにJava系のPaaSはGAEだけでなくHerokuも使えるようになり随分幅が広がって来ました。
データベースに様々なものが使え、技術的にロックインされないう点でHerokuには大きな魅了があります。というわけで、今回はScala2.9.1を使ってScalatraというRubySinatraライクなWebフレームワークをHerokuにデプロイし、Eclipseでのデバック&開発環境を作成するということをやっていきます。


なお、前回Mavenでビルドを行うということをやっていましたが、sbtとgiter8を使った方が断然開発が楽ですし、GitHubと連携して更新が速いので、個人的にはsbtをお勧めします。


環境は、

  • scala 2.9.1-1
  • sbt 0.11.2
  • giter8 0.4.0

にて行います。全てMacOSX LionにてHomebrewのbrew installでインストールしたものの最新です(2012年3月30日現在)。


なお今回作成した最終的なソースは全て、
sifue/scalatra-heroku・GitHub
にプッシュしてありますので、途中で行き詰った方は、こちらからチェックアウトして使って下さい。


では早速、
Scalatra
以上の公式サイトを参考にScalatraをテンプレートからインストールします。

g8 scalatra/scalatra-sbt
organization [com.example]: org.soichiro
package [com.example.app]: sifue.scalatra
name [scalatra-sbt-prototype]: scalatra
servlet_name [MyScalatraServlet]: MyScalatraServlet
scala_version [2.9.1]: 
version [0.1.0-SNAPSHOT]: 


これでプロジェクト作成完了です。
まずは動作確認。

$ cd scalatra
$ sbt
  > container:start
    > ~ compile


http://localhost:8080/ にアクセスして動くことを確認します。

sbtでは~ compileコマンドを起動したままにすると、ファイルの更新があるたびに自動ビルドしてくれます。MyScalatraServlet.scalaの表示内容などを変更して、試して見ると良いかもしれません。


次にCtrl+CでJettyを終了させて、次にEclipseへのインポートします。
開発環境はやはりscalaの開発者が力を要れているeclipseが将来有望ですので、そちらを使います。


typesafehub/sbteclipse・GitHub
以上を参考に。


project/plugins.sbtに以下を追記します。

addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.0.0")


そして、

$ sbt
  > eclipse

以上を実行の後、Scala IDE for Eclipse2.0のインストールされたEclipse3.6.2のパッケージエクスプローラーの右クリックメニューのインポートからプロジェクトのインポートをします。

これで、無事Eclipseで開発できるようになりました。ただし、ビルドやサーバーの実行は、今のままではsbtから実行することになります。


次にherokuへのデプロイを行います。


Scalatra on Heroku
typesafehub/xsbt-start-script-plugin · GitHub
siasia/xsbt-web-plugin · GitHub
Getting Started with Scala on Heroku/Cedar
以上を参考にして実施します。ただ、ところどころ情報が古いので、Heroku本家やtypesafe本家も参照します。
なお、Herokuのアカウントの用意、gitのインストールherokuコマンドのインストールなどは済ませている前提とします。


project/build.sbtを作成して

resolvers += Classpaths.typesafeResolver

addSbtPlugin("com.typesafe.startscript" % "xsbt-start-script-plugin" % "0.5.1")

を記述します。


プロジェクトフォルダ直下のbuild.sbtの先頭に

import com.typesafe.startscript.StartScriptPlugin
    
seq(StartScriptPlugin.startScriptForClassesSettings: _*)

追記し、更に、compileの際にもjettyを利用するように、

  "org.eclipse.jetty" % "jetty-webapp" % "7.6.0.v20120127" % "compile",

を追記し、最終的に以下のようにします。

import com.typesafe.startscript.StartScriptPlugin
    
seq(StartScriptPlugin.startScriptForClassesSettings: _*)

organization := "org.soichiro"

name := "scalatra"

version := "0.1.0-SNAPSHOT"

scalaVersion := "2.9.1"

seq(webSettings :_*)

libraryDependencies ++= Seq(
  "org.scalatra" %% "scalatra" % "2.0.4",
  "org.scalatra" %% "scalatra-scalate" % "2.0.4",
  "org.scalatra" %% "scalatra-specs2" % "2.0.4" % "test",
  "ch.qos.logback" % "logback-classic" % "1.0.0" % "runtime",
  "org.eclipse.jetty" % "jetty-webapp" % "7.6.0.v20120127" % "container",
  "org.eclipse.jetty" % "jetty-webapp" % "7.6.0.v20120127" % "compile",
  "javax.servlet" % "servlet-api" % "2.5" % "provided"
)

resolvers += "Sonatype OSS Snapshots" at "http://oss.sonatype.org/content/repositories/snapshots/"


次にプロジェクト直下にProcfileという名前のファイルを作成し、

web: target/start

以上を記述します。


src/main/scala/JettyLauncher.scalaを作成し、以下を記述。
サーブレット名は適宜変更してください。

import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.{DefaultServlet, ServletContextHandler}
import org.eclipse.jetty.webapp.WebAppContext
import sifue.scalatra.MyScalatraServlet

object JettyLauncher {
  def main(args: Array[String]) {
    val port = if(System.getenv("PORT") != null) System.getenv("PORT").toInt else 8080

    val server = new Server(port)
    val context = new WebAppContext()
    context setContextPath "/"
    context.setResourceBase("src/main/webapp")
    context.addServlet(classOf[MyScalatraServlet], "/*")
    context.addServlet(classOf[DefaultServlet], "/")

    server.setHandler(context)

    server.start
    server.join
  }

}

ここで、クリーン後、再コンパイル、ステージしてして動作テストをします。

$ sbt
  > clean
  > compile
  > stage
  > container:start
    > ~ compile

これで問題なく動けば、開発環境とHerokuへデプロイする準備は完了です。なお、Eclipseブレークポイントをはってデバッグなどしたい際には、JettyLauncher.scalaを右クリックメニューからDebug As > Scala Applicationsとすれば、デバッグすることができます。


蛇足ですが、Herokuにデプロイしたくないよ、自前のJettyやTomcatサーバーにデプロイしたいよ、という方は、
Production Deployment
以上を参照下さい。あっさりwarファイルが作れます。


話を戻して、Herokuにデプロイするため、次にローカルのgitへのコミットの準備を行います。プロジェクト直下の.gitignoreファイルを作成して、

target
project/boot
project/target
project/plugins/target

以上を追記します。これでビルドされたものはコミットされずにすみます。


そして、実際のコミットを行います。

$ git init
$ git add .
$ git commit -m "init"

これで完了です。このコミットを行わないとherokuにpushすることができません。


最後にherokuにログインをして、アプリの作成、そしてデプロイを実行します。

$ heroku login
$ heroku create --stack cedar
Creating strong-winter-3291... done, stack is cedar
http://strong-winter-3291.herokuapp.com/ | git@heroku.com:strong-winter-3291.git
Git remote heroku added
$ git push heroku master

無事、デプロイに成功したようなら、
http://strong-winter-3291.herokuapp.com/
にアクセスしてみましょう。(なおこのアプリは後に消去する可能性があります。)


無事Hello World!が表示されたら、これでHeroku上のScalatraの完成でした。
まさかScalaがHeroku上で動かせる時代がくるなんて嬉しい限りですね。


以上、お疲れ様でした。