Master Docker: 10 Essential Best Practices for Secure, Efficient Java Containers
This guide walks you through ten practical Docker best‑practice steps—from using deterministic image tags and minimal base images to multi‑stage builds, non‑root users, PID‑1 handling, graceful shutdown, .dockerignore usage, container‑aware JVM settings, and cautious adoption of automation tools—ensuring your Java applications run securely and efficiently in production containers.
Want to build a Java application and run it in Docker? This cheat‑sheet provides production‑grade best practices for creating secure, efficient Java container images.
1. Use deterministic image tags
Instead of pulling the latest maven image, specify an exact version and SHA to guarantee reproducible builds.
FROM maven:3.6.3-jdk-11-slim@sha256:68ce1cd457891f48d1e137c7d6a4493f60843e84c9e2634e3df1d3d5b381d36c2. Install only what you need
Build the JAR in a Maven stage, then copy only the compiled artifact into a minimal JRE base image.
FROM openjdk:11-jre-slim@sha256:31a5d3fa2942eea891cf954f7d07359e09cf1b1f3d35fb32fedebb1e3399fc9e
RUN mkdir /app
COPY ./target/java-application.jar /app/java-application.jar
WORKDIR /app
CMD "java" "-jar" "java-application.jar"3. Use multi‑stage builds
Separate the build environment from the final runtime image to keep the production image small and free of build tools.
FROM maven:3.6.3-jdk-11-slim@sha256:... AS build
RUN mkdir /project
COPY . /project
WORKDIR /project
RUN mvn clean package -DskipTests
FROM adoptopenjdk/openjdk11:jre-11.0.9.1_1-alpine@sha256:...
COPY --from=build /project/target/java-application.jar /app/java-application.jar
WORKDIR /app
CMD "java" "-jar" "java-application.jar"4. Prevent sensitive data leaks
Copy only required files in the final stage and keep credentials out of the runtime image; use .dockerignore to exclude unnecessary files.
.dockerignore
**/*.log
.git
.gitignore5. Do not run as root
Create a low‑privilege user and switch to it before starting the application.
RUN addgroup --system javauser && adduser -S -s /bin/false -G javauser javauser
COPY --from=build /project/target/java-application.jar /app/java-application.jar
RUN chown -R javauser:javauser /app
USER javauser
CMD "java" "-jar" "java-application.jar"6. Avoid PID 1 issues
Use dumb-init as the entrypoint so signals are correctly forwarded.
RUN apk add dumb-init
CMD "dumb-init" "java" "-jar" "java-application.jar"7. Graceful shutdown
Add a JVM shutdown hook to cleanly stop the application when it receives SIGINT or SIGTERM.
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("Inside Add Shutdown Hook");
}
});8. Use a .dockerignore file
Exclude build‑only files, logs, and credentials to keep the image tidy and secure.
.dockerignore
**/*.log
.git
.gitignore9. Ensure Java version supports containers
JVMs prior to Java 10 ignore container limits. Upgrade to Java 10+ or at least Java 8u191 with
-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeapto enable container awareness.
-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap10. Be cautious with automated tools
Tools like JIB can simplify image creation, but manual Dockerfiles give you full control over security and size. If you use such tools, still verify the resulting image for vulnerabilities.
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>2.7.1</version>
</plugin>Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
