Windows Azure 上で Scala アプリケーションを実行 - Windows Azure Starter Kit for Java 使用

Windows Azure Starter Kit for Java を使って、Windows Azure 上で簡単な Scala アプリケーションを実行してみました。

今回は、Grizzly を使った簡単な HTTP サーバーアプリケーションを Scala で実装し、sbt でパッケージングした JAR ファイルを Windows Azure にデプロイしました。

サンプルソースは http://github.com/fits/try_samples/tree/master/blog/20110424/

Scala アプリケーション作成

まず、Scala アプリケーションを作成します。

Grizzly の HTTP Server API を利用するための sbt プロジェクトファイルは以下のようになります。

GrizzlyScalaSampleProject.scala (grizzly_scala_sample\project\build)
import sbt._

class GrizzlyScalaSampleProject(info: ProjectInfo) extends DefaultProject(info) {
    override def mainClass = Some("fits.sample.Sample")

    lazy val glassFishRepo = "Java.net Maven 2 Repository for GlassFish" at "http://download.java.net/maven/glassfish/"
    lazy val javaNetRepo = "Java.net Repository for Grizzly" at "http://download.java.net/maven/2"

    lazy val grizzly = "org.glassfish.grizzly" % "grizzly-http-server" % "2.0.1"
}

/test にアクセスされた際に hello 文字列を返すだけの単純な HTTP サーバー処理を実装します。(ポート 8080 で HTTP サーバーが起動されます)

Sample.scala (grizzly_scala_sample\src\main\scala\fits.sample)
package fits.sample

import scala.io.Source
import org.glassfish.grizzly.http.server._

object Sample {
    def handler(proc: (Request, Response) => Unit) = {
        new HttpHandler {
            override def service(req: Request, res: Response) = {
                proc(req, res)
            }
        }
    }

    def main(args: Array[String]) {
        val server = HttpServer.createSimpleServer
        val conf = server.getServerConfiguration

        conf.addHttpHandler(
            handler { (req, res) => 
                res.getWriter.write("hello")
            }, "/test"
        )

        //デフォルトのポート番号 8080 で HTTP サーバーが起動
        server.start

        println("Press key to stop")
        Source.stdin.reader().read()

        server.stop
    }
}

sbt で JAR ファイル化します。

ビルドとパッケージング
> sbt package

クラウドアプリ作成(Windows Azure Starter Kit for Java

それでは本題の Windows Azure Starter Kit for Java を使ったクラウドアプリを作成していきます。

まず、Windows Azure Starter Kit for Java を適当なディレクトリに展開して(サンプルでは ScalaAzureSample)、必要に応じてサービス名等を変更しておきます。(デフォルト値のままでも特に問題なし)

  • package.xml の packagefilename
  • ServiceDefinition.csdef の name
  • ServiceConfiguration.cscfg の serviceName

なお、今回は Programs Files 内に Azure SDK をインストールしていなかったので、package.xml の wasdkdir の設定値も変更しています。


次に、64bit 版 Windows用の JRE を zip 化したファイルを WorkerRole1\approot\JRE ディレクトリ内に配置します。(配置場所は approot の下なら何処でも良いです)
今回は JDK 1.6.0 24 内の jre ディレクトリを zip 化し、jre6.zip としました。

  • WorkerRole1\approot\JRE\jre6.zip

WorkerRole1\approot\lib に先ほど作成した Scala アプリと、その実行に必要な JAR ファイルを配置します。

  • WorkerRole1\approot\lib
    • grizzly_scala_sample_2.8.1-1.0.jar
    • grizzly-framework-2.0.1.jar
    • grizzly-http-2.0.1.jar
    • grizzly-http-server-2.0.1.jar
    • scala-library.jar

Worker ロールの開始時に jre6.zip を解凍し、Grizzly のサンプルアプリケーションを実行するためのコマンドを用意します。

なお、startup.cmd の処理が完了しないと Worker ロールのステータスが正常な状態にならないので、java コマンドを start を使って別のコマンドプロンプトウィンドウ上で実行するようにしています。(approot がカレントディレクトリになります)

WorkerRole1\approot\util\startup.cmd
cscript "util\unzip.vbs" JRE\jre6.zip . >> log.txt 2>> err.txt

set JRE_HOME=JRE
set CP=lib\grizzly_scala_sample_2.8.1-1.0;lib\grizzly-framework-2.0.1.jar;lib\grizzly-http-2.0.1.jar;lib\grizzly-http-server-2.0.1.jar;lib\scala-library.jar

start %JRE_HOME%\bin\java -cp %CP% fits.sample.Sample

ちなみに、今回は独自のサンプルアプリを実行していますが、Tomcat 等を起動したい場合でも同様です。(startup.cmd 内で環境変数を設定して、Tomcat の startup.bat 等を実行すればよい)

また、他のプログラム言語で書かれたプログラムを実行する際も同じような事をすればよいと思います。


最後に、サービス定義ファイルは以下のようになります。
サンプルアプリのポート番号 8080 を 80 にマッピングするための設定を追加します。(startup.cmd の設定は初めからあるはずです)

ServiceDefinition.csdef
<ServiceDefinition name="ScalaAzureSample" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WorkerRole name="WorkerRole1">
    <Startup>
      <Task commandLine="util\startup.cmd" executionContext="elevated" taskType="simple"/>
    </Startup>
    <Endpoints>
      <InputEndpoint name="Http" protocol="tcp" port="80" localPort="8080" />
    </Endpoints>
  </WorkerRole>
</ServiceDefinition>

Compute Emulator 上での実行

Windows Azure Starter Kit for Java ではパッケージングを行うための Ant 用のビルドファイル package.xml が用意されているので、Ant を使って以下のように実行します。(必要に応じて package.xml を編集しておく)

パッケージング
> ant -f package.xml

上記を実行することで、ローカル実行用にパッケージングされ(cspack が /copyonly 付きで実行される)、emulatorTools ディレクトリ内に Compute Emulator で実行するためのコマンドが生成されます。

Compute Emulator 上で実行するには、emulatorTools ディレクトリに作成された RunInEmulator.cmd を実行します。

Compute Emulator での実行
> emulatorTools\RunInEmulator.cmd

http://127.0.0.1:8080/test にアクセスすると、正常に動作していることが確認できるはずです。

クラウド上での実行

クラウド用にパッケージングするには、package.xml ファイルの windowsazurepackage 要素の packagetype 属性を local から cloud に変更するだけです。

package.xml
<project name="ScalaAzureSample" default="createwapackage" basedir=".">
  <target name="createwapackage" description="Creates a Windows Azure package">
    ・・・
    <windowsazurepackage
      ・・・
      packagetype="cloud"
      ・・・
    > 
      ・・・
    </windowsazurepackage>
  </target>
</project> 
パッケージング
> ant -f package.xml

deploy ディレクトリにクラウド用パッケージファイル .cspkg と ServiceConfiguration.cscfg が生成されるので、これを Windows Azure のクラウド環境にアップロードします。

Worker ロールが Ready になった後で、http://xxxxx.cloudapp.net/test にアクセスすれば正常に動作していることが確認できるはずです。(ステージング環境の場合、xxxxx には Azure で設定された Guid を指定します)