If you have tried building a docker image using the SBT native packager you may have noticed that the docker image produced by the plugin is well over 700MB for a very basic Play Framework service.

Why is it so big?

So why is it that the images we produce via SBT native packager are so large?

It turns out that the base image used by the native packager is quite large on its own.

How do we check what the base image used by the plugin is?

In the root of your play project, start up the SBT console:

  1. In the terminal, run sbt in the root of your project working directory
  2. Once in the console, enter show dockerBaseImage

When you run the above command you should see something like:

$ sbt
[play-project] $ show dockerBaseImage
[info] openjdk:latest

What this tells us is that the base image used by the plugin is openjdk:latest

Lets see how big this image is:

docker pull openjdk:latest  
docker images  

The output of the docker images is:

openjdk     latest  a001fc27db5a   2 weeks ago   643.2 MB  

Thats right, the base image is 643.2 MB!

After looking at the openjdk Dockerhub page, we can see that there are two general flavours of the image:

  1. Images based on Ubuntu
  2. Images based on Alpine Linux

Alpine linux is a very minimalistic linux distribution which has a very small footprint as a docker image (~5MB). There is an image of openjdk based on alpine which is significantly smaller than its Ubuntu based counterpart.

So why don't we just use this smaller image as our base?

We can't just use this image directly since it does not have bash installed. When SBT native packager builds the docker image, it expects the base image to have bash installed so it can execute the startup script for the application.

We have a few options:

  1. We can add a docker RUN command to install bash into our SBT native packager Dockerfile settings.
  2. We can look for an existing image with bash installed

For the first option, we can add our RUN command to the SBT setting dockerCommands

See Adding Commands to Dockerfile SBT Native Packager

The command we would need to add to our Dockerfile would be along the lines of:

RUN apk add bash

This would install bash on Alpine.

An existing image

Luckily, there is already an existing image for Java on Alpine.

The image i'm using is anapsix/alpine-java:8

This image contains Oracle JRE 8 (we don't really need the JDK if we are only running our java apps) and bash.

Note: The openjdk image as the name implies, is using OpenJDK rather than Oracle Java like the image from anapsix.

Updating our build.sbt file

In order to make use of the more compact base image we need to add the following to our build.sbt:

dockerBaseImage := "anapsix/alpine-java:8"  

Thats it. This line will override the default base image setting for the native packager.

You should now be able to build much smaller images (~200MB) than with the default.