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:
- In the terminal, run
sbtin the root of your project working directory
- Once in the console, enter
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
Lets see how big this image is:
docker pull openjdk:latest docker images
The output of the
docker images is:
REPOSITORY TAG IMAGE ID CREATED SIZE 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:
- Images based on Ubuntu
- 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:
- We can add a docker RUN command to install bash into our SBT native packager Dockerfile settings.
- We can look for an existing image with bash installed
For the first option, we can add our RUN command to the SBT setting
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
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.