Why does container size matter? For some developers, the question sounds similar to “Why don’t cows fly?” tempting to answer “just because” without reflecting much on why it is crucial. But many programmers, especially backenders, don’t even consider the issues hidden underneath heavyweight containers. Their logic: “It’s no concern of mine!”
This article will explain why reducing the container size will benefit all teams, even backenders.
Table of Contents
Why Spring makes Java code lighter
Soon after the Java programming language emerged, the developers understood it was a perfect platform for complex systems. Indeed, developing and maintaining a huge monolith in Java was much easier than in other languages. But monolithic applications have a substantial downside, i.e., prolonged startup. A simple application could start in one minute, a complex enterprise one in ten. A portal with portlets could even load in 40 minutes! In addition, Java development required special hardware, and it took ages to grasp complicated frameworks and their specific issues.
Then came the Spring framework, which is lightweight, fast, user-friendly, and based on tried-and-true programming patterns. The adoption of Spring across Java development coincided with the dawn of microservices, and slow, clumsy Java apps gradually became a thing of the past.
But there’s no time to bask in the Spring sun. We must continue improving the development techniques, or the nightmare of a 40-minute startup will return. Even now, the developer’s laptop has a hard time under the weight of dozens of deployed containers and microservices. We can alleviate its suffering by migrating to a lightweight Liberica Runtime Container of only 40.32 MB — the resulting Spring container can be 1.5 smaller than an Oracle-based one. But what benefits will it bring exactly?
Minimize the effort
The most significant advantage of any innovative solution is the seamless integration into the existing workflow and instant results. Switching to Liberica Runtime Container, in most cases, requires changing only one line FROM openjdk to FROM bellsoft/liberica-runtime-container in the Docker file, and the container size will be immediately cut several times.
Note that Liberica Runtime Container is based on Liberica Lite optimized for the cloud and Alpaquita Linux, which comes with two libc implementations: improved musl and glibc. So even if you use a musl-based distro, you can migrate to glibc-based Alpaquita and still save a significant amount of memory. So why not try it out?
Reduce the cloud cost
The cloud offers unique advantages such as easy scalability, universal data access, and big data management. But according to a study by Gartner, companies overspend up to 70% on cloud services. The expenses can sometimes inflate to such an extent that businesses start thinking about abandoning the cloud for good. Look at the article on Amazon’s failure with serverless by David Heinemeier Hansson, the creator of Ruby on Rails. The key takeaway is that bad code turns into inadequate infrastructure, which wreaks havoc in large-scale deployments.
But what if companies go back to earth? For developers, it will mean an immediate many-fold increase in work. Instead of ready-to-go cloud solutions (such as Spring Cloud AWS) they will have to create their own from scratch or even give up automatization.
We believe that there are better decisions than refusing cloud opportunities. Instead, enterprises should learn to manage the cloud resources and integrate cloud cost optimization strategy in the early stages of cloud migration. If you have already noticed the negative impact on your finances, decreasing the base container image will help you get back on track. After that, you can start optimizing your IT infrastructure — we prepared a white paper with steps on optimizing cloud costs, tested and proven to work. Download it now, and don’t let the cloud hang over your IT budget!
Accelerate docker pull
What is the difference between waiting for 140 or 600 MB to load? If you have a fast Internet connection, the difference is negligible. However, in the case of a slow or expensive connection, pulling a heavy image may take ages, and constant docker push/pull will become torture.
Decrease the cash size
How much cache on your computer is eaten by Docker? Run docker system df to find out. You will notice a RECLAIMABLE section, which shows the space taken by unused images. The docker system df -v will provide you with more detailed information. If you work with Docker but disregard clearing the disk, the results will shock you because you may have hundreds of gigabytes of trash on your machine.
On the one hand, you can run docker system prune and forget about the trash. On the other hand, it may contain images you will require later, so you will have to load them again. But, as we discussed earlier, lightweight containers load rapidly, so it is better to load necessary images from time to time rather than foster compulsive hoarding.
Facilitate the development process and stimulate experiments
Minor problems cloud the blue-sky thinking. Imagine you are struck with a grand idea. If you have to divert your attention to housekeeping activities, there’s a high chance you will get bogged down in routine and won’t be able to return to your idea.
The life of a developer can be filled with numerous chores. Apart from heavy, slowly loading containers, you may need to download several gigabytes of Maven packages, debug a couple of framework configurations, or deploy and test some incomprehensible Helm Charts.
In a perfect world, developers should
- Manage the number of utilized libraries,
- Apply straightforward configuration methods,
- Control the complexity of dependencies and resource capacity of the selected solution,
Or else the whole development process will quickly spin out of control. It is especially relevant in the Spring ecosystem, which includes 30+ projects and loads of related code on GitHub and Docker Hub.
But at the same time, dealing with these tasks means “death by a thousand cuts” — none of them is complicated on their own, but taken together, they may devour all of your or your team’s free time. For instance, you want to share an image with your colleagues without uploading it to Docker Hub but as a .tar.gz file. What if that file weighs about 1GB? Imagine the psychological state of the team that has to download and unpack it manually!
New extralight Spring containers
A simple application may be relatively small compared to the whole JDK, a container with libraries, or an operating system. Still, enterprise programs are usually complex and require multiple dependencies, significantly affecting the final image size.
Fortunately, Spring Boot 3 has baked-in support for GraalVM Native image. What does it mean for Java applications? GraalVM Native Image enables the Ahead-of-time (AOT) compilation, eliminating unused code and turning an app into a compact native executable file. As a result, there’s no need to pack the whole JDK into the image anymore, and provided that you have mastered the intricacies of using Native Image with Java, you will be able to optimize memory consumption and minimize startup time to 1/10 s.
If you would like to try out the Native Image technology, you need to install a GraalVM distribution. The Spring team recommends Liberica Native Image Kit (NIK), a free GraalVM CE-based native-image tool used by default with Cloud Native Buildpacks.
We also provide a ready-to-go container image with Alpaquita Linux and Liberica NIK. Alpaquita Linux has a base image size of only 3.32 MB (optimized musl) or 8.39 MB (glibc). Try calculating how much memory you can save if the base OS layer takes up less than 10 MB and your AOT-compiled app — about 50 MB!
In this article, we examined several benefits of small Spring container images. Of course, downsizing the container size is not a sole solution but a substantial part of an IT infrastructure management strategy, together with the right choice of libraries and other tools. But all in all, a lightweight container image, for example, Liberica Runtime Container, is guaranteed to facilitate, accelerate, and cheapen microservice development.