DEV Community

Alif Ruliarso
Alif Ruliarso

Posted on

2

Spring Boot Docker Images using JRE base

This is my attempt at creating a smaller Docker image for my Spring Boot application.

Development images

As a starting point, I use the Maven docker image based on Alpine Linux.

FROM maven:3.9.5-eclipse-temurin-21-alpine
RUN mkdir /app
WORKDIR /app

COPY pom.xml ./
RUN mvn dependency:go-offline

COPY docker-entrypoint-dev.sh ./
COPY src ./src
Enter fullscreen mode Exit fullscreen mode

docker-entrypoint-dev.sh

#!/bin/bash
export TERM=xterm
echo "wait 5s"
sleep 5

mvn spring-boot:run -Dspring-boot.run.jvmArguments="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" &

while true; do
    watch -d -t -g "ls -lR . | sha1sum" && mvn compile
done
Enter fullscreen mode Exit fullscreen mode

The above script executes spring-boot:run, then watch for source code changes, and compiles the Java code.

  • The watch command executes a program periodically, showing output fullscreen
  • The -d (--difference) option to view the changing output. This option will highlight the changes.
  • The -t (--no-title) option is used to turn off the header showing the interval, command, and the current time
  • By default, the watch command keeps running until it is interrupted manually by the user (Ctrl+C). However, sometimes instead of highlighting the changes, you’d prefer the watch command to exit when a change is detected completely. We can set watch to exit when the output from the command changes by using the -g (--chgexit) option.
  • ls -lR . | sha1sum Produces an sha1sum file source code

Final Image

After building my development image, I want to make the final image for deploying into the server.
To make the image smaller, I use the layering feature and multi-stage build.

Dockerfile

FROM maven:3.9.5-eclipse-temurin-21-alpine AS java-build

WORKDIR /app/

COPY .mvn/ .mvn
COPY pom.xml ./
RUN mvn dependency:go-offline

COPY src src
RUN mvn package
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)

FROM eclipse-temurin:21-jre-alpine

COPY --from=java-build /etc/passwd /etc/shadow /etc/
ARG DEPENDENCY=/app/target/dependency
# dependencies
COPY --from=java-build ${DEPENDENCY}/BOOT-INF/lib /app/lib
# metadata
COPY --from=java-build ${DEPENDENCY}/META-INF /app/META-INF
# java classes
COPY --from=java-build ${DEPENDENCY}/BOOT-INF/classes /app

ENV _JAVA_OPTIONS "-XX:MaxRAMPercentage=90 -Djava.security.egd=file:/dev/./urandom -Djava.awt.headless=true -Dfile.encoding=UTF-8"
ENTRYPOINT ["java","-cp","app:app/lib/*","com.galapea.techblog.springboot.onlinesurvey.SpringbootOnlineSurveyApplication"]
Enter fullscreen mode Exit fullscreen mode
  • First stage: extract the content of our fat Jar.
  • Second stage: copy application layers into the final docker image which only contains jre
  • Finally, run Java with a classpath definition, instead of a link to a JAR.

After making small code changes, I rebuilt the docker image, the previous layer didn't change java-build 2 to 5/8, taking advantage of the Docker cache (=> CACHED).

[+] Building 34.1s (19/19) FINISHED                                                                                                                                                              docker:default
 => [survey-app internal] load build definition from Dockerfile                                                                                                                                            0.1s
 => => transferring dockerfile: 839B                                                                                                                                                                       0.0s
 => [survey-app internal] load .dockerignore                                                                                                                                                               0.0s
 => => transferring context: 177B                                                                                                                                                                          0.0s
 => [survey-app internal] load metadata for docker.io/library/maven:3.9.5-eclipse-temurin-21-alpine                                                                                                        1.1s
 => [survey-app internal] load metadata for docker.io/library/eclipse-temurin:21-jre-alpine                                                                                                                1.1s
 => [survey-app java-build 1/8] FROM docker.io/library/maven:3.9.5-eclipse-temurin-21-alpine@sha256:c0f2d9ba99a1a3a0c95bdd7b1888fff4183e06fe8c5c3c8cb0c19dc7d1ab893b                                       0.0s
 => [survey-app stage-1 1/5] FROM docker.io/library/eclipse-temurin:21-jre-alpine@sha256:2a4755c16fe3390e6a89daed9adfc6d9dc7be116dfce84497cf84f761b973311                                                  0.0s
 => [survey-app internal] load build context                                                                                                                                                               0.0s
 => => transferring context: 8.94kB                                                                                                                                                                        0.0s
 => CACHED [survey-app java-build 2/8] WORKDIR /app/                                                                                                                                                       0.0s
 => CACHED [survey-app java-build 3/8] COPY .mvn/ .mvn                                                                                                                                                     0.0s
 => CACHED [survey-app java-build 4/8] COPY pom.xml ./                                                                                                                                                     0.0s
 => CACHED [survey-app java-build 5/8] RUN mvn dependency:go-offline                                                                                                                                       0.0s
 => [survey-app java-build 6/8] COPY src src                                                                                                                                                               0.1s
 => [survey-app java-build 7/8] RUN mvn package                                                                                                                                                           30.5s
 => [survey-app java-build 8/8] RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)                                                                                                 1.6s
 => CACHED [survey-app stage-1 2/5] COPY --from=java-build /etc/passwd /etc/shadow /etc/                                                                                                                   0.0s
 => CACHED [survey-app stage-1 3/5] COPY --from=java-build /app/target/dependency/BOOT-INF/lib /app/lib                                                                                                    0.0s
 => CACHED [survey-app stage-1 4/5] COPY --from=java-build /app/target/dependency/META-INF /app/META-INF                                                                                                   0.0s
 => [survey-app stage-1 5/5] COPY --from=java-build /app/target/dependency/BOOT-INF/classes /app                                                                                                           0.1s
 => [survey-app] exporting to image                                                                                                                                                                        0.1s
Enter fullscreen mode Exit fullscreen mode

And the final docker image.

Image description

In the next iteration, I will try to use Jlink.

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more