Full Stack • Java • System Design • Cloud • AI Engineering

Dockerfile for Spring Boot on OpenShift

Learn how to write production-ready Dockerfiles for Spring Boot applications running on OpenShift. Explore multi-stage builds, image optimization, security best practices, health checks, and enterprise deployment strategies.


Introduction

A Dockerfile defines how a container image is built. It contains a sequence of instructions that package your Spring Boot application along with the required runtime environment.

When deploying applications to OpenShift, a well-designed Dockerfile is critical because it affects:

  • Image size
  • Startup time
  • Security
  • Build speed
  • Deployment speed
  • Resource utilization

In this article, you'll learn how to create production-ready Dockerfiles optimized for OpenShift.


Learning Objectives

By the end of this article, you will understand:

  • What is a Dockerfile?
  • Docker build lifecycle
  • Spring Boot Dockerfile
  • Multi-stage builds
  • Layer caching
  • Image optimization
  • OpenShift security requirements
  • Best practices
  • Enterprise examples

What is a Dockerfile?

A Dockerfile is a text file containing instructions to build a container image.

The Docker Engine reads each instruction and creates image layers.

flowchart LR
    DEV["Developer"]
    DF["Dockerfile"]
    BUILD["Docker Build"]
    IMAGE["Container Image"]
    REG["Container Registry"]

    subgraph OCP["OpenShift Cluster"]
        DEPLOY["Deployment"]
        POD["Running Pod"]
    end

    DEV --> DF
    DF --> BUILD
    BUILD --> IMAGE
    IMAGE --> REG
    REG --> DEPLOY
    DEPLOY --> POD

Docker Build Lifecycle

flowchart LR
    DEV["Developer"]
    CODE["Source Code"]
    MAVEN["Maven Build"]
    JAR["Application JAR"]
    DOCKER["Docker Build"]
    IMAGE["Container Image"]
    QUAY["Quay / Image Registry"]

    subgraph OCP["OpenShift Cluster"]
        DEPLOY["Deployment"]
        POD["Spring Boot Pod"]
    end

    DEV --> CODE
    CODE --> MAVEN
    MAVEN --> JAR
    JAR --> DOCKER
    DOCKER --> IMAGE
    IMAGE --> QUAY
    QUAY --> DEPLOY
    DEPLOY --> POD

Sample Project Structure

springboot-demo/

├── src/
├── target/
│   └── app.jar
├── Dockerfile
├── pom.xml
└── deployment.yaml

Basic Dockerfile

FROM eclipse-temurin:21-jre

WORKDIR /app

