Dockerizing Spray HTTP Server

dockerspray

This is the continuation of the previous article. This series shows how simple it is to create a lightweight HTTP-server based on Spray framework, put it into a Docker-image and run multiple instances on any single machine requiring no dependencies.

Implementing a lightweight RESTful HTTP Service

The whole project can be found on GitHub. For impatient, git pull it and jump right to the next section. We’re going to use Scala and Akka framework along with SBT build tool. From Spray framework we will use a spray-routing module which has a simple routing DSL for elegantly defining RESTful web services and it works on top of a spray-can HTTP Server.

Ok, let’s get started.

import akka.actor.{ActorSystem}
import spray.routing._
import akka.util.Timeout
import scala.concurrent.duration._
import scala.util.{Failure, Success}

object HttpServer extends App with SimpleRoutingApp {

  implicit val actorSystem = ActorSystem()
  implicit val timeout = Timeout(1.second)
  import actorSystem.dispatcher

  startServer(interface = "localhost", port = 8080) {

    // GET /welcome --> "Welcome!" response
    get {
      path("welcome") {
        complete {
          <html>
            <h1>"Welcome!</h1>
            <p><a href="/terminate?method=post">Stop the server</a></p>
          </html>
        }
      }
    } ~
      // POST /terminate --> "The server is stopping" response
      (post | parameter('method ! "post")) {
        path("terminate") {
          complete {
            actorSystem.scheduler.scheduleOnce(1.second)(actorSystem.shutdown())(actorSystem.dispatcher)
            "The server is stopping"
          }
        }
      }
  }
    .onComplete {
    case Success(b) =>
      println("Successfully started")
    case Failure(ex) =>
      println(ex.getMessage)
      actorSystem.shutdown()
  }
}

The REST API is as follows:

  • GET/welcome –> responds with a “Welcome” and Post-hyperlink.
  • POST/terminate –> will stop the server.

DSL describing this API is inside of a method startServer.  And that’s it!

I didn’t want to show the full power of Spray because this article is solely about Docker.

Let’s run it and check:

curl http://localhost:8080/welcome

Dockerizing the server

Because the Docker Engine uses Linux-specific kernel features, I’m going to use lightweight virtual machine to run it on OS X. If you too, just download it, install and run – easy peasy. Just make sure before dockerizing that you’ve set the following 3 env variables for connecting your client to the VM:

export DOCKER_HOST=tcp://192.168.59.103:2376
export DOCKER_CERT_PATH=/Users/ivan/.boot2docker/certs/boot2docker-vm
export DOCKER_TLS_VERIFY=1

The remaining stuff doesn’t differ much.

We use a trusted automated java build (OpenJDK Java 7 JRE Dockerfile) as a base of our image.

First, you will need to create a Dockerfile for the image in your project:

# Our base image
FROM dockerfile/java

WORKDIR /

USER daemon

# Here the stuff that we're going to place into the image
ADD target/scala-2.11/docker-spray-http-server-assembly-1.0.jar /app/server.jar

# entry jar to be run in a container
ENTRYPOINT [ "java", "-jar", "/app/server.jar" ]

# HTTP port
EXPOSE 8080

Build your project as a single jar file:

DockerSprayHttpServer$ sbt assembly

And now navigate to the project’s folder and run:

DockerSprayHttpServer$ docker build .

This will send the newly created image to the Docker daemon.

Running multiple instances on a single machine

Run the following command to see available docker images :

DockerSprayHttpServer$ docker images

Снимок экрана 2014-12-15 в 23.48.52

a83cda03f529 is not in the repo yet – what we’ve just created. We’re going to run multiple instances from it.

First run the 1-st instance:

DockerSprayHttpServer$ docker run -d -p 10001:8080 a83cda03f529

Note, that we have mapped our 8080–>10001 port.

Now, let’s verify the container is running:

DockerSprayHttpServer$ docker ps

Снимок экрана 2014-12-16 в 0.58.12

We exposed port 8080 for the http-server. When run in Docker-container, it maps our port onto another. On top of this I am  on OS X. Do you remember we set at the beginning 3 env vars? One of them is DOCKER_HOST.

You can actually check this IP as follows:

DockerSprayHttpServer$ boot2docker ip

We need to use this IP address (for OS X, as we are not on Linux).

Let’s test it:

DockerSprayHttpServer$ curl $(boot2docker ip):10001/welcome

Great!

You can run as many containers as you want! They are completely isolated. For Scala developers, by they way, I’ve found a nice contribution, you can dockerize your artifacts right from SBT.