0
0
Spring Bootframework~15 mins

Dockerfile for Spring Boot in Spring Boot - Deep Dive

Choose your learning style9 modes available
Overview - Dockerfile for Spring Boot
What is it?
A Dockerfile for Spring Boot is a text file that contains instructions to build a Docker image for a Spring Boot application. It tells Docker how to package the application and its environment so it can run anywhere. This file automates creating a container that includes the app and everything it needs to work.
Why it matters
Without a Dockerfile, packaging and running a Spring Boot app consistently across different computers or servers is hard. Developers would spend a lot of time setting up environments manually, leading to errors and delays. Dockerfiles solve this by making the app portable and easy to deploy anywhere, saving time and avoiding surprises.
Where it fits
Before learning Dockerfiles for Spring Boot, you should understand basic Docker concepts like images, containers, and commands. You also need to know how to build and run Spring Boot applications. After this, you can learn advanced Docker topics like multi-stage builds, orchestration with Kubernetes, and CI/CD pipelines using Docker images.
Mental Model
Core Idea
A Dockerfile is a recipe that tells Docker how to build a container image for your Spring Boot app, bundling code and environment together.
Think of it like...
It's like a cooking recipe that lists ingredients and steps to bake a cake, ensuring anyone can make the same cake with the same taste anywhere.
┌─────────────────────────────┐
│ Dockerfile Instructions      │
├─────────────────────────────┤
│ FROM openjdk:17-jdk-slim    │
│ COPY app.jar /app/app.jar   │
│ ENTRYPOINT ["java", "-jar", "/app/app.jar"] │
└─────────────────────────────┘
        ↓
┌─────────────────────────────┐
│ Docker Build Process         │
├─────────────────────────────┤
│ Reads Dockerfile             │
│ Creates Image Layers         │
│ Packages App & JDK           │
└─────────────────────────────┘
        ↓
