sbt uses a plugin called sbt-native-packager to allow conveniently packaging Java and Scala applications built using sbt as Docker images.
This plugin is automatically enabled and configured by the Lagom sbt plugin, so no setup is needed to use it.
By default, sbt native packager uses the
openjdk latest Docker image from DockerHub. At time of writing, this will give you OpenJDK 11, which is not certified by Lightbend, and it also gives you the Debian OpenJDK build, which is not certified by Lightbend either. For a full list of Lightbend certified JDK builds and versions, see here.
If you’re a RedHat customer, then you will probably want to use RedHat’s certified OpenJDK base image, which is using RHEL. These OpenJDK builds are certified by Lightbend too for use with Lightbend products. This can be configured using:
dockerBaseImage := "registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift"
Otherwise, we recommend using the AdoptOpenJDK base image:
dockerBaseImage := "adoptopenjdk/openjdk8"
This step is optional, but we recommend basing the version number of your application on the current git hash, since this ensures that you will always be able to map what is deployed to production back to the exact version of your application being used.
There are a number of sbt plugins available for generating a version number from a git hash, we’re going to use
sbt-dynver, which incorporates the most recent git tag as the base version number, appends the git hash to that only if there are any changes since that tag, and also includes a datetime stamp if there are local changes in the repository. To add this plugin to your project, add the following to
addSbtPlugin("com.dwijnand" % "sbt-dynver" % "3.3.0")
For the plugin to work, you need to ensure that you don’t specify a
version in your sbt build, since this will overwrite the version that
sbt-dynver generates. Additionally,
sbt-dynver generates versions with a
+ character in them (the
+ is used to indicate how many commits have been added since the last tag, so
1.0+4 indicates this is the 1.0 tag plus 4 commits). To replace this with a
- character, add the following to
version in ThisBuild ~= (_.replace('+', '-')) dynver in ThisBuild ~= (_.replace('+', '-'))
You may also want to configure the sbt native packager to tag your image as the
latest image, this will be necessary if you’re using the
latest tag in your deployment spec. To do this, enable
dockerUpdateLatest := true
After building the docker image, we will need to deploy it to the built in OpenShift docker registry. To do that, we need to configure both the docker username, which should equal the OpenShift project/namespace, as well as the registry. This can be done by configuring the
dockerUsername := sys.props.get("docker.username") dockerRepository := sys.props.get("docker.registry")
In this case, we’re reading both variables from system properties, which ensures that the build is not tied to any particular OpenShift installation. We’ll supply these system properties when we invoke sbt.
Now that we’re setup, we can build our docker image. Run the following:
sbt -Ddocker.username=$NAMESPACE -Ddocker.registry=$DOCKER_REPO_URL shopping-cart/docker:publish
This will build the project that you wish to build, tag it, and then push it to the configured OpenShift registry.
When you push a docker image to OpenShift’s internal registry, it will automatically create an image stream that the image can be consumed from.
Since we’re using Kubernetes deployments rather than OpenShift deployment configs, in order to ensure that our deployment can consume this from the internal OpenShift registry with an unqualified tag, we need to allow local lookups on it. This can be enabled by running the following command.
oc set image-lookup shopping-cart
For more information on image stream lookups, see the OpenShift documentation.