Creating a Distroless Java 17 Container Image¶
About This Task¶
With an eLxr Server 12 development host, you can either obtain the source or create your own to build a distroless container image that runs a Java application as described in this procedure.
When planning your container image, certain frameworks such as Spring Boot, Quarkus, and Micronaut, prefer a build that produces a single runnable JAR, or an exploded application layout, over copying the artifact into the distroless image. This procedure provides such an example.
Tip
In your Java environment, consider setting JVM options for for memory limits, GC tuning, and so on, via ENTRYPOINT or an environment variable.
Before You Begin¶
You must have a development host with Docker installed.
You must have the Java 17 Java Development Kit (JDK) installed.
If you require a distroless container for more complex applications, you will need Apache Maven or Gradle to build the application prior to creating the container image.
Procedure¶
Create a directory for the container project and navigate to it.
$ mkdir -p my-distroless-app && cd my-distroless-app
Create a HelloServer.java file.
This is for example purposes. For your own container application, substitute this code with you own.
java import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpExchange; import java.io.OutputStream; import java.net.InetSocketAddress; public class HelloServer { public static void main(String[] args) throws Exception { int port = Integer.parseInt(System.getenv().getOrDefault("PORT", "8080")); HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); server.createContext("/", new HttpHandler() { @Override public void handle(HttpExchange exchange) { try { String resp = "Hello from Java 17 Distroless!"; exchange.sendResponseHeaders(200, resp.getBytes().length); try (OutputStream os = exchange.getResponseBody()) { os.write(resp.getBytes()); } } catch (Exception e) { e.printStackTrace(); } } }); server.start(); System.out.println("Server running on port " + port); } }
This example uses the lightweight bundled com.sun.net.httpserver.HttpServer available in the JDK, which keeps the application dependency-free.
Build the application locally or in a build stage.
Note
The following is for example only. Consult Java documentation concerning build requirements for a given application.
Option 1: Small application
For a small application, you can compile and package with using javac and jar. This requires a Main-Class manifest with cfe. For additional information, consult Java documentation.
$ javac -d out HelloServer.java $ jar cfe app.jar HelloServer -C out .
Option 2: Large applications
For larger, more complex applications that require an executable (also called a fat JAR), use Apache Maven or Gradle to produce it.
Create a multi-stage Dockerfile
This Dockerfile builds the application using a JDK image and then copies the resulting artifact into a distroless Java 17 runtime image. Copy the following contents in to a text editor and save the file as java17-distroless-example.Dockerfile.
Example 1: Application built with javac and jar
Dockerfile # Build stage FROM eclipse-temurin:17-jdk AS build WORKDIR /app COPY HelloServer.java ./ RUN javac -d out HelloServer.java && \ jar cfe app.jar HelloServer -C out . # Production stage (distroless Java 17) FROM elxrlinux/elxr:latest-distroless-java17 WORKDIR /app COPY --from=build /app/app.jar /app/app.jar ENTRYPOINT ["java","-jar","/app/app.jar"] # If your distroless base uses a different entrypoint pattern, use: # CMD ["-jar","/app/app.jar"] # and set ENTRYPOINT ["java"] as appropriate for that image.
Example 2: Application built with Maven
Dockerfile # Build stage FROM maven:3.8.8-eclipse-temurin-17 AS build WORKDIR /app COPY pom.xml ./ COPY src ./src RUN mvn -DskipTests package # Production stage (distroless Java 17) FROM elxrlinux/elxr:latest-distroless-java17 WORKDIR /app COPY --from=build /app/app.jar /app/app.jar ENTRYPOINT ["java","-jar","/app/app.jar"] # If your distroless base uses a different entrypoint pattern, use: # CMD ["-jar","/app/app.jar"] # and set ENTRYPOINT ["java"] as appropriate for that image.
- In both examples:
The Build stage uses either an official JDK image or the Maven environment to compile and package the application
The Production stage uses a distroless Java 17 image and copies only the jar file
Build the Docker image.
$ docker build -t java17-distroless-example .
Run the container.
$ docker run -p 8080:8080 java17-distroless-example
Visit http://localhost:8080 to see the application respond.
Hello from Java 17 Distroless!
Results¶
Now that you have completed the distroless Java container image, consider learning about creating distroless nodejs images. For details, see Creating a Distroless Node.js 18 Container Image.