┌─────────────────────────────┐
│ Docker Image                 │
│ (Portable Spring Boot App)  │
└─────────────────────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding Dockerfile Basics
🤔
Concept: Learn what a Dockerfile is and its role in containerizing applications.
A Dockerfile is a plain text file with instructions Docker uses to build an image. Each instruction creates a layer in the image. Common instructions include FROM (base image), COPY (copy files), RUN (execute commands), and ENTRYPOINT (start command). For Spring Boot, the Dockerfile packages the app and Java runtime together.
Result
You know how Dockerfiles define step-by-step how to build a container image.
Understanding Dockerfile basics is key because it shows how container images are built layer by layer, making apps portable.
2
FoundationSpring Boot Application Packaging
🤔
Concept: Learn how Spring Boot apps are packaged as executable JAR files.
Spring Boot apps are usually packaged as a single executable JAR file containing all dependencies and the embedded server. This JAR can run with 'java -jar app.jar'. This packaging style makes it easy to copy the app into a Docker image and run it without extra setup.
Result
You understand that the Spring Boot JAR is a self-contained app ready to run anywhere with Java.
Knowing the app is a single JAR simplifies Dockerfile creation because you only need to copy and run one file.
3
IntermediateWriting a Simple Dockerfile for Spring Boot
🤔Before reading on: do you think the Dockerfile needs to install Java manually or use a base image with Java? Commit to your answer.
Concept: Use a base image with Java installed and copy the Spring Boot JAR into it.
Start your Dockerfile with a base image that already has Java, like 'openjdk:17-jdk-slim'. Then copy your Spring Boot JAR into the image. Finally, set the ENTRYPOINT to run the JAR with 'java -jar'. Example: FROM openjdk:17-jdk-slim COPY target/app.jar /app/app.jar ENTRYPOINT ["java", "-jar", "/app/app.jar"]
Result
Docker builds an image that can run your Spring Boot app anywhere with Java 17.
Using a Java base image avoids manual Java installation, making the Dockerfile simpler and faster to build.
4
IntermediateOptimizing Dockerfile with Layer Caching
🤔Before reading on: do you think copying the whole project before building the app helps or hurts build speed? Commit to your answer.
Concept: Order Dockerfile instructions to maximize cache reuse and speed up rebuilds.
Docker caches layers to avoid repeating work. Copying only the JAR after building the app keeps layers stable. Avoid copying source code or running build commands inside the Dockerfile for faster rebuilds. Example: FROM openjdk:17-jdk-slim COPY target/app.jar /app/app.jar ENTRYPOINT ["java", "-jar", "/app/app.jar"]
Result
Subsequent builds are faster because unchanged layers are reused.
Knowing how Docker caches layers helps you write Dockerfiles that save time during development.
5
IntermediateUsing Multi-Stage Builds for Smaller Images
🤔Before reading on: do you think building the app inside the Dockerfile or outside leads to smaller final images? Commit to your answer.
Concept: Use multi-stage builds to separate building the app and packaging the runtime image.
Multi-stage builds let you use one stage to build the Spring Boot app with Maven or Gradle, then copy only the final JAR into a smaller runtime image. This keeps the final image small and clean. Example: FROM maven:3.8.6-openjdk-17 AS build COPY src /app/src COPY pom.xml /app RUN mvn -f /app/pom.xml clean package FROM openjdk:17-jdk-slim COPY --from=build /app/target/app.jar /app/app.jar ENTRYPOINT ["java", "-jar", "/app/app.jar"]
Result
Final image contains only the runtime and app JAR, reducing size and attack surface.
Multi-stage builds improve security and efficiency by excluding build tools from the final image.
6
AdvancedConfiguring Environment and Ports in Dockerfile
🤔Before reading on: do you think setting environment variables in Dockerfile or at runtime is better? Commit to your answer.
Concept: Learn how to expose ports and set environment variables for Spring Boot in Dockerfiles.
Use EXPOSE to document which port the app listens on (usually 8080). Use ENV to set default environment variables like 'SPRING_PROFILES_ACTIVE'. These can be overridden at runtime. Example: EXPOSE 8080 ENV SPRING_PROFILES_ACTIVE=prod
Result
The container clearly shows which ports it uses and has default configs that can be changed.
Setting environment variables in Dockerfile provides sensible defaults but keeps flexibility for different deployments.
7
ExpertAdvanced Image Size Reduction and Security
🤔Before reading on: do you think running the app as root inside the container is safe or risky? Commit to your answer.
Concept: Use minimal base images, non-root users, and layer squashing to optimize size and security.
Replace 'openjdk:17-jdk-slim' with 'eclipse-temurin:17-jre-alpine' or similar minimal images to reduce size. Add a non-root user and switch to it with USER instruction to improve security. Use Docker build options to squash layers and reduce image size. Example additions: RUN addgroup -S appgroup && adduser -S appuser -G appgroup USER appuser
Result
Smaller, more secure images that follow best practices for production.
Understanding security and size tradeoffs in Docker images is critical for production-grade Spring Boot deployments.
Under the Hood
When you run 'docker build', Docker reads the Dockerfile line by line. Each instruction creates a new image layer, which is a snapshot of the filesystem changes. Layers are cached and reused if unchanged. The base image provides the Java runtime environment. Copying the Spring Boot JAR adds the app code. ENTRYPOINT defines the command to start the app inside the container. When running the container, Docker creates a writable layer on top of these image layers and executes the ENTRYPOINT command.
Why designed this way?
Docker uses layered images to save space and speed up builds by reusing unchanged layers. This design allows developers to build images incrementally and share common base layers. Using base images with Java pre-installed avoids reinventing the wheel and ensures consistency. Multi-stage builds were introduced to separate build and runtime environments, reducing final image size and attack surface.
Docker Build Flow:

