Skip to content
kenji yoshida edited this page Aug 13, 2013 · 5 revisions

このチュートリアルはHerokuにデプロイされるScalaとFinagleウェブライブラリについて扱っていきます。

事前準備/前提条件

ローカルの開発環境の設定

始めに、Heroku Toolbeltをローカルにインストール します。これはあなたのHeroku command-line client、Foreman、そしてGitのバージョン管理システムへアクセスを確かなものにします。

一度インストールできると、herokuコマンドがシェルから使えるようになります。アカウントを作ったときに使ったE-mailアドレスやパスワードを使ってログインしてみます :

$ heroku login
Enter your Heroku credentials.
Email: adam@example.com
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"のソースコードを用意しています :

src/main/scala/Web.scala

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)
  }
}

sbtを使った依存ファイル郡の宣言

Herokuはアプリケーションを、project/build.propertiesの存在によって認識をします。

project/build.properties

sbt.version=0.12.0

sbtと一緒に、lightfullのビルド構成を使用する事ができます。私たちはlightの構成を使用していきます。ルートディレクトリの中にあるbuild.sbtに依存ファイルを宣言してきます :

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タスクを追加します。

このプラグインを使用するためには、このファイルを作成します :

project/build.sbt

resolvers += Classpaths.typesafeResolver

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

このstageタスクは、慣習によって、適切に実行されるためのアプリケーションの準備のために必要とされるタスクを実行します。実行のためのアプリケーションの準備に対してのアプローチがが違う他のプラグインも同様に、stageを定義していることがあります。

(オプションとして)JDKを選択

デフォルトでは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へのプロセスタイプの宣言

アプリケーションのルートディレクトリにあるテキストファイルであるProcfileを使って、Web Dynoを開始させるために何のコマンドを実行するべきかを明示的に宣言します。今回は、Webメインメソッドを実行する必要があります。

私たちが上で追加した xsbt-start-script-plugintarget/start内にスタートスクリプトを生成します。 このシンプルなシェルスクリプトはCLASSPATHを設定し、あなたが明示したオブジェクトのメインメソッドを実行してくれます。あなたのProcfileから叩いてみましょう :

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で終了します。

Gitへのあなたのアプリケーションの格納

ビルド時の生成物がバージョン管理の中に含まれるのを防ぐために、.gitignoreファイルを作成します :

.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の)アプリケーションを作成します :

$ heroku create
Creating warm-frost-1289... done, stack is cedar
http://warm-frost-1289.herokuapp.com/ | git@heroku.com: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 git@heroku.com: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

Dynoのスリープと拡張

実行中の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.

One-off Dyno

mainメソッドがそのオブジェクトに存在する限り、ターミナルに呼び出されたOne-off Dynoの中であなたは、アプリケーションのあらゆるオブジェクトを実行することができます。例えば以下のようにです :

src/main/scala/Demo.scala

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 がインストールされている場合、そのパスの名前をsbt7sbt10のようなものに変更するべきです。
  • もしこのプロジェクトを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の仕組みを読むといいかもしれません。
Clone this wiki locally