Akka Clustering with SBT-Docker and SBT-Native-Packager
Jun 19 2014Since my last post on akka clustering with docker containers a new plugin, SBT-Docker, has emerged which allows you to build docker containers directly from SBT. I’ve updated my akka-docker-cluster-example to leverage these two plugins for a smoother docker build experience.
One Step Build
The approach is basically the same as the previous example: we use SBT Native Packager to gather up the appropriate dependencies, upload them to the docker container, and create the entrypoint. I decided to keep the start script approach to “prep” any environment variables required before launching. With SBT Docker linked to Native Packager all you need to do is fire
docker
from sbt and you have a docker container ready to launch or push.
Understanding the Build
SBT Docker requires a dockerfile defined in your build. I want to pass in artifacts from native packager to docker. This allows native packager to focus on application needs while docker is focused on docker. Docker turns into just another type of package for your app.
We can pass in arguments by mapping the appropriate parameters to a function which returns the Dockerfile. In build.spt:
// Define a dockerfile, using parameters from native-packager dockerfile in docker <<= (name, stagingDirectory in Universal) map { case(appName, stageDir) => val workingDir = s"/opt/${appName}" new Dockerfile { //use java8 base box from("relateiq/oracle-java8") maintainer("Michael Hamrah") //expose our akka port expose(1600) //upload native-packager staging directory files add(stageDir, workingDir) //make files executable run("chmod", "+x", s"/opt/${appName}/bin/${appName}") run("chmod", "+x", s"/opt/${appName}/bin/start") //set working directory workDir(workingDir) //entrypoint into our start script entryPointShell(s"bin/start", appName, "$@") } }
Linking SBT Docker to SBT Native Packager
Because we’re relying on Native Packager to assemble our runtime dependencies we need to ensure the native packager files are “staged” before docker tries to upload them. Luckily it’s easy to create dependencies with SBT. We simply have docker depend on the native packager’s stage task:
docker <<= docker.dependsOn(com.typesafe.sbt.packager.universal.Keys.stage.in(Compile))
Adding Additional Files
The last step is to add our start script to the native packager build. Native packager has a mappings
key where we can add files to our package. I kept the start script in the docker folder and I want it in the bin directory within the docker container. Here’s the mapping:
mappings in Universal += baseDirectory.value / "docker" / "start" -> "bin/start"
With this setting everything will be assembled as needed and we can package to any type we want. Setting up a cluster with docker is the same as before:
docker run --name seed -i -t clustering docker run --name c1 -link seed:seed -i -t clustering
It’s interesting to note SBT Native Packager also has docker support, but it’s undocumented and doesn’t allow granular control over the Dockerfile output. Until SBT Native Packager fully supports docker output the SBT Docker plugin is a nice tool to package your sbt-based apps.