Help us understand the problem. What is going on with this article?

Finatra使ってみた

More than 3 years have passed since last update.

どうもこんにちは、久しぶりのScala投稿です。
今回も安定のdocker上でScalaを動かしていきたいと思います。
どうでもいいけど「〜てみた」というタイトルYouTuber感出るのであれですね…

環境のセットアップ

アプリケーションのディレクトリ構造はこんな感じ
シンプルにmain.scala内でサーバーとコントローラを宣言してます。

build.sbt
buildcache
project/
src/main/scala/main.scala

とりあえずdocker単体のコンテナで動かします。

使用イメージ: takashioshikawa/scala-2.11.7
ポート: 9000:9000
ボリューム: $(pwd)/buildcache/.ivy2/cache:/root/.ivy2/cache
ボリューム: $(pwd)/buildcache/.sbt/boot:/root/.sbt/boot
ボリューム: $(pwd):/var/app

くっっっっそ遅いビルドを少しでも高速化するためにキャッシュディレクトリをマウントしています。
これやっとかないとコンテナ消すたびに色々ダウンロードしだすので病みます
DockerでScalaを使う時のベストプラクティスがまだ分かってないので良い情報を持っている方はぜひ情報の方よろしくお願いします

最終的に実行するコマンドはこちら

docker run --rm -it -p 9000:9000 -v $(pwd)/buildcache/.ivy2/cache:/root/.ivy2/cache -v $(pwd)/buildcache/.sbt/boot:/root/.sbt/boot -v $(pwd):/var/app --name finatra-server takashioshikawa/scala-2.11.7

build.sbtとmain.scalaファイル

コピーしてもらえば動きます、多分

build.sbt
lazy val root = (project in file(".")).
  settings(
    name := "finatra-server",
    version := "1.0",
    scalaVersion := "2.11.7",
    libraryDependencies ++= dervy,
    resolvers ++= resolve
  )

lazy val dervy = {
  Seq(
    "com.twitter" % "finatra-http_2.11" % "2.6.0"
  )
}

lazy val resolve = {
  Seq(
    Resolver.sonatypeRepo("releases"),
    "Twitter Maven" at "https://maven.twttr.com"
  )
}
src/main/scala/main.scala
import com.twitter.finagle.Http
import com.twitter.finagle.http.Request
import com.twitter.finagle.stats.NullStatsReceiver
import com.twitter.finagle.tracing.NullTracer
import com.twitter.finatra.http.filters.HttpResponseFilter
import com.twitter.finatra.http.routing.HttpRouter
import com.twitter.finatra.http.{Controller, HttpServer}

object Main extends FinatraBenchmarkServer

class FinatraBenchmarkServer extends HttpServer {
  // 色々な設定項目はBaseHttpServerを参照
  // override def defaultFinatraHttpPort: String = ":9000"
  // override def defaultHttpServerName: String = "0.0.0.0"

  override def configureHttpServer(server: Http.Server) = {
    server
      .withCompressionLevel(0)
      .withStatsReceiver(NullStatsReceiver)
      .withTracer(NullTracer)
  }

  override def configureHttp(router: HttpRouter): Unit = {
    router
      .filter[HttpResponseFilter[Request]]
      .add[FinatraBenchmarkController]
  }
}

class FinatraBenchmarkController extends Controller {
  private[this] val helloWorldResponseText = "Hello, World!"

  get("/json") { request: Request =>
    Map("message" -> "Hello, World!")
  }

  get("/plaintext") { request: Request =>
    helloWorldResponseText
  }
}

finatraを起動する

コンテナ内に入っていると思うのでアプリケーションディレクトリに移動
cd /var/app

アプリケーションを起動してみましょう。

-http.port=:9000がポートの設定
-http.name=:0.0.0.0がホストの設定
0.0.0.0はdockerでlocalhostは使えないから

sbt 'run -http.port=:9000 -http.name=:0.0.0.0'

※FinatraBenchmarkServerにoverride def defaultFinatraHttpPort = ":9000"と書くとsbt run時じゃなくてもポートの設定が出来る
※FinatraBenchmarkServerにoverride def defaultHttpServerName: String = "0.0.0.0"と書くとsbt run時じゃなくてもサーバー名の設定ができる

上の2つを設定するとsbt runと実行するだけでsbt 'run -http.port=:9000 -http.name=:0.0.0.0'と同じ動作になる

なんか情報としてホストの設定が全然見つからなくてfinatraでは設定できない?と思ったけど普通にsbt runのエラーに出力されました

あとパラメータ入れる時は''で囲まないといけないっぽいので注意が必要です。

sbr 'run'の''の中に間違ったパラメータ入れると色々出てきます。

flags:
  -admin.announce='java.lang.String': Address for announcing admin server
  -admin.port=':9990': Admin http server port
  -cert.path='': path to SSL certificate
  -doc.root='': File serving directory/namespace for classpath resources
  -help='false': Show this help
  -http.announce='java.lang.String': Address for announcing HTTP server
  -http.name='http': Http server name
  -http.port=':8888': External HTTP server port
  -http.response.charset.enabled='true': Return HTTP Response Content-Type UTF-8 Charset
  -https.announce='java.lang.String': Address for announcing HTTPS server
  -https.name='https': Https server name
  -https.port='': HTTPs Port
  -key.path='': path to SSL key
  -local.doc.root='': File serving directory for local development
  -log.append='true': If true, appends to existing logfile. Otherwise, file is truncated.
  -log.async='true': Log asynchronously
  -log.async.inferClassNames='false': Infer class and method names synchronously. See com.twitter.logging.QueueingHandler
  -log.async.maxsize='4096': Max queue size for async logging
  -log.level='INFO': Log level
  -log.output='/dev/stderr': Output file
  -log.rollPolicy='Never': When or how frequently to roll the logfile. See com.twitter.logging.Policy#parse documentation for DSL details.
  -log.rotateCount='-1': How many rotated logfiles to keep around
  -maxRequestSize='5242880.bytes': HTTP(s) Max Request Size
  -mustache.templates.dir='templates': templates resource directory
  -shutdown.time='1.minutes': Maximum amount of time to wait for pending requests to complete on shutdown

ではサーバーが起動している状態で
main.scalaに設定されていたルーティングの/jsonを確認してみましょう

まずはdocker-machineのIPアドレスを確認して
docker-machine ip あなたのVM名

僕は192.168.99.100なので

192.168.99.100:9000/json
にアクセスします

ブラウザに表示された結果は以下の通りでした

json
{"message":"Hello, World!"}

plaintextも設定していた文字列がそのまま表示されました。

設定していないエンドポイントにアクセスしようとすると特に何の設定もされていない404ページが表示されました

今回はサンプルのリクエストを叩いてみるだけで終了します
次回があるかわかりませんが何かメモしたくなったらまた書きます

所感

なんか公式見ながらやっても普通に動かない印象がありました笑
とりあえずコピペしたらサーバーくらい起動するくらいが理想なのでそのへんは割りと不親切かもしれません。
あと日本語情報が少ないので英語少しくらい読めたほうが良いはず
僕自身Sprayが昔好きでakka-httpやろうかなと思ってたんですけどふと目に入ってきたので触ってみました、APIに特化してると軽量スタートできるのが嬉しいです。

今回はただサンプルのリクエストを行っただけなので全然全体の触り心地はわからないですが、もう少し何か作ってみて判断したいと思います。

参考

Finatra
finatraはじめの一歩
travis-ciのキャッシュ機能を使って、Scalaプロジェクトのビルドを少しだけ高速化する
Maven Repository finatra-http_2.11: 2.6.0

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away