Maybe you missed this news !!!

  • Container size really matters and we should keep our image size small
  • Spring Native is a collaboration between Spring & GraalVM with an aim to compile Spring Java Applications to standalone executables called native image
  • The benefits are not only reducing half of the size but also about achieving nearly instant startup (<100ms), instant peak performance, lower memory consumption with suited microservice, functions, Kubernetes workloads.
  • Below example result: >50% saving of storage size and memory consumption, startup time reduced from 5 seconds to 90 milliseconds.

Spring Native Beta Launched on 2021 Mar 11 and available on start.spring.io, this article explores the benefit by investigating and comparing with the traditional way of serving Spring-based service in the container.

1. Why Size Matter?

When discussing about container, the portability and lightweight of container images are obviously the winner when compare with virtual machine images. This makes most of us easily forgot on optimizing the size of our containers.

In fact, with the booming adoption of cloud, storage is become cheaper and cheaper and it create the illusion of saving a few MBs is not important nor relevant. Not many of us to-day know about Copy-On-Write technique – the one killing feature that improves container startup time (incredibly fast) that tradeoff by required some extra disk usage for layers; thus, image authors are asked to avoid creating large images.

Let leave the storage size and its cost factor on one side, there are several advantages of smaller image size:

  • Security: Smaller containers means lesser number of libraries inside, lesser software vulnerabilities, this reduce the risk of surface attack and more transparent of what happening inside.
  • Performance Efficiency: Not only faster start up time, smaller containers are also improving the build and deployment process, making them moving much easier and faster among the cluster.
  • Maintainability: Smaller size turns into better managed and maintain since there are less dependencies and libraries which always required effort to keeping them up to date with patches.

2. Before Spring Native, let investigate Spring Boot App in Docker!

Let make a typical Spring Boot application that have a helloWorld API with JDK11 and containerize it with the alpine base image. (Feel free to you your favorite tool: Spring Boot CLI, Maven Archetype, start.spring.io, etc…)

Figure 1: A simple Spring Hello World with Docker.

Let examine what inside our image that cost us 167MB using the command docker history (Interesting readers can use param –no-trunc to see the full details)

Figure 2: Investigate what are inside our Spring Boot image.

While the jar file only takes up 17.1 MB, the base image is 5.58 MB, a lot of stuff like JRE and necessary libs take up 144.2 MB!!!

3. Let try Spring Native

To address above disadvantages, Spring team together with GraalVM develop an incubation project called Spring Native with main goal to compile Spring application using GraalVM multi-language runtime that not only reduce the size (only required bits from JDK, Spring) but also have other benefits such as: nearly instant start up (fewer than 100ms), instant peak performance, lower memory consumption with the cost of longer build times and fewer runtime optimizations than the traditional JVM.

Currently, there are two main ways to build a Spring Boot Native application:

  • Using Spring Boot Buildpacks support to generate a lightweight container containing a native executable.
  • Using the GraalVM native image Maven plugin support to generate a native executable.

In this article, I will use an easy way by using start.spring.io (don’t forget to also add Spring Native in dependencies) and build with Spring Boot Buildpacks using the command mvn spring-boot:build-image (Note: Only Spring Boot 2.4.3 is supported, so change the version if necessary)

The build-time is longer than normal especially on the first-time and the image is built locally with name: docker.io/library/[artifact]:[version]

Figure 3: A simple Spring Native Hello World with Docker.

Let investigating the newly created native image that only has 86MB in size, we see only the optimized layers that only contain what necessary libs and dependencies.

Figure 4: Investigate what are inside our Spring Native image.

Don’t worry if we used some technologies that created 41 years ago, in order to reuse the Buildpacks create layers with a fixed time stamp. Not only the benefit of image size, we see huge improvement of startup time: the app only takes 90ms (compared to Spring Boot with used to take 5 to 6 seconds). If we run docker stats we can see that the memory consumption is only 59 MB (compared to our previous Spring Boot version took 140 MB), this mean we can save a lot of resource for other workload, this make a huge different!

4. Conclusion

We will need to wait sometime for the project team to finish their works and make the RC release that supports your existing Spring application, almost unmodified on this new platform. Native images can enable cheaper and more sustainable hosting for many types of workload. These include microservices, function workloads, well suited to containers, and Kubernetes. We need to spend time exploring to understand the key differences between a regular JVM and this native image platform, the benefit, the trade-off, the limitation and how to applied it into our system.

Tran Nguyen Dang Khoa – Solution & Technology Department, FPT Software

Related posts: