DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Keep Your Application Secrets Secret
  • Auto-Scaling a Spring Boot Native App With Nomad
  • Google Cloud Pub/Sub: Messaging With Spring Boot 2.5
  • Zero-Downtime Deployments for Java Apps on Kubernetes

Trending

  • Architecting Zero-Trust AI Agents: How to Handle Data Safely
  • Mocking Kafka for Local Spring Development
  • Rethinking Java CRUDs With Event Sourcing and CQRS Patterns
  • From APIs to Actions: Rethinking Back-End Design for Agents
  1. DZone
  2. Coding
  3. Java
  4. Guide to Creating and Containerizing Native Images

Guide to Creating and Containerizing Native Images

In this article, we will learn how to turn Java applications into native images and then containerize them for further deployment in the cloud.

By 
Dmitry Chuyko user avatar
Dmitry Chuyko
·
Apr. 18, 23 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
8.6K Views

Join the DZone community and get the full member experience.

Join For Free

Native Image technology is gaining traction among developers whose primary goal is to accelerate startup time of applications. In this article, we will learn how to turn Java applications into native images and then containerize them for further deployment in the cloud. We will use:

  • Spring Boot 3.0 with baked-in support for Native Image as the framework for our Java application;

  • Liberica Native Image Kit (NIK) as a native-image compiler;

  • Alpaquita Stream as a base image.

Building Native Images from Spring Boot Apps

Installing Liberica NIK

It would be best to utilize a powerful computer with several gigabytes of RAM to work with native images. Opt for a cloud service provided by Amazon or a workstation so as not to overload the laptop. We will be using Linux bash commands further on because bash is a perfect way of accessing the code remotely. macOS commands are similar. As for Windows, you can use any alternative, for instance, bash included in the Git package for Windows.

Download Liberica Native Image Kit for your system. Choose a Full version for our purposes.

Unpack tar.gz with:

tar -xzvf ./bellsoft-liberica.tar.gz

Now, put the compiler to $PATH with:

GRAALVM_HOME=/home/user/opt/bellsoft-liberica export PATH=$GRAALVM_HOME/bin:$PATH

Check that Liberica NIK is installed:

java -version openjdk version "17.0.5" 2022-10-18 LTS

OpenJDK Runtime Environment GraalVM 22.3.0 (build 17.0.5+8-LTS)

OpenJDK 64-Bit Server VM GraalVM 22.3.0 (build 17.0.5+8-LTS, mixed mode, sharing)


native-image --version

GraalVM 22.3.0 Java 17 CE (Java Version 17.0.5+8-LTS)

If you get the error "java: No such file or directory" on Linux, you installed the binary for Alpine Linux, not Linux. Check the binary carefully.

Creating a Spring Boot Project

The easiest way to create a new Spring Boot project is to generate one with Spring Initializr. Select Java 17, Maven, JAR, and Spring SNAPSHOT-version (3.0.5 at the time of writing this article), then fill in the fields for project metadata. We don’t need any dependencies.
Add the following code to you main class:
System.out.println("Hello from Native Image!");

Spring has a separate plugin for native compilation, which utilizes multiple context dependent parameters under the hood. Let’s add the required configuration to our pom.xml file: 

XML
 
<profiles>

    <profile>

        <id>native</id>

        <build>

            <plugins>

                <plugin>

                    <groupId>org.graalvm.buildtools</groupId>

                    <artifactId>native-maven-plugin</artifactId>

                    <executions>

                        <execution>

                            <id>build-native</id>

                            <goals>

                                <goal>compile-no-fork</goal>

                            </goals>

                            <phase>package</phase>

                        </execution>

                    </executions>

                </plugin>

            </plugins>

        </build>

    </profile>

</profiles>

Let’s build the project with the following command:

./mvnw clean package -Pnative

The resulting native image is in the target directory.

Write a Dockerfile

We need to write a Dockerfile to generate a Docker image container. Put the following file into the application folder:

Dockerfile
 
FROM bellsoft/alpaquita-linux-base:stream-musl

COPY target/native-image-demo .

CMD ["./native-image-demo"]

Where we:

  1. Create an image with Alpaquita Linux base image (the native image doesn’t need a JVM to execute);

  2. Copy the app into the new image;

  3. Run the program inside the container.

We can also skip the step with Liberica NIK installation and we build a native image straight in a container, which is useful when the development and deployment architectures are different. For that purpose, create another folder and put there your application and the following Dockerfile:

Dockerfile
 
FROM bellsoft/liberica-native-image-kit-container:jdk-17-nik-22.3-stream-musl as builder

WORKDIR /home/myapp

ADD native-image-demo /home/myapp/native-image-demo

RUN cd native-image-demo && ./mvnw clean package -Pnative

FROM bellsoft/alpaquita-linux-base:stream-musl

WORKDIR /home/myapp

COPY --from=builder /home/myapp/native-image-demo/target/native-image-demo .

CMD ["./native-image-demo"]

Where we:

  1. Specify the base image for Native Image generation;

  2. Point to the directory where the image will execute inside Docker;

  3. Copy the program to the directory;

  4. Build a native image;

  5. Create another image with Alpaquita Linux base image (the native image doesn’t need a JVM to execute);

  6. Specify the executable directory;

  7. Copy the app into the new image;

  8. Run the program inside the container. 

Build a Native Image Container

To generate a native image and containerize it, run:

docker build .

Note that if you use Apple M1, you may experience troubles with building a native image inside a container.

Check that the image was create with the following command:

Dockerfile
 
docker images

REPOSITORY   TAG       IMAGE ID       CREATED          SIZE

<none>       <none>    8ebc2a97ef8e   18 seconds ago   45.2MB

Tag the newly created image:

docker tag 8ebc2a97ef8e nik-example

Now you can run the image with:

docker run -it --rm 8ebc2a97ef8e

Hello from Native Image!

Conclusion

Native image containerization is as simple as creating Docker container images of standard Java apps. Much trickier is to migrate a Java application to Native Image.

We used a simple program that didn’t require any manual configuration. But dynamic Java features (Reflection, JNI, Serialization, etc.) are not supported by GraalVM, so you have to make the native-image tool aware of them.

Docker (software) Java (programming language) Spring Boot Cloud

Published at DZone with permission of Dmitry Chuyko. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Keep Your Application Secrets Secret
  • Auto-Scaling a Spring Boot Native App With Nomad
  • Google Cloud Pub/Sub: Messaging With Spring Boot 2.5
  • Zero-Downtime Deployments for Java Apps on Kubernetes

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook