-
Notifications
You must be signed in to change notification settings - Fork 9
Scala
このチュートリアルはHerokuにデプロイされるScalaとFinagleウェブライブラリについて扱っていきます。
- 基本的なScalaとsbtの知識。
- あなたのアプリケーションはサポートされているSBTのバージョンと適合している必要があります。
- あなたのアプリケーションはOpenJDKのversion6の上で実行される必要があります。
- Herokuのユーザアカウント。こちらで無料で簡単に取得ができます。
始めに、Heroku Toolbeltをローカルにインストール します。これはあなたのHeroku command-line client、Foreman、そしてGitのバージョン管理システムへアクセスを確かなものにします。
一度インストールできると、heroku
コマンドがシェルから使えるようになります。アカウントを作ったときに使ったE-mailアドレスやパスワードを使ってログインしてみます :
$ heroku login
Enter your Heroku credentials.
Email: [email protected]
Password:
Could not find an existing public key.
Would you like to generate one? [Yn]
Generating new SSH public key.
Uploading ssh public key /Users/adam/.ssh/id_rsa.pub
プロンプトでエンターキーをおすと、存在しているssh
キーか新しいものをアップロードしてくれます。後でコードをプッシュするときに使います。キーに関する更なる情報については、SSHキーの管理を確認してください。
既に存在しているアプリケーションから始める人もいるかもしれませんが、もしそうでなければ、あなたに使ってもらえる簡単な"hello, world"のソースコードを用意しています :
import org.jboss.netty.handler.codec.http.{HttpRequest, HttpResponse}
import com.twitter.finagle.builder.ServerBuilder
import com.twitter.finagle.http.{Http, Response}
import com.twitter.finagle.Service
import com.twitter.util.Future
import java.net.InetSocketAddress
import util.Properties
object Web {
def main(args: Array[String]) {
val port = Properties.envOrElse("PORT", "8080").toInt
println("Starting on port:"+port)
ServerBuilder()
.codec(Http())
.name("hello-server")
.bindTo(new InetSocketAddress(port))
.build(new Hello)
println("Started.")
}
}
class Hello extends Service[HttpRequest, HttpResponse] {
def apply(req: HttpRequest): Future[HttpResponse] = {
val response = Response()
response.setStatusCode(200)
response.setContentString("Hello World")
Future(response)
}
}
Herokuはアプリケーションを、project/build.properties
の存在によって認識をします。
sbt.version=0.12.0
sbtと一緒に、lightやfullのビルド構成を使用する事ができます。私たちはlightの構成を使用していきます。ルートディレクトリの中にあるbuild.sbt
に依存ファイルを宣言してきます :
import com.typesafe.startscript.StartScriptPlugin
seq(StartScriptPlugin.startScriptForClassesSettings: _*)
name := "hello"
version := "1.0"
scalaVersion := "2.9.2"
resolvers += "twitter-repo" at "http://maven.twttr.com"
libraryDependencies ++= Seq("com.twitter" % "finagle-core" % "1.9.0", "com.twitter" % "finagle-http" % "1.9.0")
デプロイ時に、HerokuはあなたのScalaアプリケーションをビルドするためにsbt clean compile stage
を実行します。sbt-start-script
は、あなたのアプリケーションのためのスタートスクリプトを生成するsbtにstage
タスクを追加します。
このプラグインを使用するためには、このファイルを作成します :
resolvers += Classpaths.typesafeResolver
addSbtPlugin("com.typesafe.startscript" % "xsbt-start-script-plugin" % "0.5.3")
このstage
タスクは、慣習によって、適切に実行されるためのアプリケーションの準備のために必要とされるタスクを実行します。実行のためのアプリケーションの準備に対してのアプローチがが違う他のプラグインも同様に、stage
を定義していることがあります。
デフォルトではOpenJDK1.6がインストールされています。ですが、新しいJDKを使う事もできます。使う場合はsystem.properties
ファイルの中にjava.runtime.version=1.7
と指定します。
system.properties
はこのような見た目をしています :
java.runtime.version=1.7
Java 6, 7, 8(ラムダ式が使えます) のそれぞれで、1.6, 1.7, 1.8(1.8はベータです)を指定することができます。
ローカルであなたのアプリケーションをビルドします :
$ sbt clean compile stage
...
[info] Compiling 1 Scala source to .../target/scala-2.9.2/classes...
[success] Total time: 5 s, completed Sep 5, 2012 12:42:56 PM
[info] Wrote start script for mainClass := Some(Web) to .../target/start
[success] Total time: 0 s, completed Sep 5, 2012 12:42:56 PM
アプリケーションのルートディレクトリにあるテキストファイルであるProcfileを使って、Web Dynoを開始させるために何のコマンドを実行するべきかを明示的に宣言します。今回は、Web
メインメソッドを実行する必要があります。
私たちが上で追加した xsbt-start-script-plugin
はtarget/start
内にスタートスクリプトを生成します。 このシンプルなシェルスクリプトはCLASSPATH
を設定し、あなたが明示したオブジェクトのメインメソッドを実行してくれます。あなたのProcfileから叩いてみましょう :
web: target/start Web
これは、1個のweb
プロセスタイプと実行する必要のあるコマンドを宣言しています。"web"と付けることはここではとても重要です。これは、このプロセスタイプがHerokuのHTTPルーティングのスタックに積まれ、デプロイされた際にWebトラフィックを受け付けることを意味しています。
これでForeman を使って、ローカルであなたのアプリケーションを開始出来るようになりました。(Toolbeltの一部としてインストールされています) :
$ foreman start
11:53:15 web.1 | started with pid 2281
11:53:15 web.1 | Starting on port:5000
11:53:15 web.1 | Started.
アプリケーションが5000番ポートで立ち上がります。curl
やブラウザで適切に動いているかを確認した上で、Ctrl-Cで終了します。
ビルド時の生成物がバージョン管理の中に含まれるのを防ぐために、.gitignore
ファイルを作成します :
target
project/boot
project/target
project/plugins/target
今、私たちはアプリの中に3つの主要な構成要素を持っています。build.sbt
の中の依存関係ファイル、Procfile
の中のプロセスタイプ、そしてsrc/main/Web.scala
の中にある私たちのアプリのソースです。Gitに追加していきましょう :
$ git init
$ git add .
$ git commit -m "init"
(Herokuの)アプリケーションを作成します :
$ heroku create
Creating warm-frost-1289... done, stack is cedar
http://warm-frost-1289.herokuapp.com/ | [email protected]:warm-frost-1289.git
Git remote heroku added
コードをデプロイします :
$ git push heroku master
Counting objects: 14, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (14/14), 1.51 KiB, done.
Total 14 (delta 1), reused 0 (delta 0)
-----> Heroku receiving push
-----> Scala app detected
-----> Building app with sbt
-----> Running: sbt clean compile stage
Getting net.java.dev.jna jna 3.2.3 ...
...
[info] Compiling 1 Scala source to /tmp/build_1otpp7ujqznr3/target/scala-2.9.2/classes...
[success] Total time: 1 s, completed Sep 5, 2012 7:26:27 PM
[info] Wrote start script for mainClass := Some(Web) to /tmp/build_1otpp7ujqznr3/target/start
[success] Total time: 0 s, completed Sep 5, 2012 7:26:27 PM
-----> Discovering process types
Procfile declares types -> web
-----> Compiled slug size is 43.1MB
-----> Launching... done, v3
http://warm-frost-1289.herokuapp.com deployed to Heroku
To [email protected]:warm-frost-1289.git
* [new branch] master -> master
Herokuにコードをデプロイしました、そしてProcfile
の中にプロセスタイプを指定しました。今、あなたはHerokuに対してプロセスタイプを実行するための指示を出す事が出来ます。Herokuはdynoに関連づいたコマンドを実行することでこれを行います。dynoとはHerokuにおける基本的な構成要素の単位になっている軽量コンテナのことです。
web
プロセスタイプが実行されているdynoがあることを確かめてみましょう :
$ heroku ps:scale web=1
アプリケーションのdynoの状態を確認することができます。このheroku ps
コマンドはあなたのアプリケーションの実行中のdynoをリストします :
$ heroku ps
=== web: `target/start Web`
web.1: up for 5s
ここにdynoが一つ走っています。
heroku open
を使ってブラウザでアプリを確認することができます。
$ heroku open
Opening warm-frost-1289... done
実行中のWeb dynoを一つだけ持っている事は、dynoが非アクティブになったあと1時間経つとスリープすることを意味します。これは再度立ち上がるときの最初のリクエストに対して数秒の遅れが発生することを意味します。後続のリクエストは通常通りに帰ってくるでしょう。
これを避けるために、web dynoを1個以上に増やすことが出来ます。例えば :
$ heroku ps:scale web=2
それぞれのアプリケーションごとに、Herokuは750時間のdyno無料利用時間を提供しています。2個のdynoで動いているアプリケーションは、月々のこの無料利用時間を超える可能性が高いので、増やしたものを戻してみましょう :
$ heroku ps:scale web=1
Herokuは、アプリケーションの内容物を実行しているすべてのdynoの出力ストリームから時系列イベントのストリームとしてログを扱います。HerokuのLogplexはこれらのイベントの全てをあつかう単体のチャネルを提供しています。
ログ用コマンドの一つを使って、実行中のあなたのアプリケーションの情報を見てみましょう。heroku logs
を実行します。 :
$ heroku logs
2011-08-18T00:13:41+00:00 heroku[web.1]: Starting process with command `target/start Web `
2011-08-18T00:14:18+00:00 app[web.1]: Starting on port:28328
2011-08-18T00:14:18+00:00 app[web.1]: Started.
2011-08-18T00:14:19+00:00 heroku[web.1]: State changed from starting to up
Herokuでは、必要な時にスクリプトとそのためだけに実行されるアプリケーションであるone-off dynoの中で、heroku run
を使って、コマンドを実行することが可能です。 あなたのアプリケーションの環境の中で実験のために、ローカルのターミナルでREPLプロセスを実行するためにこれを使います :
$ heroku run sbt console
Running sbt console attached to terminal... up, run.1
[info] Loading global plugins from /app/.sbt_home/.sbt/plugins
[info] Updating {file:/app/.sbt_home/.sbt/plugins/}default-0f55ac...
...
[info] Done updating.
[info] Compiling 1 Scala source to /app/.sbt_home/.sbt/plugins/target/scala-2.9.2/sbt-0.12/classes...
[info] Loading project definition from /app/project
[info] Updating {file:/app/project/}default-525df6...
...
[info] Done updating.
[info] Set current project to hello (in build file:/app/)
[info] Updating {file:/app/}default-0c35ee...
[info] Done updating.
[info] Compiling 1 Scala source to /app/target/scala-2.9.2/classes...
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.9.2 (OpenJDK 64-Bit Server VM, Java 1.6.0_20)
Type in expressions to have them evaluated.
Type :help for more information.
scala>
このコンソールはあなたのアプリケーションのコードを利用可能な物にします。例えば以下のようにです :
scala> Web.main(Array())
Starting on port:33418
Started.
main
メソッドがそのオブジェクトに存在する限り、ターミナルに呼び出されたOne-off Dynoの中であなたは、アプリケーションのあらゆるオブジェクトを実行することができます。例えば以下のようにです :
object Demo {
def main(args:Array[String]){
println("Hello From Demo")
}
}
コミットしてデプロイをします :
$ git add src/main/scala/Demo.scala
$ git commit -m "demo class"
$ git push heroku master
そして、One-offプロセスを実行します :
$ heroku run 'target/start Demo'
Running target/start Demo attached to terminal... up, run.1
Hello From Demo
sbtは過去数年の間に急速な開発がなされてきました、そのためメジャーリリースはそれぞれ互換性がありません。最たる問題として、sbtのバージョンの不一致に関するものが出てくるでしょう。
- もし
sbt
と名の付いたパスが通っているスクリプトとして、sbt 0.7.x や sbt 0.10.x がインストールされている場合、そのパスの名前をsbt7
やsbt10
のようなものに変更するべきです。 - もしこのプロジェクトをsbt 0.7.x を使ってビルドしようとすると、プロジェクトのクリエイションプロンプトが確認できるでしょう。もしこんなプロンプトを確認した場合は、sbtを終了し、
sbt
がsbt 0.11.0かそれ以降を実行しているか確認をしてください。 - もしこのプロジェクトをsbt 0.10.x を使ってビルドしようとすると、
org.scala-tools.sbt#sbt_2.9.2;0.11.0: not found
という未解決な依存ファイルによるエラーを得る事になるでしょう。もしこのエラーを見たら、sbt
がsbt 0.11.0かそれ以降を実行しているか確認をしてください。
- Scalaアプリケーションの開発とデプロイについて更に学ぶためにScala categoryへ訪問しましょう。
- HerokuでのAkkaとScalaを使ったスケールアウトはAkkaとScalaの使用について詳しく書かれています。
- Heroku Scala サポートはHerokuのScalaのサポートについてのリファレンスドキュメントを提供しています。
- アプリケーションを書いたり、構成したり、デプロイしたり、実行する時に直面するだろう概念について、技術的な大枠を知りたい場合はHerokuの仕組みを読むといいかもしれません。