Dockerizing Scala Applications
If you are in doubt about using Docker, Google Trends says enough about its popularity.
Until a few release ago, it was quite a hassle to run Docker. However it has become stable lately. I have been using Docker for 1.5 years and my experience has been quite amazing. I love how I can run a Docker image built on my laptop in production without any headache. Also, it’s very easy to distribute a runnable image or run someone else’s image on your machine. You need Docker insatlled on your system and you can just run the application.
In this post, we are going to create Docker image for a simple Scala application.
What is Docker?
Docker is a tool designed to run applications in an isolated environment using containers. Containerization is an OS level virtualization method to run multiple systems on a single kernel without launching an entire virtual machine. On Linux based operating systems, it is achieved using LXC (Linux Containers). Docker uses built-in Linux containment features like CGroups, Namespaces, UnionFS, chroot to run applications in the virtual environment.
LXC is an API for Linux containment features. Initially, Docker was built on top of LXC. Starting with Docker 0.9, it has been replaced with libcontainer
.
To learn more about Docker, official documentation is a good place to start.
Docker with Scala Build
To create Docker image for a Scala application, we’ll use sbt-native-packager
.
sbt-native-packager focuses on creating a Docker image which can “just run” the application built by SBT.
To achieve this, a few entries have to added in settings
of project definition.
Let’s create Docker image for a simple service. Here is one that uses Akka HTTP. I just picked the first example I saw in Akka HTTP documentation. This service listens on 8080
and displays a simple hello page for /hello
path. Full code is available on GitHub.
To build Docker image for this service, project definition in Build.scala
looks like
L15 specifies the main class of the project.
L16 specifies a list of TCP ports to expose from the Docker image. Your application must be listening on one of these ports.
L17 specifies the entry point for Docker. This command will be executed when Docker container is run.
L18 specifies the repository to which the image should be pushed when docker:publish
is run.
L19 specifies the base image to be used when building Docker image for this project.
Run docker:publishLocal
after compilation to publish the Docker image locally.
Docker with Play Application
With Play framework, project definitions are written in build.sbt
by default. Here, root
or main
project definition looks like
L15 prevents Docker from creating images for the subprojects separately.
Build your own Baseimage
I personally prefer phusion/baseimage
which is a minimal Ubuntu baseimage. In a lot of cases, it so happens that you need some packages to run your applications. Rather than adding the code to install these packages in all build files separately, it’s easier to build an image containing all the packages and use it as baseimage for your projects.
For example, if you need Java installed, you can create a Dockerfile with following code and build your own baseimage.
Resources
- Example Code: https://github.com/neerajgangwar/dockerize-scala-app
- Official Docs: https://docs.docker.com
- sbt-native-packager: http://www.scala-sbt.org/sbt-native-packager/formats/docker.html