Dockerizing a Java 24 Project with Docker Init
Hello Wowlrd!
I'm starting a new series called "Docker Hour", where I'll publish a new Docker-related article every week. But in the beginning, I'll publish a new article for two weeks, so 10 articles in total. I wanted to called the series "Docker Deca", but I'm just making up too many names.
Later, I'll give a talk at PlatformCon named:
Bake a Docker Cake
10 Docker Commands You Probably Didn't Know About
It's going to be about these 10 commands. So, let's init!
Docker Init
Docker Init was a new command introduced in Docker Desktop 4.27 (for comparison, currently, the latest version is 4.40). It's a "smart" command that helps you Dockerize your project. It does the following:
- Creates a Dockerfile
- Creates a
docker-compose.yml
file (well, they call itcompose.yaml
to be more of a cool guy) - Creates a
.dockerignore
file - Creates a README file with instructions on how to run the project
It's great stuff! Let's see it in action.
Technical Requirements
- Docker Desktop 4.27 or later
- Git is good to have, I guess
Create a New Project, or Rather Download One
I'm going to do it with a Spring Boot project. Because it's in early Spring now, and I haven't done a Spring Boot project in a while. So, let's do it!
Let's go to start.spring.io because Josh Long loves this site. And let's create a new project with the following settings:
- Project: Maven
- Language: Java
- Spring Boot: 3.4.4
- Packaging: Jar
- Java: 24
I also named added the following metadata, but you can choose your own:
- Group: com.dockerhour
- Artifact: docker-init
- Name: docker-init
- Description: Docker Init
- Package Name: com.dockerhour.dockerinit
Then, I downloaded the project and unzipped it. I also renamed the folder to docker-init
. Now, let's go to the folder:
cd docker-init
That was easy enough! Now, it's time!
Run Docker Init
Now, let's run the command:
docker init
The interactive wizard will detect that you have Java project. Press Enter to accept the "Java" option, accept the default for source directory and Java version, and enter the port manually:
? 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? 24
? What port does your server listen on? 8080
The following files are generated:
Dockerfile
: The Dockerfile to build the image.compose.yaml
: The Docker Compose file to run the image..dockerignore
: The.dockerignore
file to exclude files from the build context.README.Docker.md
: The README file with instructions on how to build and run the image.
Let's take a look into the Dockerfile
:
# syntax=docker/dockerfile:1
################################################################################
FROM eclipse-temurin:24-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
################################################################################
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
################################################################################
FROM package as extract
WORKDIR /build
RUN java -Djarmode=layertools -jar target/app.jar extract --destination target/extracted
################################################################################
FROM eclipse-temurin:24-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" ]
The following base images are used:
eclipse-temurin:24-jdk-jammy
: The Java Development Kit (JDK) image to compile the Java code, based on Ubuntu 22.04 (Jammy Jellyfish).eclipse-temurin:24-jre-jammy
: The Java Runtime Environment (JRE) image to run the compiled Java code, based on Ubuntu 22.04 (Jammy Jellyfish).
At the time of writing this article, Java 24 was recently released, so the Eclipse Temurin images are not available yet. To address that, we will use the following images instead:
sapmachine:24-jdk-ubuntu-noble
: The JDK image based on Ubuntu 24.04 (Noble Numbat).sapmachine:24-jre-ubuntu-noble
: The JRE image based on Ubuntu 24.04 (Noble Numbat).
These images are provided by SAP, the German vendor of ERP systems, who also provides a free and open-source distribution of the OpenJDK. You can find their Java images on Docker Hub: hub.docker.com/_/sapmachine.
After replacing the base images in the Dockerfile
, you can execute the following command to build and run the image:
docker compose up
This command will use the Docker Compose configuration that looks like this:
services:
server:
build:
context: .
ports:
- 8080:8080
The server
service will build the image using the Dockerfile
in the current directory and expose the port 8080 on the host machine.
The application starts successfully, but also directly stops with exit code 0. This means that the application is running, but there is no endpoint to access it.
Let's add a simple endpoint to the application.
Add a Controller
Let's add a simple controller to the application. Create a new file src/main/java/come/dockerhour/dockerinit/hello/HelloController.java
with the following content:
package com.dockerhour.dockerinit.hello;
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 Hour!";
}
}
Also, add the following block to your pom.xml
to include the Spring Web dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Now, let's build the project and run it again:
docker compose up --build
The application should start successfully and you can access it at localhost:8080. Let's check the endpoint:
curl http://localhost:8080
It should say "Hello, Docker Security!". Voilà!
More Links
If you want to test Docker Init with other languages, you can check the guides on Docker's website: docs.docker.com/guides. E.g. you can check the C++ guide, especially because I co-authored it:
The guide starts like this:
Docker would like to thank Pradumna Saraf and Mohammad-Ali A'râbi for their contribution to this guide.
So, I was the one writing these words, so I thanked myself on behalf of Docker. I hope you like it!
Conclusion
The new Java just came out, and Docker Init is a great tool to help you Dockerize your Java project. It creates a Dockerfile, a Docker Compose file, a .dockerignore
file, and a README file with instructions on how to run the project.
Docker Init for Java only works with Maven projects for now. But you can use the files as a starting point and adapt them to your project. This is what we did here, because the Eclipse Temurin images were not available yet.
I hope you liked the article! Please don't forget to like and subscribe to my channel.
If you want to learn about Docker Security basics, grab the first chapter of my book for free: Docker and Kubernetes Security. It's a great book, and I wrote it myself. So, you can trust me!