COPY target/*.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java","-jar","app.jar"]

Dockerfile Explanation

FROM

FROM eclipse-temurin:21-jre

Defines the base image.

This image already contains:

  • Linux
  • Java Runtime
  • JVM

WORKDIR

WORKDIR /app

Sets the working directory inside the container.


COPY

COPY target/*.jar app.jar

Copies the Spring Boot JAR into the image.


EXPOSE

EXPOSE 8080

Documents the application's listening port.


ENTRYPOINT

ENTRYPOINT ["java","-jar","app.jar"]

Starts the Spring Boot application.


Docker Image Layers

Docker creates immutable layers.

flowchart TD
    BASE["Layer 1: Base OS Image"]
    RUNTIME["Layer 2: Java Runtime"]
    APP["Layer 3: Spring Boot JAR"]
    ENTRY["Layer 4: ENTRYPOINT / Startup"]

    BASE --> RUNTIME
    RUNTIME --> APP
    APP --> ENTRY

Only changed layers are rebuilt.


Build Docker Image

docker build -t springboot-demo:1.0 .

Verify:

docker images

Run Container

docker run -p 8080:8080 springboot-demo:1.0

Open:

http://localhost:8080/api/hello

Multi-Stage Build

Instead of packaging the JAR outside Docker, Docker can build everything.

FROM maven:3.9-eclipse-temurin-21 AS builder

WORKDIR /workspace

COPY . .

RUN mvn clean package -DskipTests

FROM eclipse-temurin:21-jre

WORKDIR /app

COPY --from=builder /workspace/target/*.jar app.jar

ENTRYPOINT ["java","-jar","app.jar"]

Multi-Stage Build Architecture

flowchart LR
    SRC["Source Code"]
    BUILDER["Builder Stage (Maven)"]
    ARTIFACT["Spring Boot JAR"]
    RUNTIME["Runtime Image (JRE Only)"]
    REGISTRY["Container Registry"]
    OCP["OpenShift"]

    SRC --> BUILDER
    BUILDER --> ARTIFACT
    ARTIFACT --> RUNTIME
    RUNTIME --> REGISTRY
    REGISTRY --> OCP

Advantages:

  • Smaller images
  • Cleaner runtime
  • Better security

Layer Caching

Docker caches image layers.

flowchart TD
    L1["Layer 1: FROM eclipse-temurin:21-jre"]
    L2["Layer 2: Install Dependencies"]
    L3["Layer 3: Copy Source Code"]
    L4["Layer 4: Maven Build"]
    L5["Layer 5: Final Image"]

    L1 --> L2
    L2 --> L3
    L3 --> L4
    L4 --> L5

Changing source code rebuilds only the affected layers.


Image Optimization

Large images slow deployments.

Instead of:

1.2 GB

Aim for:

250 MB

or smaller.


Use Minimal Base Images

Recommended:

  • eclipse-temurin
  • ubi9/openjdk
  • Red Hat UBI

Avoid unnecessary packages.


Environment Variables

ENV JAVA_OPTS="-Xms256m -Xmx512m"

Access inside Spring Boot:

server.port=8080

OpenShift Security

OpenShift runs containers as non-root.

Avoid:

USER root

Prefer:

USER 1001

or let OpenShift assign a random UID.


Readiness and Liveness

Enable Spring Boot Actuator.

management.endpoints.web.exposure.include=health

Deployment:

livenessProbe:
  httpGet:
    path: /actuator/health
    port: 8080

OpenShift Deployment Flow

flowchart LR
    DEV["Developer"]
    GIT["Git Repository"]
    BUILD["CI/CD Pipeline"]
    DF["Dockerfile"]
    IMG["Container Image"]
    REG["Image Registry"]

    subgraph OCP["OpenShift Cluster"]
        DEP["Deployment"]
        POD["Spring Boot Pod"]
        SVC["Service"]
        ROUTE["Route"]
    end

    USER["Browser"]

    DEV --> GIT
    GIT --> BUILD
    BUILD --> DF
    DF --> IMG
    IMG --> REG
    REG --> DEP
    DEP --> POD
    POD --> SVC
    SVC --> ROUTE
    ROUTE --> USER

Enterprise Banking Example

Payment Service deployment.

flowchart LR
    GIT["Git"]
    JENKINS["Jenkins"]
    BUILD["Docker Build"]
    QUAY["Quay Registry"]
    OCP["OpenShift"]
    POD["Payment Pod"]
    CUSTOMERS["Customers"]

    GIT --> JENKINS
    JENKINS --> BUILD
    BUILD --> QUAY
    QUAY --> OCP
    OCP --> POD
    POD --> CUSTOMERS

Benefits:

  • Fast deployments
  • Rolling updates
  • Easy rollback

Common Docker Commands

Build:

docker build -t app .

Run:

docker run -p 8080:8080 app

List images:

docker images

List containers:

docker ps

Remove image:

docker rmi app

Push Image

docker tag springboot-demo quay.io/demo/app:1.0

docker push quay.io/demo/app:1.0

Verify Image

docker inspect springboot-demo

Common Mistakes

❌ Using latest tag

FROM openjdk:latest

Prefer:

FROM eclipse-temurin:21-jre

❌ Running as root


❌ Large image sizes


❌ Installing unnecessary tools


❌ Hardcoding secrets

Never store:

  • Passwords
  • API Keys
  • Database URLs

Use OpenShift Secrets instead.


Best Practices

✅ Multi-stage builds

✅ Small base images

✅ Use non-root users

✅ Enable Actuator

✅ Health probes

✅ Pin image versions

✅ Keep Dockerfile simple

✅ Use .dockerignore

Example:

target/
.git
.idea
README.md

Production Dockerfile

FROM eclipse-temurin:21-jre

WORKDIR /opt/app

COPY target/*.jar app.jar

EXPOSE 8080

ENV JAVA_OPTS="-Xms256m -Xmx512m"

USER 1001

ENTRYPOINT ["sh","-c","java $JAVA_OPTS -jar app.jar"]

Real-World Deployment Workflow

sequenceDiagram
    participant Dev as Developer
    participant Git
    participant CI as Jenkins
    participant Docker
    participant Registry
    participant OCP as OpenShift
    participant Pod
    participant User as End User

    Dev->>Git: Commit & Push
    Git->>CI: Webhook Trigger
    CI->>Docker: Build Image
    Docker->>Registry: Push Image
    Registry->>OCP: Image Available
    OCP->>Pod: Deploy New Version
    Pod-->>User: HTTP Response

Summary

A Dockerfile is the foundation of every containerized Spring Boot application.

Key takeaways:

  • Dockerfiles package applications into portable images.
  • Multi-stage builds create smaller, cleaner images.
  • OpenShift requires secure, non-root containers.
  • Layer caching improves build performance.
  • Health probes and environment variables make applications production-ready.
  • Optimized Dockerfiles reduce deployment time and improve scalability.

Interview Questions

  1. What is a Dockerfile?
  2. What does the FROM instruction do?
  3. Why use multi-stage builds?
  4. What is layer caching?
  5. Why should containers avoid running as root?
  6. What is the purpose of ENTRYPOINT?
  7. How do you optimize Docker image size?
  8. Why use .dockerignore?
  9. How do OpenShift and Docker work together?
  10. What are Docker image layers?

Loading likes...

Comments

Share a question, correction, or practical insight about this article.

Loading approved comments...