Dockerizing a Scala Play application

23 August 2017

Docker is one of the most popular container technologies in the IT world nowadays. It provides many benefits such as portability and component isolation along some other features. For more info: Docker

In this example we are going to dockerize a sample REST API which is built using Scala 2.11.11 and Play Framework 2.6.3.

Sample Play Docker app - how to run

Clone the project

git clone https://github.com/guilhebl/play-scala-rest-api-example

compile and run

sbt run

Check your app at localhost:9000

Sample JSON output (http://localhost:9000/v1/posts):

[
   {
      "id":"1",
      "link":"/v1/posts/1",
      "title":"title 1",
      "body":"blog post 1"
   },
   {
"id":"2", "link":"/v1/posts/2", "title":"title 2", "body":"blog post 2" }, {
"id":"3", "link":"/v1/posts/3", "title":"title 3", "body":"blog post 3" }, {
"id":"4", "link":"/v1/posts/4", "title":"title 4", "body":"blog post 4" }, {
"id":"5", "link":"/v1/posts/5", "title":"title 5", "body":"blog post 5" } ]

How to run an app instance inside a Docker container

In order to dockerize your play rest api example run the following steps:

Generate secret key - since docker will host our production app we need to generate a secret key.

sbt playGenerateSecret

copy the secret key (for example: "YtvWptxIlpf@Q[_dPvE[Z6NLAh_KU0YlGvwnN7sV8DKSk>PSBNbzarVp8j?=;l/y")

Create a new prod dist

sbt dist

Generate a new local Docker image

sbt docker:publishLocal

Run the play app inside a docker container
  • replace with your generated key

docker run -p 9000:9000 -e APPLICATION_SECRET="YtvWptxIlpf@Q[_dPvE[Z6NLAh_KU0YlGvwnN7sV8DKSk>PSBNbzarVp8j?=;l/y" play-scala-rest-api-example:1.0-SNAPSHOT

To check the running docker containers run:

docker ps -a

Output:

CONTAINER ID        IMAGE                                      COMMAND                  CREATED             STATUS                           PORTS                    NAMES
3d0bc5f7b2aa        play-scala-rest-api-example:1.0-SNAPSHOT   "bin/play-scala-re..."   20 seconds ago      Up 19 seconds                    0.0.0.0:9000->9000/tcp   admiring_darwin

Misc commands

to clean the image using sbt-native-packager

sbt docker:clean

  • In order to stop all running docker containers

docker stop $(docker ps -aq)

Docker configuration using sbt-native-packager

Add to build.sbt the sbt native docker configuration:

javaOptions in Universal ++= Seq(
  // JVM memory tuning
  "-J-Xmx1024m",
  "-J-Xms128m",
  // Since play uses separate pidfile we have to provide it with a proper path
  // name of the pid file must be play.pid
  s"-Dpidfile.path=/opt/docker/${packageName.value}/run/play.pid"
)

// use ++= to merge a sequence with an existing sequence dockerCommands ++= Seq( ExecCmd("RUN", "mkdir", s"/opt/docker/${packageName.value}"), ExecCmd("RUN", "mkdir", s"/opt/docker/${packageName.value}/run"), ExecCmd("RUN", "chown", "-R", "daemon:daemon", s"/opt/docker/${packageName.value}/") )

// exposing the play ports dockerExposedPorts in Docker := Seq(9000, 9443)

This will generate a

In our conf/application.conf file we need to change secret key to read from an ENV var:

 play.http.secret.key=${?APPLICATION_SECRET} 

This will generate a docker image based on openjdk In our conf/secure.conf we need to modify trusted proxies in order to load balance in cloud environments:

play {
  http {
    cookies.strict = true
    session.secure = true
    session.httpOnly = true
    flash.secure = true
    flash.httpOnly = true
    forwarded.trustedProxies = ["::1", "127.0.0.1"]
  }
  i18n {
    langCookieSecure = true
    langCookieHttpOnly = true
  }
  filters {
    csrf {
      cookie.secure = true
    }
    hosts {
      allowed = ["localhost:9443", "localhost:9000"]
    }
    hsts {
      maxAge = 1 minute # don't interfere with other projects
      secureHost = "localhost"
      securePort = 9443
    }
  }
}

comments powered by Disqus