┌───────────────┐
│ Dockerfile    │
│ Instructions  │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Base Image    │
│ (Java Runtime)│
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Copy JAR File │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Set ENTRYPOINT│
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Docker Image  │
│ (Layers)     │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Docker Run    │
│ Container     │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does copying source code into the Docker image speed up rebuilds? Commit yes or no.
Common Belief:Copying the entire source code into the Docker image speeds up rebuilds and is best practice.
Tap to reveal reality
Reality:Copying source code causes Docker to rebuild layers every time code changes, slowing down builds. It's better to build the app outside and copy only the final JAR.
Why it matters:Ignoring this leads to slow development cycles and wasted resources during image builds.
Quick: Is running your Spring Boot app as root inside the container safe? Commit yes or no.
Common Belief:Running the app as root inside the container is fine because containers are isolated.
Tap to reveal reality
Reality:Running as root increases security risks if the container is compromised. Best practice is to run as a non-root user.
Why it matters:Not following this can lead to serious security vulnerabilities in production.
Quick: Does the EXPOSE instruction publish ports to the host automatically? Commit yes or no.
Common Belief:EXPOSE in Dockerfile automatically opens ports on the host machine.
Tap to reveal reality
Reality:EXPOSE only documents the port inside the container; you must explicitly publish ports when running the container.
Why it matters:Misunderstanding this causes confusion when the app is unreachable from outside the container.
Quick: Does multi-stage build always make the build process slower? Commit yes or no.
Common Belief:Multi-stage builds always slow down the build process because they add complexity.
Tap to reveal reality
Reality:Multi-stage builds can speed up builds by separating concerns and reducing final image size, improving deployment speed.
Why it matters:Avoiding multi-stage builds due to this misconception leads to bloated images and inefficient deployments.
Expert Zone
1
Using a minimal JRE base image instead of a full JDK reduces image size significantly without losing runtime functionality.
2
Layer ordering in Dockerfile affects caching; placing rarely changed instructions early maximizes cache hits.
3
Explicitly setting a non-root user inside the container prevents privilege escalation attacks in production.
When NOT to use
Avoid building the Spring Boot app inside the Dockerfile for large projects or CI pipelines; instead, build externally and use multi-stage builds. For very small or simple apps, a single-stage build might suffice. If you need extreme image size reduction, consider native image compilation with GraalVM instead of standard JAR packaging.
Production Patterns
In production, teams use multi-stage Dockerfiles with separate build and runtime stages, non-root users, environment variable configuration, and health checks. Images are scanned for vulnerabilities and pushed to private registries. Kubernetes deployments use these images with resource limits and readiness probes.
Connections
Continuous Integration/Continuous Deployment (CI/CD)
Dockerfiles for Spring Boot are often integrated into CI/CD pipelines to automate building and deploying container images.
Understanding Dockerfiles helps you automate app delivery, making deployments faster and more reliable.
Operating System Virtualization
Docker containers use OS-level virtualization to isolate apps, unlike full virtual machines.
Knowing how containers share the OS kernel explains why Docker images need only app and runtime, not a full OS.
Software Packaging and Distribution
Docker images are a modern form of software packaging that bundles code and environment together.
Recognizing Docker images as packages helps understand their role in consistent software delivery across environments.
Common Pitfalls
#1Copying source code instead of the built JAR into the Docker image.
Wrong approach:FROM openjdk:17-jdk-slim COPY src /app/src COPY pom.xml /app RUN mvn -f /app/pom.xml clean package ENTRYPOINT ["java", "-jar", "/app/target/app.jar"]
Correct approach:Build the JAR outside Docker, then: FROM openjdk:17-jdk-slim COPY target/app.jar /app/app.jar ENTRYPOINT ["java", "-jar", "/app/app.jar"]
Root cause:Misunderstanding that Docker should build the app instead of just packaging the final artifact.
#2Running the container as root user.
Wrong approach:FROM openjdk:17-jdk-slim COPY app.jar /app/app.jar ENTRYPOINT ["java", "-jar", "/app/app.jar"] # runs as root by default
Correct approach:FROM openjdk:17-jdk-slim RUN addgroup -S appgroup && adduser -S appuser -G appgroup COPY app.jar /app/app.jar USER appuser ENTRYPOINT ["java", "-jar", "/app/app.jar"]
Root cause:Ignoring container security best practices and default user context.
#3Assuming EXPOSE publishes ports to host automatically.
Wrong approach:FROM openjdk:17-jdk-slim COPY app.jar /app/app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "/app/app.jar"] # run with 'docker run image' only
Correct approach:docker run -p 8080:8080 image # explicitly publish ports at runtime
Root cause:Confusing Dockerfile documentation with runtime port mapping.
Key Takeaways
A Dockerfile is a step-by-step recipe that builds a container image bundling your Spring Boot app and Java runtime.
Using a base image with Java pre-installed simplifies Dockerfiles and ensures consistent runtime environments.
Multi-stage builds separate building and runtime, producing smaller and more secure images.
Proper layer ordering and caching in Dockerfiles speed up rebuilds and development cycles.
Running containers as non-root users and explicitly publishing ports are essential best practices for security and accessibility.