Get started with your SpringBoot App in seconds. Use your favorite builder (Gradle or Maven) and choose your version of JRE - without needing to manage a complex maze of non-business logic steps in your Dockerfiles!
- No more copy-and-paste Dockerfile boilerplate code for your App's Runnable Jars!
- We use the Builder Pattern for Gradle and Maven
- Decoupled way to run your application in different JVMs
- Our parameterized builds allows you to just select which JVM implementation to run!
- Enterprise-friendly: Pick and choose the base images for your applications and push to your internal Docker Registry!
Builder
: Any Java build system.-
Maven
different base Operating Systems. -
Gradle
different base Operating Systems. -
Bazel
Waiting for contributions.
-
Linker
: Any JDK 9+ with support tojlink
to generate custom JVMs tailored for your application.jar
-
OpenJDK on Alpine
musl` -
OpenJDK on Debian
glibc`
-
Runner
: Any JVM available to the Custom JVMs generated by theLinker
for your application.
All images are located at the DockerHub Intuit Repository.
- Create a Dockerfile selecting the first stage the Builder image
This step requires the inspection of the build system used and the target JVM instructions used.
For instance, the Kotlin tutorial uses Gradle and JDK8. For this reason, the builder image selected is using Gradle with JDK8 (See the dir samples/gradle-kotlin-jdk8-jre8
for details)
- If the project is to run in a JRE 8, then select the Runner image with the base OS desired
Since the Kotlin tutorial simply runs the application, then we just selected the base image with JRE8. That simplified the initial process of using the current tutorial.
- If your team is already required to migrate to JRE11 using the current code, then select a Linker image to create a custom JRE for your application based on the
.jar
produced by the Builder image.
This requires a matching base image with a matching OS type. For instance, if you will run on Alpine, then select a Linker image on Alpine with the JDK11 type (See the dir samples/gradle-java-jdk8-x-jre11-custom-alpine
for details)
Implementation of a set of ONBUILD
instructions that are reusable for any SpringBoot Application:
- Injection of env vars such as
GIT_SHA
,GIT_BRANCH
andBUILD_NUMBER
for versioning. - Supports the following builders:
- Gradle 4.x.x + openjdk 1.8
- Maven 3.x.x + openjdk 1.8
- Gradle 4.x.x + openjdk 1.11
- Gradle 5.x.x + openjdk 1.12
- Maven 3.x.x + openjdk 1.11
- Maven 3.x.x + openjdk 1.12
Implementation of the call using jlink
to create a custom VM for your application based on the generated Jar.
- Custom Runners will consume the linker JVM.
Implementation of all tasks to execute a runnable WAR
from a SpringBoot application.
- Uses the built executable file to the appropriate directory.
- Prepares the image with underlying capabilities to make TLS calls.
- Uses small JRE images.
- Supports the following Runners:
- JRE Slim 1.8
- JRE Slim 1.11
- JRE Slim 1.12
- JRE Alpine 1.11
- JRE Alpine 1.12
Implementation of samples using the Docker Images for both builder
and runner
.
Look at the directory samples
for details.
- Samples with the following:
- Java/Gradle SpringBoot 2.x with JRE Slim 1.8
- Java/Gradle SpringBoot 2.x with JRE Slim 1.11
- Java/Gradle SpringBoot 2.x with JRE Slim 1.12
- Kotlin/Gradle SpringBoot 2.x with JRE Slim 1.8
- Kotlin/Gradle SpringBoot 2.x with JRE Slim 1.11
-
Gradle version is latest 5.0.0, currently at 4.10.1 with OpenJDK 1.8
-
Uses Gradle as the builder tool and requires:
build.gradle
: Main build filesettings.gradle
: Project settings
-
Regular Java project using maven structure
src
: java source directory with any code
Requires the use of the following build args
BUILDER_GIT_SHA
: the current sha of the projectBUILDER_GIT_BRANCH
: the current branch of the projectBUILDER_GRADLE_BUILD_CMD
: the command used to build the executablejar
orwar
gradle bootRepackage
orgradle build
- https://docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/html/build-tool-plugins-gradle-plugin.html#build-tool-plugins-gradle-packaging
If you use gradle, declare your images with the dependency to gradle. Note that builder image
must be annotated as unmazedboot-builder-artifacts
, so that the runner knows where to get the built artifacts from.
- The builder should be the first image of the Dockerfile
- It can also include additional steps required by the builder such as installing new dependencies, etc.
FROM unmazedboot/builder:gradle4.10.2-jdk8-alpine as unmazedboot-builder-artifacts
RUN echo "You can add extra packages or anything needed to the final image for building"
- Latest Maven version with versions
- Uses Maven as the builder tool and requires:
pom.xml
: Main build filesettings.xml
: Project settings
- Regular Java project using maven structure
src
: java source directory with any structure
Requires the use of the following build args
BUILDER_GIT_SHA
: the current sha of the projectBUILDER_GIT_BRANCH
: the current branch of the projectBUILDER_MAVEN_BUILD_CMD
: the command used to build the executablejar
orwar
mvn -s settings.xml install -P embedded
BUILDER_DIR
: The directory containing the executable file.- Default Gradle directory is
build/libs
- Default Maven directory is
target
- Default Gradle directory is
- The runner image is the same for any builder supported
- Gradle
- Maven
- The single image simplifies the whole process and requires a couple of args
- Entrypoint defined as
start.sh
with the following capabilities- Sources a group of files under the
/runtime/sources/*.sh
dir - Creates JAVA_OPTS based on values under
/runtime/java-opts/*.opt
- Executes a default command provided, showing debug information
- Sources a group of files under the
Those are the runtime information important when deploying springboot in Docker/Kubernetes environments. In addition:
/runtime/sources
gives you a mount path to execute additional app-based hooks- You can use side-cars during Kubernetes deployments
runtime/java-opts
are values that comes from sidecars or secret values
Requires the use of the following build args to build, providing optional values.
RUNNER_EXTENSION
: the extension of the executable binary- Gradle has plenty of examples with
jar
andwar
files.
- Gradle has plenty of examples with
RUNNER_PORT
: the port to use in theEXPOSE
instruction in the final Docker ImageRUNNER_HOOKS_DIR_SOURCES
: the sources directory to be executed before executingRUNNER_ENV_HOOK_VAR
: the name of the env to be populated with contents fromRUNNER_HOOKS_ENV_VAR_DIR
- Defaults to
JAVA_OPTS
- Defaults to
RUNNER_HOOKS_ENV_VAR_DIR
: the directory with contents to be concatenated as value forRUNNER_ENV_HOOK_VAR
- Those values for
mem
,agents
, etc.
- Those values for
RUNNER_CMD_EXEC
: The command to execute after the sources and var has been processed.- source
RUNNER_HOOKS_DIR_SOURCES/*.sh
RUNNER_ENV_HOOK_VAR
=concat of allRUNNER_HOOKS_ENV_VAR_DIR/*.opt
RUNNER_CMD_EXEC
is executed, already set for runnable springboot apps
- source
This runnable image will require any stage of the Dockerfile to be named as unmazedboot-builder-artifacts
as shown above.
- The runner is the last image in the
Dockerfile
without any stage name.- It also should be specified the tag referring to the supported runtime.
- The version supported is the tag with the kind of JRE to use.
FROM intuit/unmazedboot:runner-openjdk-8-jre-slim
RUN echo "You can include more libraries or anything in the Runnable image"
- Provide the build args as needed.
- You can use the default images.
- See the samples for details
- See the runner Dockerfile for details
Go to the directory sample
directory for more details.
Building all samples in parallel (docker-compose version 1.23.1, build b02f1306
)
$ docker-compose -f docker-compose-samples.yaml build --parallel
Building sample-gradle-java-jre8 ...
Building sample-gradle-java-jre10 ...
Building samples-gradle-java-custom-jre10 ...
Building sample-gradle-java-jre8
Building samples-gradle-java-custom-jre10
Building sample-gradle-java-jre10
- It's common to add the creation of
JAVA_OPTS
either in a shell script or a concatenation of all things needed.- In addition, JAVA_OPTS may depend on agents available in given environments
- For a given environment, you can inject sources that will compute what's needed
- In this case, something that is run before JAVA_OPTS gets created.
The support for hooks is added as a feature that uses an environment injector
pattern. This is useful when dealing with containers in Kubernetes that are
initialized via InitContainer
and requires sources. There are 2 types as explained
above and the sample is in JDK 11 cross-compiled
$ docker-compose -f docker-compose-samples.yaml up --build samples-gradle-java-jdk8-x-jre-custom-11
Building samples-gradle-java-jdk8-x-jre-custom-11
Step 1/10 : ARG BUILDER_GIT_SHA=${GIT_SHA:-0101010}
Step 2/10 : ARG BUILDER_GIT_BRANCH=${GIT_BRANCH:-develop}
Step 3/10 : ARG BUILDER_BUILD_NUMBER=${BUILD_NUMBER:-0223}
Step 4/10 : ARG BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD="gradle downloadDependencies"
Step 5/10 : ARG BUILDER_GRADLE_BUILD_CMD="gradle build -x test"
Step 6/10 : ARG BUILDER_DIR="build/libs"
Step 7/10 : ARG RUNNER_EXTENSION="jar"
Step 8/10 : ARG RUNNER_PORT="8080"
Step 9/10 : FROM unmazedboot/builder:gradle-4-jdk8-x-jdk11 as unmazedboot-builder-artifacts
# Executing 18 build triggers
---> Using cache
...
...
---> Using cache
---> dd9c8589da4c
Step 10/10 : FROM unmazedboot/runner:jre8-x-jre11-custom
# Executing 34 build triggers
---> Using cache
...
...
---> Using cache
---> 73f12942ee77
Successfully built 73f12942ee77
Successfully tagged sample-jdk8-x-jre11-custom:latest
Starting springboot-docker-reusable-images_samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 ... done
Attaching to springboot-docker-reusable-images_samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 |
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | => Initializing SpringBoot Runner 'start.sh'
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 |
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | => Processing env hooks at /runtime/sources
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 |
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | [1] source /runtime/sources/myself.sh
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 |
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | => Processing hooks at /runtime/java-opts
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 |
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | [1] << /runtime/java-opts/mem.opt
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 |
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | Exporting JAVA_OPTS= -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:+UseStringDeduplication -XX:MaxRAMFraction=2 -XshowSettings:vm
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 |
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | ####### Debugging env before app start ##########
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 |
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | DEBUG_ENV=true
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | HOSTNAME=dc6ede09cd5b
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | JAVA_OPTS= -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:+UseStringDeduplication -XX:MaxRAMFraction=2 -XshowSettings:vm
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | JAVA_HOME=/opt/jdk-custom/jre
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | RUNNER_EXTENSION=jar
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | BUILDER_DIR=build/libs
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | RUNNER_PORT=8080
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | RUNNER_HOOKS_ENV_VAR_DIR=/runtime/java-opts
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | PWD=/runtime
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | HOME=/root
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | NAME=Marcello
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | RUNNER_CMD_EXEC=java $JAVA_OPTS -jar /runtime/server.jar $JAR_OPTS
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | APP_TIMEZONE=PST
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | CITY=San Diego
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | SHLVL=1
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | RUNNER_HOOKS_DIR_SOURCES=/runtime/sources
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/jdk-custom/jre/bin
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | _=/usr/bin/env
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 |
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | Starting the app
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | java $JAVA_OPTS -jar /runtime/server.jar $JAR_OPTS
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 |
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | OpenJDK 64-Bit Server VM warning: Option MaxRAMFraction was deprecated in version 10.0 and will likely be removed in a future release.
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | VM settings:
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | Max. Heap Size (Estimated): 3.89G
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | Using VM: OpenJDK 64-Bit Server VM
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 |
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 |
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | . ____ _ __ _ _
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | \\/ ___)| |_)| | | | | || (_| | ) ) ) )
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | ' |____| .__|_| |_|_| |_\__, | / / / /
samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | =========|_|==============|___/=/_/_/_/
- Execute the sample for more details
$ docker-compose -f docker-compose-samples.yaml up
- See Contributing
- We use GitLab Build Pipelines
- Deployments are from the Master Branch
- Docker Images will be pushed to Docker Registry available at hub.docker.com