The Meeting of Kubernetes and Spring Boot 3.0 Native Image
Key point
Spring Boot 3.0 Native Image reduced Kubernetes pod readiness time from 50 seconds to 2 seconds.
Details
Crash Report from Netmarble's QA department is an internal system that collects and statisticizes crash data generated during game execution. The edge server cluster is based on Kubernetes (K8S), and HPA was configured to scale up pods and nodes based on CPU resource request rate.
The problem was that during traffic spikes, adding new pods took at least 1 minute. Since client connection wait time was around 10-20 seconds, data loss could occur while pods were becoming ready, and ultimately an environment that could scale up nodes and pods within 15 seconds became necessary.
As a solution, Spring Boot 3.0 and GraalVM Native Image were adopted. Spring Boot 3.0 raised the minimum supported version to Java 17 while officially supporting Native Image generation, absorbing the features of the existing Spring Native project.
Native images can run without a JVM, so initial startup is fast and memory usage is low. However, dynamic features need to be predefined, so along with AOT (Ahead Of Time) compilation, a hint file was needed, and spring-boot:process-aot was used to generate proxy-config.json, reflect-config.json, resource-config.json, and serialization-config.json. Dynamic elements not automatically captured were directly registered using RuntimeHintsRegistrar.
The build was done using native-maven-plugin and mvn -Pnative native:compile, and Docker was configured as a multi-stage build. Initially, the build combined GraalVM, musl, zlib, and UPX, and the runtime image was set to Alpine Linux.
The environment was continuously refined through deployments.
- 1st deployment: Since the build/runtime OS differed, CPU usage and OOM restarts were frequent, so CPU was adjusted from 800m to 1200m, and minimum pods from 15 to 20.
- 2nd deployment: When both build and runtime environments were aligned to Oracle Linux 9, OOM restarts were reduced to 2-3 times.
- 3rd deployment:
spring-boot:process-aotwas run again to reflect changed hint files, andtomcat-embed-programmaticwas applied. Due to Serial GC characteristics, more memory was allocated. - 4th deployment:
--libc:muslwas added to switch to Alpine Linux runtime, and CPU and memory settings were restored to JAR-era levels. - 5th deployment: UPX was applied to further reduce executable file size, and the final Docker image was reduced to 69.81MB. Additionally, readinessProbe and livenessProbe were utilized to receive traffic more quickly after readiness.
The difference was also clear in terms of performance. Execution readiness time was reduced from the existing 50 seconds to 2 seconds, and the Docker image size for new pods was reduced from around 300MB to around 70MB. In environments like Crash Report where initial response and pod scaling speed are critical, the effect of Native Image was very significant.
However, in long-term repeated testing, JAR-based services also stabilized in performance over time. Ultimately, the key is whether it's an environment where pod scaling is frequent, readiness time must be short, and initial response delay directly leads to data loss. Under such conditions, the combination of Kubernetes + Spring Boot 3.0 Native Image becomes a sufficiently powerful choice.
This summary was generated automatically by AI. Check the original for the author's claims and context. Copyright belongs to the original author.
Our guide explains how the AI works. Report summary errors, attribution issues, or removal requests via Contact.