DEV Community

Cover image for Dockerizing a Java 26 Project with Docker Init
Mohammad-Ali A'RÂBI
Mohammad-Ali A'RÂBI

Posted on • Originally published at dockersecurity.io

Dockerizing a Java 26 Project with Docker Init

Docker Init was introduced in Docker Desktop 4.27, before LLMs became the default answer to everything. It's a "smart" interactive wizard that analyzes your project and generates:

  • A Dockerfile (multi-stage, production-ready)
  • A compose.yaml file
  • A .dockerignore file
  • A README.Docker.md with build and run instructions

What makes it valuable is that it's deterministic—not a probabilistic guess. It produces the same correct output every time, following Docker's own best practices.

Docker Commandos setting up the command center

Technical Requirements

  • Docker Desktop 4.27 or later

Create a New Project

I'm using a Spring Boot project. Because it's early Spring now and I haven't touched one in a while—so let's go.

Head to start.spring.io and create a project with:

  • Project: Maven
  • Language: Java
  • Spring Boot: 4.0.5 (or whatever the latest stable is)
  • Packaging: Jar
  • Java: 26

I used these coordinates, but pick your own:

  • Group: io.dockersecurity
  • Artifact: hello-wowlrd
  • Package Name: io.dockersecurity.hello-wowlrd

Download, unzip, and step into the directory:

cd hello-wowlrd
Enter fullscreen mode Exit fullscreen mode

Run Docker Init

As my British friend say, "It's Docker, innit?"

docker init
Enter fullscreen mode Exit fullscreen mode

The interactive wizard detects your Java project automatically. Accept "Java", confirm the source directory and Java version, and enter the port:

? What application platform does your project use? Java
? What's the relative directory (with a leading .) for your app? ./src
? What version of Java do you want to use? 26
? What port does your server listen on? 8080
Enter fullscreen mode Exit fullscreen mode

Docker Init generates four files. The one that matters most is the Dockerfile:

# syntax=docker/dockerfile:1

################################################################################
# Stage 1: resolve and download dependencies
FROM eclipse-temurin:26-jdk-jammy as deps

WORKDIR /build

COPY --chmod=0755 mvnw mvnw
COPY .mvn/ .mvn/

RUN --mount=type=bind,source=pom.xml,target=pom.xml \
    --mount=type=cache,target=/root/.m2 ./mvnw dependency:go-offline -DskipTests

################################################################################
# Stage 2: build the application
FROM deps as package

WORKDIR /build

COPY ./src src/
RUN --mount=type=bind,source=pom.xml,target=pom.xml \
    --mount=type=cache,target=/root/.m2 \
    ./mvnw package -DskipTests && \
    mv target/$(./mvnw help:evaluate -Dexpression=project.artifactId -q -DforceStdout)-$(./mvnw help:evaluate -Dexpression=project.version -q -DforceStdout).jar target/app.jar

################################################################################
# Stage 3: extract Spring Boot layers
FROM package as extract

WORKDIR /build

RUN java -Djarmode=layertools -jar target/app.jar extract --destination target/extracted

################################################################################
# Stage 4: minimal runtime image
FROM eclipse-temurin:26-jre-jammy AS final

ARG UID=10001
RUN adduser \
    --disabled-password \
    --gecos "" \
    --home "/nonexistent" \
    --shell "/sbin/nologin" \
    --no-create-home \
    --uid "${UID}" \
    appuser
USER appuser

COPY --from=extract build/target/extracted/dependencies/ ./
COPY --from=extract build/target/extracted/spring-boot-loader/ ./
COPY --from=extract build/target/extracted/snapshot-dependencies/ ./
COPY --from=extract build/target/extracted/application/ ./

EXPOSE 8080

ENTRYPOINT [ "java", "org.springframework.boot.loader.launch.JarLauncher" ]
Enter fullscreen mode Exit fullscreen mode

This is already a proper multi-stage build: separate stages for dependency resolution, compilation, layer extraction, and a minimal runtime image with a non-root user. Gord would approve.

A Note on Java 26 Base Images

The generated Dockerfile references eclipse-temurin:26-jdk-jammy and eclipse-temurin:26-jre-jammy. Since Java 26 was just released, these Eclipse Temurin images may not be fully available on Docker Hub yet.

Swap them out for SAP Machine images instead—SAP's free OpenJDK distribution ships Java 26 on Ubuntu 24.04 (Noble Numbat):

  • sapmachine:26-jdk-ubuntu-noble
  • sapmachine:26-jre-ubuntu-noble

Find them on Docker Hub: hub.docker.com/_/sapmachine. Just replace eclipse-temurin with sapmachine in both FROM lines.

Build and Run

docker compose up --build
Enter fullscreen mode Exit fullscreen mode

The generated compose.yaml is minimal:

services:
  server:
    build:
      context: .
    ports:
      - 8080:8080
Enter fullscreen mode Exit fullscreen mode

The application starts, and immediately stops with exit code 0. That's expected: there's no HTTP endpoint to keep it alive.

Add a Controller

Create src/main/java/io/dockersecurity/hellowowlrd/HelloController.java:

package io.dockersecurity.hellowowlrd;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/")
    public String hello() {
        return "Hello, Docker Security!";
    }
}
Enter fullscreen mode Exit fullscreen mode

Add the Spring Web dependency to pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Build and run again:

docker compose up --build
Enter fullscreen mode Exit fullscreen mode

Verify:

curl http://localhost:8080
# Hello, Docker Security!
Enter fullscreen mode Exit fullscreen mode

See It Live — Jfokus 2026

I presented Docker Init and Docker security at Jfokus in Stockholm in February 2026. If you want to see the commands in action rather than reading about them, the full talk is on YouTube:

More Links

Docker Init supports more than Java. If you want to try it with other languages, Docker's official guides are the place to start: docs.docker.com/guides.

I co-authored the C++ guide—Docker thanked me for it at the top of the page, which means I wrote those words and then thanked myself on their behalf. Worth a read:

Conclusion

Java 26 just shipped and Docker Init handles it cleanly out of the box—multi-stage build, layer extraction, non-root user, bind mounts for caching. You get a production-ready Dockerfile in under a minute. When Eclipse Temurin catches up, swap the base images back. Until then, SAP Machine has you covered.

Docker Init is Gord's move. The rest of the Commandos handle what comes after.


The Docker Commandos

Docker Init is assigned to Commando 1: Gord. In the Docker Commandos workshop, each Docker security feature is taught through a character on a mission to defend Asgard from CVE monsters. The ten commandos are:

  1. Gorddocker init: establish a secure base from day one ← you are here
  2. Rothütle — SBOM: inventory every dependency in your image
  3. Jack — Docker Scout: hunt CVEs across your supply chain
  4. The Valkyrie — SBOM Attestations: cryptographically sign your component inventory
  5. Artemisia — Docker Hardened Images: near-zero-CVE base images
  6. Mina — VEX Exemptions: mark false-positive CVEs as not exploitable
  7. RuinTan — VEX Attestations: attach signed exemptions to your image
  8. Captain Ahab — Docker Bake: codify your entire build pipeline in one file
  9. Evie — Cosign: sign images and attestations cryptographically
  10. Agent Null — Zero-Day Defense: harden against unknown, unpatched threats

The workshop has been delivered at WeAreDevelopers World Congress, Jfokus, and Rabobank. More at dockersecurity.io/commandos.

Top comments (0)