DEV Community

Cover image for Multi-Architecture Spring OCI from anywhere with Paketo
DaShaun
DaShaun

Posted on • Originally published at dashaun.com

Multi-Architecture Spring OCI from anywhere with Paketo

Multi-Architecture Spring OCI from anywhere with Paketo

My favorite feature of Spring Boot 3.4.0 is the adoption of multi-architecture buildpacks.
This feature empowers you to construct native images and traditional JVM-based applications for both AMD64 and ARM64, from a unified build process.
The fact that OCI images will also be smaller because of the new default buildpack is a bonus.

Emotionally Invested

I've been building native images for ARM64 since 2021, because I'm a Raspberry Pi enthusiast and passionate about Spring Boot.
Since that time, I've created dozens of solutions, to put production-ready, enterprise-grade, Spring Boot on Raspberry Pi ARM64 devices with only 512MB of RAM.
I no longer have to support my own solution.

Getting Started

Prerequisites:

  • At least Java 17
  • Docker

Docker Desktop Configuration

Docker Desktop comes with built-in QEMU support for multi-architecture builds. However, if you need to install QEMU manually, you have two options:

Option 1: Using tonistiigi/binfmt

# Install QEMU support for all architectures docker run --privileged --rm tonistiigi/binfmt --install all 
Enter fullscreen mode Exit fullscreen mode

This command was found here: https://docs.docker.com/build/building/multi-platform/

Option 2: Using multiarch/qemu-user-static

# Install and configure QEMU docker run --privileged --rm multiarch/qemu-user-static --reset -p yes 
Enter fullscreen mode Exit fullscreen mode

More information can be found here: https://github.com/multiarch/qemu-user-static

Spring Boot 3.4.0 application

First, let's create a new Spring Boot application:

mkdir mydemo cd mydemo curl https://start.spring.io/starter.tgz -d dependencies=web,actuator -d type=maven-project | tar -xvzf - 
Enter fullscreen mode Exit fullscreen mode

You could also use https://start.spring.io

Create a multi-architecture OCI Image

Here's the step-by-step process to build and publish multi-architecture images:

# Build ARM64 image ./mvnw spring-boot:build-image -Dspring-boot.build-image.imagePlatform=linux/arm64 -Dspring-boot.build-image.imageName=dashaun/blog-3-4-0:arm64 docker push dashaun/blog-3-4-0:arm64 # Build AMD64 image ./mvnw spring-boot:build-image -Dspring-boot.build-image.imagePlatform=linux/amd64 -Dspring-boot.build-image.imageName=dashaun/blog-3-4-0:amd64 docker push dashaun/blog-3-4-0:amd64 # Create and push multi-architecture manifest docker manifest create dashaun/blog-3-4-0:multiarch --amend dashaun/blog-3-4-0:arm64 --amend dashaun/blog-3-4-0:amd64 docker manifest push dashaun/blog-3-4-0:multiarch 
Enter fullscreen mode Exit fullscreen mode

Inspect

Inspect the multi-architecture manifest:

docker manifest inspect dashaun/blog-3-4-0:multiarch 
Enter fullscreen mode Exit fullscreen mode

Inspect the manifest, results below.

{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", "manifests": [ { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 2407, "digest": "sha256:96d95eed9308f86a8055156913ed8710c25917bdf0389bd6d5cf2ab0a79c77fc", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 2406, "digest": "sha256:4c42eebe412f56a03d840d2660b9defde3820ce1c5e510ffba0067be0ae11c8e", "platform": { "architecture": "arm64", "os": "linux" } } ] } 
Enter fullscreen mode Exit fullscreen mode

The manifest shows both platforms linux/amd64 and linux\arm64

Looking at the Docker Hub tags Digest sections, notice that the sha values for the arm64 and amd64 tags match the multiarch tag's values.

The new default buildpack, builder-jammy-java-tiny also results in much smaller images. Both of the images we created here are under 275mb.
Switching to Spring Boot 3.3.6 and the previous default buildpack paketobuildpacks/builder-jammy-base results in a ~350mb image.

Building Native Images

The process for building native images is similar, with the addition of GraalVM support:

mkdir my-native-demo cd my-native-demo curl https://start.spring.io/starter.tgz -d dependencies=web,actuator,native -d type=maven-project | tar -xvzf - 
Enter fullscreen mode Exit fullscreen mode

You could also use https://start.spring.io

Building Multi-Architecture Native Images

When the buildpack see's the native-maven-plugin in the project, it creates native images with GraalVM. Our steps won't change, we will just use different tags.

# Build ARM64 native image ./mvnw spring-boot:build-image -Dspring-boot.build-image.imagePlatform=linux/arm64 -Dspring-boot.build-image.imageName=dashaun/blog-3-4-0:native-arm64 docker push dashaun/blog-3-4-0:native-arm64 #Build AMD64 native image ./mvnw spring-boot:build-image -Dspring-boot.build-image.imagePlatform=linux/amd64 -Dspring-boot.build-image.imageName=dashaun/blog-3-4-0:native-amd64 docker push dashaun/blog-3-4-0:native-amd64 # Create and push multi-architecture manifest docker manifest create dashaun/blog-3-4-0:native-multiarch --amend dashaun/blog-3-4-0:native-arm64 --amend dashaun/blog-3-4-0:native-amd64 docker manifest push dashaun/blog-3-4-0:native-multiarch 
Enter fullscreen mode Exit fullscreen mode

Inspect Native

docker manifest inspect dashaun/blog-3-4-0:native-multiarch 
Enter fullscreen mode Exit fullscreen mode

Inspect the manifest, results below.

{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", "manifests": [ { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 2407, "digest": "sha256:70311015a28ff9ebbaa0ef0552e91bd85d2220716b69a8444ecf18ae542fa3f1", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 2406, "digest": "sha256:4b9243d946a61f5fd8c9762f9e8a5ef107ba5a51a3679faa54b5a3cd96e4147c", "platform": { "architecture": "arm64", "os": "linux" } } ] } 
Enter fullscreen mode Exit fullscreen mode

The manifest shows both platforms linux/amd64 and linux/arm64

Take a look at these image sizes!

dashaun/blog-3-3-6 latest 0e61fed5cf4a 44 years ago 348MB dashaun/blog-3-4-0 amd64 6ce61c588eba 44 years ago 268MB dashaun/blog-3-4-0 native-amd64 9f63e381e26c 44 years ago 117MB dashaun/blog-3-4-0 native-arm64 7a9b08bf964a 44 years ago 111MB dashaun/blog-3-4-0 arm64 0d07d6f15c86 44 years ago 259MB 
Enter fullscreen mode Exit fullscreen mode

I did this experiment on MacOS with ARM64 (M3 chip), but these exact same steps can be used on either ARM64 or AMD64 machines.

Conclusion

Spring Boot 3.4.0's multi-architecture support with Paketo buildpacks revolutionizes how we build and deploy applications across different architectures. Whether you're targeting cloud platforms or edge devices like Raspberry Pi, you can now build and deploy with confidence.

The combination of:

  • Multi-architecture support
  • Smaller image sizes
  • Native image capabilities
  • Simplified build process

Makes Spring Boot 3.4.0 a compelling choice for modern cloud-native and edge-native applications.

Keep Learning

Top comments (0)