<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: DaShaun</title>
    <description>The latest articles on DEV Community by DaShaun (@dashaun).</description>
    <link>https://dev.to/dashaun</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F51700%2F045fb338-fc52-4b39-8120-82993aa24647.jpg</url>
      <title>DEV Community: DaShaun</title>
      <link>https://dev.to/dashaun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dashaun"/>
    <language>en</language>
    <item>
      <title>Multi-Architecture Spring OCI from anywhere with Paketo</title>
      <dc:creator>DaShaun</dc:creator>
      <pubDate>Tue, 17 Dec 2024 17:33:00 +0000</pubDate>
      <link>https://dev.to/dashaun/multi-architecture-spring-oci-from-anywhere-with-paketo-1ic2</link>
      <guid>https://dev.to/dashaun/multi-architecture-spring-oci-from-anywhere-with-paketo-1ic2</guid>
      <description>&lt;h2&gt;
  
  
  Multi-Architecture Spring OCI from anywhere with Paketo
&lt;/h2&gt;

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

&lt;p&gt;I've been building native images for ARM64 since 2021, because I'm a Raspberry Pi enthusiast and passionate about Spring Boot.&lt;br&gt;
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.&lt;br&gt;
I no longer have to support my own solution.&lt;/p&gt;
&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;At least Java 17&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docker&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Docker Desktop Configuration
&lt;/h3&gt;

&lt;p&gt;Docker Desktop comes with built-in QEMU support for multi-architecture builds. However, if you need to install QEMU manually, you have two options:&lt;/p&gt;
&lt;h4&gt;
  
  
  Option 1: Using tonistiigi/binfmt
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install QEMU support for all architectures&lt;/span&gt;
docker run &lt;span class="nt"&gt;--privileged&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; tonistiigi/binfmt &lt;span class="nt"&gt;--install&lt;/span&gt; all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;This command was found here: &lt;a href="https://docs.docker.com/build/building/multi-platform/" rel="noopener noreferrer"&gt;https://docs.docker.com/build/building/multi-platform/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Option 2: Using multiarch/qemu-user-static
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install and configure QEMU&lt;/span&gt;
docker run &lt;span class="nt"&gt;--privileged&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; multiarch/qemu-user-static &lt;span class="nt"&gt;--reset&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nb"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;More information can be found here: &lt;a href="https://github.com/multiarch/qemu-user-static" rel="noopener noreferrer"&gt;https://github.com/multiarch/qemu-user-static&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Spring Boot 3.4.0 application
&lt;/h3&gt;

&lt;p&gt;First, let's create a new Spring Boot application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;mydemo
&lt;span class="nb"&gt;cd &lt;/span&gt;mydemo
curl https://start.spring.io/starter.tgz &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;web,actuator &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;maven-project | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xvzf&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;You could also use &lt;a href="https://start.spring.io/#!type=maven-project&amp;amp;language=java&amp;amp;platformVersion=3.4.0&amp;amp;packaging=jar&amp;amp;jvmVersion=23&amp;amp;groupId=com.example&amp;amp;artifactId=demo&amp;amp;name=demo&amp;amp;description=Demo%20project%20for%20Spring%20Boot&amp;amp;packageName=com.example.demo&amp;amp;dependencies=web,actuator" rel="noopener noreferrer"&gt;https://start.spring.io&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Create a multi-architecture OCI Image
&lt;/h3&gt;

&lt;p&gt;Here's the step-by-step process to build and publish multi-architecture images:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build ARM64 image&lt;/span&gt;
./mvnw spring-boot:build-image &lt;span class="nt"&gt;-Dspring-boot&lt;/span&gt;.build-image.imagePlatform&lt;span class="o"&gt;=&lt;/span&gt;linux/arm64 &lt;span class="nt"&gt;-Dspring-boot&lt;/span&gt;.build-image.imageName&lt;span class="o"&gt;=&lt;/span&gt;dashaun/blog-3-4-0:arm64
docker push dashaun/blog-3-4-0:arm64

&lt;span class="c"&gt;# Build AMD64 image&lt;/span&gt;
./mvnw spring-boot:build-image &lt;span class="nt"&gt;-Dspring-boot&lt;/span&gt;.build-image.imagePlatform&lt;span class="o"&gt;=&lt;/span&gt;linux/amd64 &lt;span class="nt"&gt;-Dspring-boot&lt;/span&gt;.build-image.imageName&lt;span class="o"&gt;=&lt;/span&gt;dashaun/blog-3-4-0:amd64
docker push dashaun/blog-3-4-0:amd64

&lt;span class="c"&gt;# Create and push multi-architecture manifest&lt;/span&gt;
docker manifest create dashaun/blog-3-4-0:multiarch &lt;span class="nt"&gt;--amend&lt;/span&gt; dashaun/blog-3-4-0:arm64 &lt;span class="nt"&gt;--amend&lt;/span&gt; dashaun/blog-3-4-0:amd64
docker manifest push dashaun/blog-3-4-0:multiarch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Inspect
&lt;/h3&gt;

&lt;p&gt;Inspect the multi-architecture manifest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker manifest inspect dashaun/blog-3-4-0:multiarch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Inspect the manifest, results below.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schemaVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mediaType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/vnd.docker.distribution.manifest.list.v2+json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"manifests"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mediaType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/vnd.docker.distribution.manifest.v2+json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2407&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"digest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha256:96d95eed9308f86a8055156913ed8710c25917bdf0389bd6d5cf2ab0a79c77fc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"platform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"architecture"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"amd64"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"linux"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mediaType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/vnd.docker.distribution.manifest.v2+json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2406&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"digest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha256:4c42eebe412f56a03d840d2660b9defde3820ce1c5e510ffba0067be0ae11c8e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"platform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"architecture"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arm64"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"linux"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The manifest shows both platforms &lt;code&gt;linux/amd64&lt;/code&gt; and &lt;code&gt;linux\arm64&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Looking at the &lt;a href="https://hub.docker.com/r/dashaun/blog-3-4-0/tags" rel="noopener noreferrer"&gt;Docker Hub tags&lt;/a&gt; &lt;code&gt;Digest&lt;/code&gt; sections, notice that the &lt;code&gt;sha&lt;/code&gt; values for the &lt;code&gt;arm64&lt;/code&gt; and &lt;code&gt;amd64&lt;/code&gt; tags match the &lt;code&gt;multiarch&lt;/code&gt; tag's values.&lt;/p&gt;

&lt;p&gt;The new default buildpack, &lt;a href="https://github.com/paketo-buildpacks/builder-jammy-java-tiny" rel="noopener noreferrer"&gt;builder-jammy-java-tiny&lt;/a&gt; also results in much smaller images.  Both of the images we created here are under 275mb.&lt;br&gt;
Switching to Spring Boot 3.3.6 and the previous default buildpack &lt;a href="https://github.com/paketo-buildpacks/builder-jammy-base" rel="noopener noreferrer"&gt;paketobuildpacks/builder-jammy-base&lt;/a&gt; results in a ~350mb image.&lt;/p&gt;
&lt;h3&gt;
  
  
  Building Native Images
&lt;/h3&gt;

&lt;p&gt;The process for building native images is similar, with the addition of GraalVM support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-native-demo
&lt;span class="nb"&gt;cd &lt;/span&gt;my-native-demo
curl https://start.spring.io/starter.tgz &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;web,actuator,native &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;maven-project | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xvzf&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;You could also use &lt;a href="https://start.spring.io/#!type=maven-project&amp;amp;language=java&amp;amp;platformVersion=3.4.0&amp;amp;packaging=jar&amp;amp;jvmVersion=23&amp;amp;groupId=com.example&amp;amp;artifactId=demo&amp;amp;name=demo&amp;amp;description=Demo%20project%20for%20Spring%20Boot&amp;amp;packageName=com.example.demo&amp;amp;dependencies=web,actuator,native" rel="noopener noreferrer"&gt;https://start.spring.io&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Building Multi-Architecture Native Images
&lt;/h3&gt;

&lt;p&gt;When the buildpack see's the &lt;code&gt;native-maven-plugin&lt;/code&gt; in the project, it creates native images with GraalVM. Our steps won't change, we will just use different tags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build ARM64 native image&lt;/span&gt;
./mvnw spring-boot:build-image &lt;span class="nt"&gt;-Dspring-boot&lt;/span&gt;.build-image.imagePlatform&lt;span class="o"&gt;=&lt;/span&gt;linux/arm64 &lt;span class="nt"&gt;-Dspring-boot&lt;/span&gt;.build-image.imageName&lt;span class="o"&gt;=&lt;/span&gt;dashaun/blog-3-4-0:native-arm64
docker push dashaun/blog-3-4-0:native-arm64

&lt;span class="c"&gt;#Build AMD64 native image&lt;/span&gt;
./mvnw spring-boot:build-image &lt;span class="nt"&gt;-Dspring-boot&lt;/span&gt;.build-image.imagePlatform&lt;span class="o"&gt;=&lt;/span&gt;linux/amd64 &lt;span class="nt"&gt;-Dspring-boot&lt;/span&gt;.build-image.imageName&lt;span class="o"&gt;=&lt;/span&gt;dashaun/blog-3-4-0:native-amd64
docker push dashaun/blog-3-4-0:native-amd64

&lt;span class="c"&gt;# Create and push multi-architecture manifest&lt;/span&gt;
docker manifest create dashaun/blog-3-4-0:native-multiarch &lt;span class="nt"&gt;--amend&lt;/span&gt; dashaun/blog-3-4-0:native-arm64 &lt;span class="nt"&gt;--amend&lt;/span&gt; dashaun/blog-3-4-0:native-amd64
docker manifest push dashaun/blog-3-4-0:native-multiarch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Inspect Native
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker manifest inspect dashaun/blog-3-4-0:native-multiarch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Inspect the manifest, results below.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"schemaVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"mediaType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/vnd.docker.distribution.manifest.list.v2+json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"manifests"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"mediaType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/vnd.docker.distribution.manifest.v2+json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2407&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"digest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha256:70311015a28ff9ebbaa0ef0552e91bd85d2220716b69a8444ecf18ae542fa3f1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"platform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"architecture"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"amd64"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"linux"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"mediaType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/vnd.docker.distribution.manifest.v2+json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2406&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"digest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha256:4b9243d946a61f5fd8c9762f9e8a5ef107ba5a51a3679faa54b5a3cd96e4147c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"platform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"architecture"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arm64"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"linux"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The manifest shows both platforms &lt;code&gt;linux/amd64&lt;/code&gt; and &lt;code&gt;linux/arm64&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Take a look at these image sizes!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The combination of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-architecture support&lt;/li&gt;
&lt;li&gt;Smaller image sizes&lt;/li&gt;
&lt;li&gt;Native image capabilities&lt;/li&gt;
&lt;li&gt;Simplified build process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Makes Spring Boot 3.4.0 a compelling choice for modern cloud-native and edge-native applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep Learning
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.4-Release-Notes" rel="noopener noreferrer"&gt;Spring Boot 3.4 Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/live/fdyj_b-Mj4c?si=MA9azUhPg1tw09Kv" rel="noopener noreferrer"&gt;YouTube with Karanbir Singh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://neuw.medium.com/multi-architecture-oci-images-spring-boot-3-4-x-d8f2a0f7d6e6" rel="noopener noreferrer"&gt;Karanbir Singh's Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/paketo-buildpacks/builder-jammy-java-tiny" rel="noopener noreferrer"&gt;paketobuildpacks/builder-jammy-java-tiny&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>springboot</category>
      <category>paketo</category>
      <category>buildpacks</category>
      <category>multiarch</category>
    </item>
    <item>
      <title>Spring Health Assessment Report</title>
      <dc:creator>DaShaun</dc:creator>
      <pubDate>Sat, 17 Feb 2024 03:11:50 +0000</pubDate>
      <link>https://dev.to/dashaun/spring-health-assessment-report-14oj</link>
      <guid>https://dev.to/dashaun/spring-health-assessment-report-14oj</guid>
      <description>&lt;p&gt;Spring Boot 3.0.0 was released 450 days ago. Helping people upgrade, and enjoy all the amazing benefits, has been one of my passions for about 450 days.  I'm a Spring Developer Advocate and I love my job.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/tschuehly/status/1723106405756846117" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdashaun.com%2Fposts%2Fspring-health-assessment-report%2Fimages%2Fnormalconversation.png" alt="Thomas Schuehly has thoughts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's a passion really. Thomas Schuehly gets it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At SpringOne 2023 in Las Vegas, my friend, Joachim Pasquali, over at Fiserv, shared a story that I'll not soon forget.  The process of upgrading and patching, doesn't have to be a painful process.  On that day, his flagship product, was on the latest and greatest version of Spring Boot.  &lt;a href="https://youtube.com/clip/UgkxKNJxAWtsIWDzsFJM8tDB8VvG1E66EMVk?si=0e7-mUIHfjIHl9Qp" rel="noopener noreferrer"&gt;Watch the clip that gave me all the feels here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I want you to know about some tools and techniques that can help you upgrade your Spring Boot projects with more joy, frequently, and safely.&lt;/p&gt;

&lt;p&gt;First things first, let's talk about the challenges. Outdated Spring Boot versions can expose your projects to security risks, leave you without access to the latest features and performance improvements, and can be costing you more money. Have you ever been working, on an outdated JVM perhaps, or an older Spring Boot version, and secretly wished you were using the latest release? I get it, I've been there too, and I'm here to help.&lt;/p&gt;

&lt;p&gt;I want you to check out the &lt;a href="https://tanzu.vmware.com/spring-health-assessment" rel="noopener noreferrer"&gt;Spring Health Assessment Report&lt;/a&gt;.  This tool is very similar to something you probably have running already, it tells you about known vulnerabilities. However, this tool is also unique in a few very special ways.  First of all, it's free for you to use.  It also has the support timeline information built in. It provides a measure of how hard it will be to upgrade. Finally, it only reports on the Spring and Micrometer dependencies that you are using. It's very focused and actionable.&lt;/p&gt;

&lt;p&gt;I like to call &lt;a href="https://docs.openrewrite.org" rel="noopener noreferrer"&gt;OpenRewrite&lt;/a&gt; my favorite &lt;code&gt;cheat code&lt;/code&gt;. When I say that I demonstrate &lt;code&gt;OpenRewrite&lt;/code&gt; twenty times per week, I'm not exaggerating.  It's a powerful tool, and I'm still surprised by how many developers still don't know about it.  &lt;a href="https://github.com/dashaun/openrewrite-spring-boot-upgrade-example" rel="noopener noreferrer"&gt;This repository includes one of those demos, that I deliver multiple times every week&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Software is soft for a reason.  It's meant to be changed.  It's meant to be upgraded.  It's meant to be improved.  Java comes out with a new JVM, every 6-months.  The Spring team releases a new Spring Boot version every 6-months.  It's time to start upgrading more frequently.  In 2023, there were only 4-weeks, of the entire year, that the Spring team didn't release something new.  You can see for yourself over at &lt;a href="https://calendar.spring.io" rel="noopener noreferrer"&gt;calendar-dot-spring-dot-io&lt;/a&gt;.  It's time to start upgrading more frequently.&lt;/p&gt;

&lt;p&gt;I believe that the way software is going to be measured, going forward, is by how easy it is to maintain. I'm convinced that continuous upgrading, and continuous patching, is going to be a key differentiator for software projects.  I want you to get started, today.&lt;/p&gt;

&lt;p&gt;By upgrading your Spring Boot projects, you can benefit from improved security, performance, and access to the latest features. You'll also be able to take advantage of the ongoing support and updates provided by the Spring team and the Java team!&lt;/p&gt;

&lt;p&gt;So why wait? &lt;a href="https://youtu.be/XI_7mpEiPjI" rel="noopener noreferrer"&gt;Watch this video I made last week&lt;/a&gt;. Check out the Spring Health Assessment Report. You will see a few reasons why you should upgrade.  You will also see how easy it can be. Spring Boot 3.2.3 comes out next Thursday, how long will it take you to upgrade?&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/XI_7mpEiPjI" rel="noopener noreferrer"&gt;Spring into Action: Boost Your Java Projects with Essential Upgrade Tools!&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://tanzu.vmware.com/spring-health-assessment" rel="noopener noreferrer"&gt;Spring Health Assessment Report&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/tschuehly/status/1723106405756846117" rel="noopener noreferrer"&gt;Thomas Schuehly gets it&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dashaun/openrewrite-spring-boot-upgrade-example" rel="noopener noreferrer"&gt;OpenRewrite Spring Boot Upgrade Example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/clip/UgkxKNJxAWtsIWDzsFJM8tDB8VvG1E66EMVk?si=bF6GiJRZgWbH78JX" rel="noopener noreferrer"&gt;Joachim Pasquali at SpringOne 2023&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>springboot</category>
    </item>
    <item>
      <title>Five Months in the making, multi-architecture builder</title>
      <dc:creator>DaShaun</dc:creator>
      <pubDate>Mon, 18 Sep 2023 00:09:00 +0000</pubDate>
      <link>https://dev.to/dashaun/five-months-in-the-making-multi-architecture-builder-27oi</link>
      <guid>https://dev.to/dashaun/five-months-in-the-making-multi-architecture-builder-27oi</guid>
      <description>&lt;h2&gt;
  
  
  Long-overdue version of multi-architecture buildpack with Spring Boot 3 AOT processing support for M1, Raspberry Pi, ARM64
&lt;/h2&gt;

&lt;p&gt;If you have been following along, you are probably asking "What took so long?" and I totally understand.&lt;br&gt;
I had no idea what was wrong before today.&lt;br&gt;
My scripts had been working for over a year, then just stopped.&lt;br&gt;
I had removed a bunch of the debug info from the logs, which didn't help the situation at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upstream progress
&lt;/h2&gt;

&lt;p&gt;The Paketo team continues to put a high priority on ARM64 and multi-architecture tools/buildpacks.&lt;br&gt;
I had created several ARM64 workarounds over the years.&lt;br&gt;
The Paketo team continued improving their tools to support ARM64 as well.&lt;br&gt;
I was not doing a good job of pulling the tooling changes from upstream.&lt;br&gt;
So my workarounds were breaking the build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Several failed attempts
&lt;/h2&gt;

&lt;p&gt;I had made several solid attempts at resolving the issues.&lt;br&gt;
I just kept getting distracted with other priorities.&lt;br&gt;
I have had this process working on multiple environments.&lt;br&gt;
Every version of my pipeline seemed to be broken in a slightly different way.&lt;br&gt;
They were, because of my workarounds.&lt;br&gt;
I had different workarounds for different environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;This year, I've been traveling more than ever.&lt;br&gt;
In fact, I'm on my way to Oracle Cloud World 2023, right now.&lt;br&gt;
The laptop that I was using for work, wasn't keeping up with what I was needing to deliver, to the community.&lt;br&gt;
My conference sessions were having issues, my customer sessions were also having issues.&lt;br&gt;
Watching for over 4-minutes, for a native compile, isn't great for anyone.&lt;br&gt;
So I requested a new M1 laptop.&lt;br&gt;
When I got home on Friday, my new laptop had arrived.&lt;br&gt;
Since I'm going to be working on an M1 from now on, I needed to have all the fast builds.&lt;br&gt;
I needed to make sure all of my demos work on the new hardware.&lt;br&gt;
I also needed to be ready to use Java 21 when it comes out in 2 days.&lt;br&gt;
In addition to my new laptop from work, my Ampere Dev Kit server also arrived.&lt;br&gt;
The server had been stuck in US Customs for a couple of months, after arriving from China.&lt;br&gt;
It was my first time working with US Customs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;M1&lt;/li&gt;
&lt;li&gt;Ampere Dev Kit&lt;/li&gt;
&lt;li&gt;Java 21&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The work
&lt;/h2&gt;

&lt;p&gt;On my new M1, I simply started adding in debug info to the scripts.&lt;br&gt;
It felt good to get back into the process and remind myself how it all worked.&lt;br&gt;
When things work, you don't need to keep the details in your mental cache.&lt;br&gt;
The upstream builder added a few buildpacks.&lt;br&gt;
Packaging the newer buildpacks is where the problems were.&lt;br&gt;
Moments ago, I was getting ready to board when my tests passed.&lt;br&gt;
The KC Chiefs were playing Jacksonville at the same time.&lt;br&gt;
When I shouted with excitement, the people around me assumed that I was watching the game.&lt;br&gt;
I love my job.&lt;br&gt;
I love what I do.&lt;br&gt;
I could hear the Chiefs game, but getting this build to work was even more exciting that watching the Chiefs win the Super Bowl, twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  A huge surprise
&lt;/h2&gt;

&lt;p&gt;I don't remember what the number was, from the last time I looked at the stats on Docker Hub.&lt;br&gt;
When I went to look today, I was hoping for it to be over 2000.&lt;br&gt;
Maybe 3000?  Is 5000 possible?&lt;br&gt;
My goosebumps hit when I saw that it was over 8500!&lt;br&gt;
I am so excited that people are using it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;I am going to try to move away from my scripts, towards what the Paketo team is doing.&lt;br&gt;
I want to get my version moved over to the &lt;a href="https://github.com/paketo-community"&gt;paketo-community&lt;/a&gt; repository.&lt;br&gt;
Hopefully, from there, it will be even closer to being merged upstream.&lt;/p&gt;

&lt;p&gt;Stay tuned!&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback welcome
&lt;/h2&gt;

&lt;p&gt;Please let me know how it is working for you, all of &lt;a href="https://dashaun.com"&gt;my socials/contact info can be found here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>arm64</category>
      <category>multiarch</category>
      <category>buildpacks</category>
      <category>spring</category>
    </item>
    <item>
      <title>Teamwork makes the dream work for this multi-architecture builder.</title>
      <dc:creator>DaShaun</dc:creator>
      <pubDate>Tue, 13 Dec 2022 04:28:48 +0000</pubDate>
      <link>https://dev.to/dashaun/teamwork-makes-the-dream-work-for-this-multi-architecture-builder-1co8</link>
      <guid>https://dev.to/dashaun/teamwork-makes-the-dream-work-for-this-multi-architecture-builder-1co8</guid>
      <description>&lt;h1&gt;
  
  
  Teamwork makes the dream work for this multi-architecture builder
&lt;/h1&gt;

&lt;p&gt;There has never been a better time to start delivering Spring Boot applications to ARM64 architectures. I've been working on ARM64 buildpacks for over a year now and I want you to see how far things have come.  These last few days have been leveled-up with help from Daniel Mikusa and Salman Malik, and the results are amazing.&lt;/p&gt;

&lt;h2&gt;
  
  
  So close
&lt;/h2&gt;

&lt;p&gt;I'm excited because the builder for ARM64 is so close to the AMD64 builder supported by Paketo.  To see just how close things are, we can do a simple &lt;code&gt;diff&lt;/code&gt; of the builders, from different architectures.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Optionally, clear cached images first&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;docker system prune &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;--volumes&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Inspect with ARM64
&lt;/h2&gt;

&lt;p&gt;On an ARM64 device:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pack builder inspect dashaun/builder:tiny &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/dashaun.builder.tiny.arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inspecting builder: dashaun/builder:tiny

REMOTE:

Description: Tiny base image (bionic build image, distroless-like run image) with buildpacks for Java, Java Native Image and Go

Created By:
Name: Pack CLI
Version: 0.28.0+git-b10e41f.build-3729

Trusted: No

Stack:
ID: io.paketo.stacks.tiny

Lifecycle:
Version: 0.15.2
Buildpack APIs:
Deprecated: (none)
Supported: 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9
Platform APIs:
Deprecated: (none)
Supported: 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.10

Run Images:
index.docker.io/paketobuildpacks/run:tiny-cnb
gcr.io/paketo-buildpacks/run:tiny-cnb

Buildpacks:
ID                                                  NAME                                                   VERSION        HOMEPAGE
paketo-buildpacks/apache-tomcat                     Paketo Buildpack for Apache Tomcat                     7.9.1          https://github.com/paketo-buildpacks/apache-tomcat
paketo-buildpacks/apache-tomee                      Paketo Buildpack for Apache Tomee                      1.4.0          https://github.com/paketo-buildpacks/apache-tomee
paketo-buildpacks/azure-application-insights        Paketo Buildpack for Azure Application Insights        5.9.3          https://github.com/paketo-buildpacks/azure-application-insights
paketo-buildpacks/bellsoft-liberica                 Paketo Buildpack for BellSoft Liberica                 9.10.1         https://github.com/paketo-buildpacks/bellsoft-liberica
paketo-buildpacks/ca-certificates                   Paketo Buildpack for CA Certificates                   3.5.1          https://github.com/paketo-buildpacks/ca-certificates
paketo-buildpacks/clojure-tools                     Paketo Buildpack for Clojure Tools                     2.6.1          https://github.com/paketo-buildpacks/clojure-tools
paketo-buildpacks/datadog                           Paketo Buildpack for Datadog                           3.1.0          https://github.com/paketo-buildpacks/datadog
paketo-buildpacks/dist-zip                          Paketo Buildpack for DistZip                           5.4.0          https://github.com/paketo-buildpacks/dist-zip
paketo-buildpacks/encrypt-at-rest                   Paketo Buildpack for Encrypt-at-Rest                   4.3.2          https://github.com/paketo-buildpacks/encrypt-at-rest
paketo-buildpacks/environment-variables             Paketo Buildpack for Environment Variables             4.4.0          https://github.com/paketo-buildpacks/environment-variables
paketo-buildpacks/executable-jar                    Paketo Buildpack for Executable JAR                    6.5.0          https://github.com/paketo-buildpacks/executable-jar
paketo-buildpacks/git                               Paketo Buildpack for Git                               1.0.0          https://github.com/paketo-buildpacks/git
paketo-buildpacks/go                                Paketo Buildpack for Go                                4.0.0          https://github.com/paketo-buildpacks/go
paketo-buildpacks/go-build                          Paketo Buildpack for Go Build                          2.0.7          https://github.com/paketo-buildpacks/go-build
paketo-buildpacks/go-dist                           Paketo Buildpack for Go Distribution                   2.2.2          https://github.com/paketo-buildpacks/go-dist
paketo-buildpacks/go-mod-vendor                     Paketo Buildpack for Go Mod Vendor                     1.0.6          https://github.com/paketo-buildpacks/go-mod-vendor
paketo-buildpacks/google-stackdriver                Paketo Buildpack for Google Stackdriver                7.0.0          https://github.com/paketo-buildpacks/google-stackdriver
paketo-buildpacks/gradle                            Paketo Buildpack for Gradle                            6.10.0         https://github.com/paketo-buildpacks/gradle
paketo-buildpacks/image-labels                      Paketo Buildpack for Image Labels                      4.3.0          https://github.com/paketo-buildpacks/image-labels
paketo-buildpacks/jattach                           Paketo Buildpack for JAttach                           1.2.0          https://github.com/paketo-buildpacks/jattach
paketo-buildpacks/java                              Paketo Buildpack for Java                              8.1.0          https://paketo.io/docs/howto/java
paketo-buildpacks/java-memory-assistant             Paketo Buildpack for Java Memory Assistant             1.2.0          https://github.com/paketo-buildpacks/java-memory-assistant
paketo-buildpacks/java-native-image                 Paketo Buildpack for Java Native Image                 7.42.0         https://paketo.io/docs/howto/java/#build-an-app-as-a-graalvm-native-image-application
paketo-buildpacks/leiningen                         Paketo Buildpack for Leiningen                         4.4.0          https://github.com/paketo-buildpacks/leiningen
paketo-buildpacks/liberty                           Paketo Buildpack for Liberty                           3.1.0          https://github.com/paketo-buildpacks/liberty
paketo-buildpacks/maven                             Paketo Buildpack for Maven                             6.11.0         https://github.com/paketo-buildpacks/maven
paketo-buildpacks/native-image                      Paketo Buildpack for Native Image                      5.6.0          https://github.com/paketo-buildpacks/native-image
paketo-buildpacks/procfile                          Paketo Buildpack for Procfile                          5.5.0          https://github.com/paketo-buildpacks/procfile
paketo-buildpacks/sbt                               Paketo Buildpack for SBT                               6.9.0          https://github.com/paketo-buildpacks/sbt
paketo-buildpacks/spring-boot                       Paketo Buildpack for Spring Boot                       5.20.0         https://github.com/paketo-buildpacks/spring-boot
paketo-buildpacks/syft                              Paketo Buildpack for Syft                              1.23.0         https://github.com/paketo-buildpacks/syft
paketo-buildpacks/upx                               Paketo Buildpack for UPX                               3.3.0          https://github.com/paketo-buildpacks/upx
paketo-buildpacks/watchexec                         Paketo Buildpack for Watchexec                         2.7.0          https://github.com/paketo-buildpacks/watchexec

Detection Order:
├ Group #1:
│  └ paketo-buildpacks/java-native-image@7.42.0
│     └ Group #1:
│        ├ paketo-buildpacks/ca-certificates@3.5.1          (optional)
│        ├ paketo-buildpacks/upx@3.3.0                      (optional)
│        ├ paketo-buildpacks/bellsoft-liberica@9.10.1
│        ├ paketo-buildpacks/syft@1.23.0                    (optional)
│        ├ paketo-buildpacks/leiningen@4.4.0                (optional)
│        ├ paketo-buildpacks/gradle@6.10.0                  (optional)
│        ├ paketo-buildpacks/maven@6.11.0                   (optional)
│        ├ paketo-buildpacks/sbt@6.9.0                      (optional)
│        ├ paketo-buildpacks/executable-jar@6.5.0           (optional)
│        ├ paketo-buildpacks/spring-boot@5.20.0             (optional)
│        ├ paketo-buildpacks/native-image@5.6.0
│        ├ paketo-buildpacks/procfile@5.5.0                 (optional)
│        ├ paketo-buildpacks/environment-variables@4.4.0    (optional)
│        └ paketo-buildpacks/image-labels@4.3.0             (optional)
├ Group #2:
│  └ paketo-buildpacks/java@8.1.0
│     └ Group #1:
│        ├ paketo-buildpacks/ca-certificates@3.5.1               (optional)
│        ├ paketo-buildpacks/bellsoft-liberica@9.10.1
│        ├ paketo-buildpacks/syft@1.23.0                         (optional)
│        ├ paketo-buildpacks/leiningen@4.4.0                     (optional)
│        ├ paketo-buildpacks/clojure-tools@2.6.1                 (optional)
│        ├ paketo-buildpacks/gradle@6.10.0                       (optional)
│        ├ paketo-buildpacks/maven@6.11.0                        (optional)
│        ├ paketo-buildpacks/sbt@6.9.0                           (optional)
│        ├ paketo-buildpacks/watchexec@2.7.0                     (optional)
│        ├ paketo-buildpacks/executable-jar@6.5.0                (optional)
│        ├ paketo-buildpacks/apache-tomcat@7.9.1                 (optional)
│        ├ paketo-buildpacks/apache-tomee@1.4.0                  (optional)
│        ├ paketo-buildpacks/liberty@3.1.0                       (optional)
│        ├ paketo-buildpacks/dist-zip@5.4.0                      (optional)
│        ├ paketo-buildpacks/spring-boot@5.20.0                  (optional)
│        ├ paketo-buildpacks/procfile@5.5.0                      (optional)
│        ├ paketo-buildpacks/jattach@1.2.0                       (optional)
│        ├ paketo-buildpacks/azure-application-insights@5.9.3    (optional)
│        ├ paketo-buildpacks/google-stackdriver@7.0.0            (optional)
│        ├ paketo-buildpacks/datadog@3.1.0                       (optional)
│        ├ paketo-buildpacks/java-memory-assistant@1.2.0         (optional)
│        ├ paketo-buildpacks/encrypt-at-rest@4.3.2               (optional)
│        ├ paketo-buildpacks/environment-variables@4.4.0         (optional)
│        └ paketo-buildpacks/image-labels@4.3.0                  (optional)
├ Group #3:
│  ├ paketo-buildpacks/go@4.0.0
│  │  └ Group #1:
│  │     ├ paketo-buildpacks/ca-certificates@3.5.1          (optional)
│  │     ├ paketo-buildpacks/watchexec@2.7.0                (optional)
│  │     ├ paketo-buildpacks/go-dist@2.2.2
│  │     ├ paketo-buildpacks/git@1.0.0                      (optional)
│  │     ├ paketo-buildpacks/go-mod-vendor@1.0.6
│  │     ├ paketo-buildpacks/go-build@2.0.7
│  │     ├ paketo-buildpacks/procfile@5.5.0                 (optional)
│  │     ├ paketo-buildpacks/environment-variables@4.4.0    (optional)
│  │     └ paketo-buildpacks/image-labels@4.3.0             (optional)
│  └ paketo-buildpacks/go@4.0.0
│     └ Group #2:
│        ├ paketo-buildpacks/ca-certificates@3.5.1          (optional)
│        ├ paketo-buildpacks/watchexec@2.7.0                (optional)
│        ├ paketo-buildpacks/go-dist@2.2.2
│        ├ paketo-buildpacks/git@1.0.0                      (optional)
│        ├ paketo-buildpacks/go-build@2.0.7
│        ├ paketo-buildpacks/procfile@5.5.0                 (optional)
│        ├ paketo-buildpacks/environment-variables@4.4.0    (optional)
│        └ paketo-buildpacks/image-labels@4.3.0             (optional)
└ Group #4:
└ paketo-buildpacks/procfile@5.5.0

LOCAL:
(not present)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Inspect with AMD64
&lt;/h2&gt;

&lt;p&gt;On an AMD64 device:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pack builder inspect dashaun/builder:tiny &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/dashaun.builder.tiny.amd64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file will look very similar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inspecting builder: dashaun/builder:tiny

REMOTE:

Description: Tiny base image (bionic build image, distroless-like run image) with buildpacks for Java, Java Native Image and Go

Created By:
  Name: Pack CLI
  Version: 0.28.0+git-b10e41f.build-3729

Trusted: No

Stack:
  ID: io.paketo.stacks.tiny

Lifecycle:
  Version: 0.15.2
  Buildpack APIs:
    Deprecated: (none)
    Supported: 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9
  Platform APIs:
    Deprecated: (none)
    Supported: 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.10

Run Images:
  index.docker.io/paketobuildpacks/run:tiny-cnb
  gcr.io/paketo-buildpacks/run:tiny-cnb

Buildpacks:
  ID                                                  NAME                                                   VERSION        HOMEPAGE
  paketo-buildpacks/apache-tomcat                     Paketo Buildpack for Apache Tomcat                     7.9.1          https://github.com/paketo-buildpacks/apache-tomcat
  paketo-buildpacks/apache-tomee                      Paketo Buildpack for Apache Tomee                      1.4.0          https://github.com/paketo-buildpacks/apache-tomee
  paketo-buildpacks/azure-application-insights        Paketo Buildpack for Azure Application Insights        5.9.3          https://github.com/paketo-buildpacks/azure-application-insights
  paketo-buildpacks/bellsoft-liberica                 Paketo Buildpack for BellSoft Liberica                 9.10.1         https://github.com/paketo-buildpacks/bellsoft-liberica
  paketo-buildpacks/ca-certificates                   Paketo Buildpack for CA Certificates                   3.5.1          https://github.com/paketo-buildpacks/ca-certificates
  paketo-buildpacks/clojure-tools                     Paketo Buildpack for Clojure Tools                     2.6.1          https://github.com/paketo-buildpacks/clojure-tools
  paketo-buildpacks/datadog                           Paketo Buildpack for Datadog                           3.1.0          https://github.com/paketo-buildpacks/datadog
  paketo-buildpacks/dist-zip                          Paketo Buildpack for DistZip                           5.4.0          https://github.com/paketo-buildpacks/dist-zip
  paketo-buildpacks/encrypt-at-rest                   Paketo Buildpack for Encrypt-at-Rest                   4.3.2          https://github.com/paketo-buildpacks/encrypt-at-rest
  paketo-buildpacks/environment-variables             Paketo Buildpack for Environment Variables             4.4.0          https://github.com/paketo-buildpacks/environment-variables
  paketo-buildpacks/executable-jar                    Paketo Buildpack for Executable JAR                    6.5.0          https://github.com/paketo-buildpacks/executable-jar
  paketo-buildpacks/git                               Paketo Buildpack for Git                               1.0.0          https://github.com/paketo-buildpacks/git
  paketo-buildpacks/go                                Paketo Buildpack for Go                                4.0.0          https://github.com/paketo-buildpacks/go
  paketo-buildpacks/go-build                          Paketo Buildpack for Go Build                          2.0.7          https://github.com/paketo-buildpacks/go-build
  paketo-buildpacks/go-dist                           Paketo Buildpack for Go Distribution                   2.2.2          https://github.com/paketo-buildpacks/go-dist
  paketo-buildpacks/go-mod-vendor                     Paketo Buildpack for Go Mod Vendor                     1.0.6          https://github.com/paketo-buildpacks/go-mod-vendor
  paketo-buildpacks/google-stackdriver                Paketo Buildpack for Google Stackdriver                7.0.0          https://github.com/paketo-buildpacks/google-stackdriver
  paketo-buildpacks/gradle                            Paketo Buildpack for Gradle                            6.10.0         https://github.com/paketo-buildpacks/gradle
  paketo-buildpacks/image-labels                      Paketo Buildpack for Image Labels                      4.3.0          https://github.com/paketo-buildpacks/image-labels
  paketo-buildpacks/jattach                           Paketo Buildpack for JAttach                           1.2.0          https://github.com/paketo-buildpacks/jattach
  paketo-buildpacks/java                              Paketo Buildpack for Java                              8.1.0          https://paketo.io/docs/howto/java
  paketo-buildpacks/java-memory-assistant             Paketo Buildpack for Java Memory Assistant             1.2.0          https://github.com/paketo-buildpacks/java-memory-assistant
  paketo-buildpacks/java-native-image                 Paketo Buildpack for Java Native Image                 7.42.0         https://paketo.io/docs/howto/java/#build-an-app-as-a-graalvm-native-image-application
  paketo-buildpacks/leiningen                         Paketo Buildpack for Leiningen                         4.4.0          https://github.com/paketo-buildpacks/leiningen
  paketo-buildpacks/liberty                           Paketo Buildpack for Liberty                           3.1.0          https://github.com/paketo-buildpacks/liberty
  paketo-buildpacks/maven                             Paketo Buildpack for Maven                             6.11.0         https://github.com/paketo-buildpacks/maven
  paketo-buildpacks/native-image                      Paketo Buildpack for Native Image                      5.6.0          https://github.com/paketo-buildpacks/native-image
  paketo-buildpacks/procfile                          Paketo Buildpack for Procfile                          5.5.0          https://github.com/paketo-buildpacks/procfile
  paketo-buildpacks/sbt                               Paketo Buildpack for SBT                               6.9.0          https://github.com/paketo-buildpacks/sbt
  paketo-buildpacks/spring-boot                       Paketo Buildpack for Spring Boot                       5.20.0         https://github.com/paketo-buildpacks/spring-boot
  paketo-buildpacks/syft                              Paketo Buildpack for Syft                              1.23.0         https://github.com/paketo-buildpacks/syft
  paketo-buildpacks/upx                               Paketo Buildpack for UPX                               3.3.0          https://github.com/paketo-buildpacks/upx
  paketo-buildpacks/watchexec                         Paketo Buildpack for Watchexec                         2.7.0          https://github.com/paketo-buildpacks/watchexec

Detection Order:
 ├ Group #1:
 │  └ paketo-buildpacks/java-native-image@7.42.0
 │     └ Group #1:
 │        ├ paketo-buildpacks/ca-certificates@3.5.1          (optional)
 │        ├ paketo-buildpacks/upx@3.3.0                      (optional)
 │        ├ paketo-buildpacks/bellsoft-liberica@9.10.1
 │        ├ paketo-buildpacks/syft@1.23.0                    (optional)
 │        ├ paketo-buildpacks/leiningen@4.4.0                (optional)
 │        ├ paketo-buildpacks/gradle@6.10.0                  (optional)
 │        ├ paketo-buildpacks/maven@6.11.0                   (optional)
 │        ├ paketo-buildpacks/sbt@6.9.0                      (optional)
 │        ├ paketo-buildpacks/executable-jar@6.5.0           (optional)
 │        ├ paketo-buildpacks/spring-boot@5.20.0             (optional)
 │        ├ paketo-buildpacks/native-image@5.6.0
 │        ├ paketo-buildpacks/procfile@5.5.0                 (optional)
 │        ├ paketo-buildpacks/environment-variables@4.4.0    (optional)
 │        └ paketo-buildpacks/image-labels@4.3.0             (optional)
 ├ Group #2:
 │  └ paketo-buildpacks/java@8.1.0
 │     └ Group #1:
 │        ├ paketo-buildpacks/ca-certificates@3.5.1               (optional)
 │        ├ paketo-buildpacks/bellsoft-liberica@9.10.1
 │        ├ paketo-buildpacks/syft@1.23.0                         (optional)
 │        ├ paketo-buildpacks/leiningen@4.4.0                     (optional)
 │        ├ paketo-buildpacks/clojure-tools@2.6.1                 (optional)
 │        ├ paketo-buildpacks/gradle@6.10.0                       (optional)
 │        ├ paketo-buildpacks/maven@6.11.0                        (optional)
 │        ├ paketo-buildpacks/sbt@6.9.0                           (optional)
 │        ├ paketo-buildpacks/watchexec@2.7.0                     (optional)
 │        ├ paketo-buildpacks/executable-jar@6.5.0                (optional)
 │        ├ paketo-buildpacks/apache-tomcat@7.9.1                 (optional)
 │        ├ paketo-buildpacks/apache-tomee@1.4.0                  (optional)
 │        ├ paketo-buildpacks/liberty@3.1.0                       (optional)
 │        ├ paketo-buildpacks/dist-zip@5.4.0                      (optional)
 │        ├ paketo-buildpacks/spring-boot@5.20.0                  (optional)
 │        ├ paketo-buildpacks/procfile@5.5.0                      (optional)
 │        ├ paketo-buildpacks/jattach@1.2.0                       (optional)
 │        ├ paketo-buildpacks/azure-application-insights@5.9.3    (optional)
 │        ├ paketo-buildpacks/google-stackdriver@7.0.0            (optional)
 │        ├ paketo-buildpacks/datadog@3.1.0                       (optional)
 │        ├ paketo-buildpacks/java-memory-assistant@1.2.0         (optional)
 │        ├ paketo-buildpacks/encrypt-at-rest@4.3.2               (optional)
 │        ├ paketo-buildpacks/environment-variables@4.4.0         (optional)
 │        └ paketo-buildpacks/image-labels@4.3.0                  (optional)
 ├ Group #3:
 │  ├ paketo-buildpacks/go@4.0.0
 │  │  └ Group #1:
 │  │     ├ paketo-buildpacks/ca-certificates@3.5.1          (optional)
 │  │     ├ paketo-buildpacks/watchexec@2.7.0                (optional)
 │  │     ├ paketo-buildpacks/go-dist@2.2.2
 │  │     ├ paketo-buildpacks/git@1.0.0                      (optional)
 │  │     ├ paketo-buildpacks/go-mod-vendor@1.0.6
 │  │     ├ paketo-buildpacks/go-build@2.0.7
 │  │     ├ paketo-buildpacks/procfile@5.5.0                 (optional)
 │  │     ├ paketo-buildpacks/environment-variables@4.4.0    (optional)
 │  │     └ paketo-buildpacks/image-labels@4.3.0             (optional)
 │  └ paketo-buildpacks/go@4.0.0
 │     └ Group #2:
 │        ├ paketo-buildpacks/ca-certificates@3.5.1          (optional)
 │        ├ paketo-buildpacks/watchexec@2.7.0                (optional)
 │        ├ paketo-buildpacks/go-dist@2.2.2
 │        ├ paketo-buildpacks/git@1.0.0                      (optional)
 │        ├ paketo-buildpacks/go-build@2.0.7
 │        ├ paketo-buildpacks/procfile@5.5.0                 (optional)
 │        ├ paketo-buildpacks/environment-variables@4.4.0    (optional)
 │        └ paketo-buildpacks/image-labels@4.3.0             (optional)
 └ Group #4:
    └ paketo-buildpacks/procfile@5.5.0

LOCAL:
(not present)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, take a look at the &lt;code&gt;diff&lt;/code&gt; between those two files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;diff dashaun.builder.tiny.arm64 dashaun.builder.tiny.amd64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As I'm writing this, the &lt;code&gt;diff&lt;/code&gt; looks like this:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
text
&amp;lt; Inspecting builder: 'dashaun/builder:tiny'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>mobile</category>
      <category>softwaredevelopment</category>
      <category>devops</category>
    </item>
    <item>
      <title>Spring Cloud Gateway 4.0.0-RC2 native example with Testcontainers</title>
      <dc:creator>DaShaun</dc:creator>
      <pubDate>Fri, 09 Dec 2022 01:24:19 +0000</pubDate>
      <link>https://dev.to/dashaun/spring-cloud-gateway-400-rc2-native-example-with-testcontainers-1jpg</link>
      <guid>https://dev.to/dashaun/spring-cloud-gateway-400-rc2-native-example-with-testcontainers-1jpg</guid>
      <description>&lt;h1&gt;
  
  
  Spring Cloud Gateway 4.0.0-RC2 native example with Testcontainers
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/dashaun/dev.dashaun.service.gateway" rel="noopener noreferrer"&gt;This example repository is on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are 3 goals I have for this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deliver Spring Cloud Gateway as a graalvm-native-image with Spring Boot 3&lt;/li&gt;
&lt;li&gt;Get feedback on the multi-architecture buildpack that includes ARM64 support&lt;/li&gt;
&lt;li&gt;Demonstrate a pattern for building and testing buildpack images using Testcontainers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://spring.io/projects/spring-cloud-gateway" rel="noopener noreferrer"&gt;Spring Cloud Gateway&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;From the &lt;a href="https://spring.io/projects/spring-cloud-gateway" rel="noopener noreferrer"&gt;Spring.io&lt;/a&gt; website:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Spring Cloud Gateway aims to provide a simple,
yet effective way to route to APIs and provide
cross cutting concerns to them such as:
security, monitoring/metrics, and resiliency.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is very popular, and even more valuable than it is popular!&lt;/p&gt;

&lt;p&gt;Spring Framework 6 and Spring Boot 3.0.0 have recently gone GA. My favorite feature of these new releases is hands down the AOT processing. The AOT processing, provided by &lt;a href="https://graalvm.org" rel="noopener noreferrer"&gt;GraalVM&lt;/a&gt;, creates statically linked binary images. These images are optimized, ahead of time, for the operating system and architecture. For many modern workloads they can provide smaller image sizes, smaller memory footprint, and a much faster startup time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dashaun.com/posts/k3s-knative-ubuntu-raspberry-pi/" rel="noopener noreferrer"&gt;In a recent experiment&lt;/a&gt;, I was able to expose Spring Cloud Gateway to the public, and have it route to other Spring Boot 3 native image workloads. &lt;/p&gt;

&lt;p&gt;In that experiment Spring Cloud Gateway provided:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single service for SSL and ingress integration&lt;/li&gt;
&lt;li&gt;YAML configured routing&lt;/li&gt;
&lt;li&gt;Circuit Breaker capabilities with Resilience4j&lt;/li&gt;
&lt;li&gt;Request Rate Limiting with Redis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the experiment, I left the Spring Cloud Gateway running, by setting the &lt;code&gt;min-scale&lt;/code&gt; value to 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spring-cloud-gateway&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;autoscaling.knative.dev/initial-scale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
        &lt;span class="na"&gt;autoscaling.knative.dev/min-scale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
        &lt;span class="na"&gt;autoscaling.knative.dev/max-scale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2"&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dashaun/dev.dashaun.service.gateway:latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The other Spring Boot applications, being routed to by the gateway, were allowed to scale-to-zero when they weren't used.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dashaun.com/posts/k3s-knative-ubuntu-raspberry-pi/" rel="noopener noreferrer"&gt;The experiment was on a cluster of Raspberry Pi&lt;/a&gt; devices which are ARM64 cpus.&lt;/p&gt;

&lt;p&gt;The Spring Cloud Gateway, native image, typically starts up between 0.600s and 0.650s, on a Raspberry Pi.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dashaun.com/posts/spring-cloud-gateway-4-0-0-rc2-native-example-with-testcontainers/images/scg-startup-rpi.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspdl5fw2vxqmdsxihjdg.png" alt="SCG native image Raspberry Pi startup" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today, the buildpack delivered by &lt;a href="https://start.spring.io" rel="noopener noreferrer"&gt;Spring Initializr at start.spring.io&lt;/a&gt;, is unable to create native images on ARM64.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-architecture buildpack
&lt;/h2&gt;

&lt;p&gt;Earlier this year, I started working on a buildpack to use with the experimental project, &lt;code&gt;Spring Native&lt;/code&gt;, and ARM64, for my Raspberry Pi devices. Later the M1/M2 Apple Silicon community, also ARM64, began showing interest in using this buildpack. &lt;a href="https://hub.docker.com/r/dashaun/java-native-builder-arm64" rel="noopener noreferrer"&gt;I have delivered a few versions to date&lt;/a&gt;. I've also created some automation to improve my process for creating these buildpacks.&lt;/p&gt;

&lt;p&gt;Recently, I created a &lt;a href="https://hub.docker.com/r/dashaun/java-native-builder-multiarch" rel="noopener noreferrer"&gt;multi-architecture buildpack&lt;/a&gt; that can be used with Spring Boot 3, to create native images on both Intel/AMD64 and ARM64 architectures. This example repository is configured with this multi-architecture buildpack.&lt;/p&gt;

&lt;p&gt;I'm still working to improve this builder, in an effort to get ARM64 support upstream to &lt;a href="https://paketo.io" rel="noopener noreferrer"&gt;Paketo&lt;/a&gt;. I have a long way to go, but with your help, I can discover gaps and continue this effort. One of the known, and frustrating gaps today, is that UPX compression does not work on ARM64, it does work with AMD64.  I really want to get this figured out, and it is a high priority for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building and testing native images
&lt;/h2&gt;

&lt;p&gt;One of the most common concerns I have heard from the community this year has been around validating that the native image artifacts are delivering the same results as the JIT/JVM based artifacts. This is a very valid concern.  This is also why I feel, that organizations with mature testing capabilities today, will be able to move forward with native images faster.&lt;/p&gt;

&lt;p&gt;This repository provides a &lt;code&gt;BuildImageTest&lt;/code&gt; that uses the buildpack to create a native image.  It then tests the native image, using &lt;a href="https://testcontainers.org" rel="noopener noreferrer"&gt;Testcontainers&lt;/a&gt; and &lt;a href="https://junit.org" rel="noopener noreferrer"&gt;JUnit&lt;/a&gt;. Building the native image with AOT processing, as part of a test, takes minutes not seconds, and should not be part of normal "inner loop" development.  So the &lt;code&gt;BuildImageTest&lt;/code&gt; is in a separate &lt;code&gt;sourceSet&lt;/code&gt; and can be executed independently. This is a very powerful pattern, that I'm just getting started with. I would love to hear your thoughts on this pattern or other alternatives to it.&lt;/p&gt;

&lt;p&gt;To build and validate the native image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./gradlew integrationTest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;You can also execute the &lt;code&gt;BuildImageTest&lt;/code&gt; directly in your IDE.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;p&gt;I am having so much fun with all of these new capabilities and challenges. I want to thank the Spring team, for all of their amazing work bring Spring Framework 6 and Spring Boot 3 to GA. I also want to thank Daniel Mikusa and the Paketo community for being amazing to work with. I want to thank Sergei Egorov for &lt;a href="https://bsideup.github.io/posts/spring_boot_in_container/" rel="noopener noreferrer"&gt;sharing the testing pattern&lt;/a&gt; and supporting my Testcontainers journey. Finally, I would like to thank &lt;a href="https://danvega.dev" rel="noopener noreferrer"&gt;Dan Vega&lt;/a&gt;, my &lt;a href="http://bit.ly/spring-office-hours" rel="noopener noreferrer"&gt;Spring Office Hours&lt;/a&gt; cohost, for being an amazing teammate, and having the JUICE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep Learning
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://spring.io/projects/spring-cloud-gateway" rel="noopener noreferrer"&gt;Spring Boot Gateway&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spring.io/projects/spring-cloud" rel="noopener noreferrer"&gt;Spring Cloud 2022.0.0-RC2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spring.io/projects/spring-boot" rel="noopener noreferrer"&gt;Spring Boot 3.0.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://testcontainers.org" rel="noopener noreferrer"&gt;Testcontainers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dashaun.com/posts/spring-boot-3-buildpacks-with-testcontainers-cloud/" rel="noopener noreferrer"&gt;Spring Boot 3 buildpacks with Testcontainers Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dashaun.com/posts/java-native-builder-multiarch-7-41-0/" rel="noopener noreferrer"&gt;Cloud Native Buildpack for ARM64 and AMD64&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dashaun.com/posts/multiarch-builder-poc/" rel="noopener noreferrer"&gt;First attempt at a multi-architecture buildpack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dashaun.com/posts/k3s-knative-ubuntu-raspberry-pi/" rel="noopener noreferrer"&gt;K3s Knative Ubuntu Raspberry Pi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Cloud Native Buildpack for ARM64 and AMD64</title>
      <dc:creator>DaShaun</dc:creator>
      <pubDate>Tue, 06 Dec 2022 22:31:40 +0000</pubDate>
      <link>https://dev.to/dashaun/cloud-native-buildpack-for-arm64-and-amd64-39g2</link>
      <guid>https://dev.to/dashaun/cloud-native-buildpack-for-arm64-and-amd64-39g2</guid>
      <description>&lt;h1&gt;
  
  
  Version 7.41.0
&lt;/h1&gt;

&lt;p&gt;This builder works with Intel/AMD architectures and ARM64 architectures like Apple M1 and Raspberry Pi.&lt;/p&gt;

&lt;p&gt;With this release I was able to use a little more automation on my side, to get my &lt;code&gt;unsupported&lt;/code&gt; builder even closer to the &lt;a href="https://paketo.io" rel="noopener noreferrer"&gt;upstream at Paketo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/r/dashaun/java-native-builder-multiarch" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dmikusa/paketo-arm64" rel="noopener noreferrer"&gt;Daniel Mikusa GitHub Repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Roadmap
&lt;/h2&gt;

&lt;p&gt;I'm trying to make each of the buildpacks as similar as possible to each other and upstream.&lt;br&gt;
I'm also working on delivering newer versions of the stack, which is currently Ubuntu Focal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback welcome
&lt;/h2&gt;

&lt;p&gt;Please let me know how it is working for you, all of &lt;a href="https://dashaun.com" rel="noopener noreferrer"&gt;my socials/contact info can be found here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>githubcopilot</category>
      <category>github</category>
    </item>
    <item>
      <title>K3s Knative Ubuntu Raspberry Pi</title>
      <dc:creator>DaShaun</dc:creator>
      <pubDate>Tue, 06 Dec 2022 07:58:45 +0000</pubDate>
      <link>https://dev.to/dashaun/k3s-knative-ubuntu-raspberry-pi-45i0</link>
      <guid>https://dev.to/dashaun/k3s-knative-ubuntu-raspberry-pi-45i0</guid>
      <description>&lt;h1&gt;
  
  
  K3s Knative Ubuntu Raspberry Pi
&lt;/h1&gt;

&lt;p&gt;Knative is a super exciting solution for serverless and event driven applications.&lt;br&gt;
Personally, I have been using it as a part of my &lt;code&gt;inner loop&lt;/code&gt; development.&lt;br&gt;
I can deploy dozens of workloads.&lt;br&gt;
All scaled down to zero when they aren't being used.&lt;br&gt;
All responding and starting up quickly when they are needed.&lt;/p&gt;

&lt;p&gt;I ran into a couple of problems with Envoy on Raspberry Pi OS.&lt;br&gt;
After investigating, it is a known issue in the Raspberry Pi OS kernel.&lt;br&gt;
In order to keep going forward with my project I had to choose between fixing the kernel or trying Ubuntu.&lt;/p&gt;

&lt;p&gt;This is an overview of how to get Knative Serving working on a Raspberry Pi device with K3s and Ubuntu.&lt;/p&gt;
&lt;h2&gt;
  
  
  Install Ubuntu Server
&lt;/h2&gt;

&lt;p&gt;Use RPI Imager.&lt;br&gt;
Select &lt;code&gt;Ubuntu Server 22.10 64-bit&lt;/code&gt; from the list of other distributions.&lt;br&gt;
Boot the new image.&lt;/p&gt;

&lt;p&gt;I was happy to see that SSH and the default user were configured as expected by using the advanced settings options.&lt;/p&gt;
&lt;h2&gt;
  
  
  Upgrade the stuff
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Grab the latest repository info&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update 
&lt;span class="c"&gt;# Install one prerequisite package that isn't installed by default&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;linux-modules-extra-raspi &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="c"&gt;# Upgrade everything that can be upgraded&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt dist-upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Fix cgroup
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Add this to the beginning of /boot/firmware/cmdline.txt&lt;/span&gt;
&lt;span class="c"&gt;# cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;nano &lt;span class="nt"&gt;-w&lt;/span&gt; /boot/firmware/cmdline.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Reboot after making this change.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;shutdown &lt;span class="nt"&gt;-r&lt;/span&gt; now
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install k3s via k3sup
&lt;/h2&gt;

&lt;p&gt;From my laptop, not one of the Raspberry Pi nodes, run &lt;a href="https://github.com/alexellis/k3sup" rel="noopener noreferrer"&gt;k3sup&lt;/a&gt;, it's super easy.&lt;br&gt;
If you haven't figured it out by now, I'm a big fan of &lt;a href="https://github.com/alexellis/k3sup" rel="noopener noreferrer"&gt;k3sup&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CONTROL_NODE_IP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10.0.0.10
&lt;span class="c"&gt;# Disable Traefik because we will use kourier for knative&lt;/span&gt;
k3sup &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--ip&lt;/span&gt; &lt;span class="nv"&gt;$CONTROL_NODE_IP&lt;/span&gt; &lt;span class="nt"&gt;--user&lt;/span&gt; pi &lt;span class="nt"&gt;--k3s-extra-args&lt;/span&gt; &lt;span class="s1"&gt;'--disable traefik'&lt;/span&gt; &lt;span class="nt"&gt;--merge&lt;/span&gt; &lt;span class="nt"&gt;--local-path&lt;/span&gt; ~/.kube/config &lt;span class="nt"&gt;--context&lt;/span&gt; cluster00
&lt;span class="c"&gt;# Knative-Serving with Kourier works on a single Raspberry Pi 4 with 8GB&lt;/span&gt;
&lt;span class="c"&gt;# Optionally add other nodes&lt;/span&gt;
k3sup &lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="nt"&gt;--ip&lt;/span&gt; 10.0.0.11 &lt;span class="nt"&gt;--server-ip&lt;/span&gt; &lt;span class="nv"&gt;$CONTROL_NODE_IP&lt;/span&gt; &lt;span class="nt"&gt;--user&lt;/span&gt; pi
k3sup &lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="nt"&gt;--ip&lt;/span&gt; 10.0.0.12 &lt;span class="nt"&gt;--server-ip&lt;/span&gt; &lt;span class="nv"&gt;$CONTROL_NODE_IP&lt;/span&gt; &lt;span class="nt"&gt;--user&lt;/span&gt; pi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deep breath
&lt;/h2&gt;

&lt;p&gt;This is where I struggled with how to deliver this example.&lt;br&gt;
The &lt;a href="https://knative.dev/docs/install/yaml-install/serving/install-serving-with-yaml/" rel="noopener noreferrer"&gt;Knative install documentation&lt;/a&gt; is awesome.&lt;br&gt;
I've been through it dozens of times!&lt;/p&gt;

&lt;p&gt;I tried to simplify this for you.&lt;br&gt;
I want to give you the 'easy button' experience.&lt;br&gt;
I created a &lt;a href="https://github.com/dashaun/knative-serving-raspberry-pi" rel="noopener noreferrer"&gt;repository&lt;/a&gt; with all the YAML you need to deploy Knative Serving to this K3s cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Knative Serving with Kourier
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/dashaun/knative-serving-raspberry-pi
&lt;span class="nb"&gt;cd &lt;/span&gt;knative-serving-raspberry-pi/operator-serving-kourier
&lt;span class="c"&gt;# Use the `default` namespace in the Kubernetes cluster&lt;/span&gt;
kubectl config set-context &lt;span class="nt"&gt;--current&lt;/span&gt; &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;default
&lt;span class="c"&gt;# Deploy the Knative operator&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; operator.yaml
&lt;span class="c"&gt;# Check the deployment status&lt;/span&gt;
kubectl get deployment knative-operator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Continue when &lt;code&gt;Ready&lt;/code&gt; status is &lt;code&gt;1/1&lt;/code&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME               READY   UP-TO-DATE   AVAILABLE   AGE
knative-operator   1/1     1            1           19h
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install Knative Serving custom resource and Kourier&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; knative-serving.yaml
&lt;span class="c"&gt;# Check the custom resource status&lt;/span&gt;
kubectl get KnativeServing knative-serving &lt;span class="nt"&gt;-n&lt;/span&gt; knative-serving
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Continue when &lt;code&gt;READY&lt;/code&gt; is &lt;code&gt;True&lt;/code&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME              VERSION   READY   REASON
knative-serving   1.8.0     True
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check the deployment status&lt;/span&gt;
kubectl get deployment &lt;span class="nt"&gt;-n&lt;/span&gt; knative-serving
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Continue when &lt;code&gt;READY&lt;/code&gt; are all &lt;code&gt;1/1&lt;/code&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
activator                1/1     1            1           23m
autoscaler               1/1     1            1           23m
controller               1/1     1            1           23m
domain-mapping           1/1     1            1           23m
domainmapping-webhook    1/1     1            1           23m
autoscaler-hpa           1/1     1            1           23m
3scale-kourier-gateway   1/1     1            1           23m
webhook                  1/1     1            1           23m
net-kourier-controller   1/1     1            1           23m
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  SSLIP.IO and a Spring Boot 3 &lt;code&gt;native&lt;/code&gt; application
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install default domain&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; serving-default-domain.yaml
&lt;span class="c"&gt;# Deploy a Spring Boot 3 `native` application&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; spring-boot-native-pi-service.yaml
&lt;span class="c"&gt;# Get the address&lt;/span&gt;
kubectl get ksvc spring-boot-native-pi &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;custom-columns&lt;span class="o"&gt;=&lt;/span&gt;NAME:.metadata.name,URL:.status.url
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                    URL
spring-boot-native-pi   http://spring-boot-native-pi.default.10.0.0.10.sslip.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Curl the address provided by knative with `/actuator/health` at the end&lt;/span&gt;
curl http://spring-boot-native-pi.default.default.10.0.0.10.sslip.io/actuator/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Expected output:&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"status":"UP"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;With the recent release of Spring Boot 3.0.0, my Raspberry Pi collection has become significantly more interesting.&lt;br&gt;
Knative Serving allows me to deploy dozens of Spring Boot / Spring Cloud workloads to a tiny, low power device, with very exciting capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep Learning
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://knative.dev" rel="noopener noreferrer"&gt;Knative&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/" rel="noopener noreferrer"&gt;Spring Boot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dashaun/knative-serving-raspberry-pi" rel="noopener noreferrer"&gt;Knative Serving Raspberry Pi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>career</category>
      <category>community</category>
    </item>
    <item>
      <title>Spring Boot 3 Buildpacks with Testcontainers Cloud</title>
      <dc:creator>DaShaun</dc:creator>
      <pubDate>Tue, 22 Nov 2022 05:55:59 +0000</pubDate>
      <link>https://dev.to/dashaun/spring-boot-3-buildpacks-with-testcontainers-cloud-5fd2</link>
      <guid>https://dev.to/dashaun/spring-boot-3-buildpacks-with-testcontainers-cloud-5fd2</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I have a modest laptop. It checks the boxes, for just about everything I need to do for work. Just about. AOT processing, with GraalVM, is not a great experience on this machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  The origin story
&lt;/h2&gt;

&lt;p&gt;Back in June 2022, I was presenting at SpringOne Tour NYC. As part of the demo, I built a &lt;code&gt;native&lt;/code&gt; image using Spring Boot 2.7 with the &lt;code&gt;spring-native&lt;/code&gt; experimental dependency. The session went well, except for the building the native image part of it. During my 50-minute session, my laptop was busy building the native image for over 8-minutes, using the buildpack. It was a humbling experience. After the session, I hung out with Sergei Egorov, and we worked on something very special. With help from &lt;a href="https://bsideup.github.io/posts/spring_boot_in_container/"&gt;one of his previous blog posts&lt;/a&gt;, we created a proof of concept. We used &lt;a href="https://www.testcontainers.cloud/"&gt;Testcontainers Cloud&lt;/a&gt; to build the native OCI image, in the cloud, in a little over 3-minutes. Pairing with Sergei is amazing, if you get the chance, I highly recommend it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/dashaun/status/1541812027286495235"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XevAkji7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dashaun.com/posts/spring-boot-3-buildpacks-with-testcontainers-cloud/images/origin-tweet.png" alt="Origin Story" width="800" height="1095"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  It sat on the back-burner and fire is hot
&lt;/h2&gt;

&lt;p&gt;I had this code sitting in my repository, waiting to be used. When it was time for SpringOne Tour Tel Aviv, Nov 2022, I was ready to show it off. Unfortunately for me, my session was shortened, so I pulled it out of the presentation. I shouldn’t have pulled it out, I made the exact same mistake that I made in NYC. When I built the native image using buildpacks, it took way too long on my laptop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Momentum
&lt;/h2&gt;

&lt;p&gt;My adventures with buildpacks have been top of mind for a couple of weeks now. Oleg Šelajev and Cora Iberklied also presented about testcontainers in Tel Aviv. The stage was set for me to take this use case further.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Goal
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Build Spring Boot 3, native OCI images, with buildpacks, during demos, faster, with Testcontainers Cloud
&lt;/h3&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You need to have an account at &lt;a href="https://testcontainers.cloud"&gt;https://testcontainers.cloud&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Login to your account
&lt;/h2&gt;

&lt;p&gt;I’m logging in with &lt;code&gt;v1.3.11&lt;/code&gt; of the cloud desktop app for Mac, this is still in private beta at the time of this writing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker context list

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;You should see at least one context named ’tcc'&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker context use tcc

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create an application example
&lt;/h2&gt;

&lt;p&gt;Create a Spring Boot 3 application with &lt;code&gt;web&lt;/code&gt;, &lt;code&gt;actuator&lt;/code&gt;, and &lt;code&gt;testcontainers&lt;/code&gt; for a simple test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://start.spring.io/starter.tgz -d dependencies=web,actuator,testcontainers -d javaVersion=17 -d bootVersion=3.0.0-RC2 -d type=maven-project | tar -xzf -

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Spring Boot 3 goes GA later this week, but I can’t wait that long&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the pom.xml add this dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.apache.maven.shared&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;maven-invoker&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.2.0&amp;lt;/version&amp;gt;
    &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;testcontainers.version&amp;gt;1.17.6&amp;lt;/testcontainers.version&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this dependency management section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.testcontainers&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;testcontainers-bom&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;${testcontainers.version}&amp;lt;/version&amp;gt;
            &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
            &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
&amp;lt;/dependencyManagement&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those pieces will allow you to write a test, that creates an OCI image, using buildpacks, with Testcontainers Cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the test class
&lt;/h2&gt;

&lt;p&gt;Here is the test class that I’ve been reusing since June.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.example.demo;

import org.apache.maven.shared.invoker.DefaultInvocationRequest;
import org.apache.maven.shared.invoker.DefaultInvoker;
import org.apache.maven.shared.invoker.InvocationResult;
import org.apache.maven.shared.invoker.MavenInvocationException;
import org.junit.jupiter.api.Test;
import org.springframework.util.DigestUtils;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.LazyFuture;

import java.io.File;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Future;

public class TccTest {
    private static final Future&amp;lt;String&amp;gt; IMAGE_FUTURE = new LazyFuture&amp;lt;&amp;gt;() {
        @Override
        protected String resolve() {
            // Find project's root dir
            File cwd;
            for (
                    cwd = new File(".");
                    !new File(cwd, "mvnw").isFile();
                    cwd = cwd.getParentFile()
            );

            // Make it unique per folder (for caching)
            var imageName = String.format(
                    "local/app-%s:%s",
                    DigestUtils.md5DigestAsHex(cwd.getAbsolutePath().getBytes()),
                    System.currentTimeMillis()
            );

            var properties = new Properties();
            properties.put("spring-boot.build-image.imageName", imageName);
            properties.put("skipTests", "true");

            var request = new DefaultInvocationRequest()
                    .addShellEnvironment("DOCKER_HOST", DockerClientFactory.instance().getTransportConfig().getDockerHost().toString())
                    .setPomFile(new File(cwd, "pom.xml"))
                    .setGoals(List.of("spring-boot:build-image"))
                    .setMavenExecutable(new File(cwd, "mvnw"))
                    .setProfiles(List.of("native"))
                    .setProperties(properties);

            InvocationResult invocationResult = null;
            try {
                invocationResult = new DefaultInvoker().execute(request);
            } catch (MavenInvocationException e) {
                throw new RuntimeException(e);
            }

            if (invocationResult.getExitCode() != 0) {
                throw new RuntimeException(invocationResult.getExecutionException());
            }

            return imageName;
        }
    };

    static final GenericContainer&amp;lt;?&amp;gt; APP = new GenericContainer&amp;lt;&amp;gt;(IMAGE_FUTURE)
            .withExposedPorts(8080);

    @Test
    void letsGo() throws Exception {
        APP.start();
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;a href="https://github.com/dashaun/spring-boot-3-buildpacks-with-testcontainers-cloud"&gt;my example repository&lt;/a&gt;, I actually create test classes for a regular OCI image and a &lt;code&gt;native&lt;/code&gt; OCI image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./mvnw clean test

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boom! You get an OCI image, or two if you use &lt;a href="https://github.com/dashaun/spring-boot-3-buildpacks-with-testcontainers-cloud"&gt;my example repository&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker images | grep "local"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This is slick. It brings me joy. When I am presenting this topic, I no longer need to have &lt;code&gt;Docker Desktop&lt;/code&gt; running on my laptop. Therefore, my laptop battery will last longer. My builds will be consistently faster, using Testcontainers Cloud, and my demos will be smoother.&lt;/p&gt;

&lt;p&gt;I am completely rethinking a few of my own use cases. I will definitely create more Testcontainers Cloud content in the future.&lt;/p&gt;

&lt;p&gt;Please let me know what you think!&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://testcontainers.cloud"&gt;Testcontainers Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dashaun/spring-boot-3-buildpacks-with-testcontainers-cloud"&gt;Example Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bsideup.github.io/posts/spring_boot_in_container/"&gt;Sergei Egorov Blog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vx9PlwbP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dashaun.com/posts/spring-boot-3-buildpacks-with-testcontainers-cloud/images/sergei-pairing.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vx9PlwbP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dashaun.com/posts/spring-boot-3-buildpacks-with-testcontainers-cloud/images/sergei-pairing.png" alt="Pairing with Sergei" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>First attempt at a multi-arch buildpack for Spring Boot 3</title>
      <dc:creator>DaShaun</dc:creator>
      <pubDate>Sat, 12 Nov 2022 13:58:51 +0000</pubDate>
      <link>https://dev.to/dashaun/first-attempt-at-a-multi-arch-buildpack-for-spring-boot-3-4p2d</link>
      <guid>https://dev.to/dashaun/first-attempt-at-a-multi-arch-buildpack-for-spring-boot-3-4p2d</guid>
      <description>&lt;p&gt;My &lt;a href="https://dashaun.com/paketo-aarch64-builder-spring-boot-3.rc1"&gt;previous builder&lt;/a&gt; generated some fabulous feedback, including &lt;a href="https://github.com/jabrena/101-docker/issues/57"&gt;an issue in GitHub&lt;/a&gt;. It also opened the door for some wonderful collaborations while I have been traveling to Barcelona and Tel Aviv.&lt;/p&gt;

&lt;p&gt;On this journey of trying to get ARM64 support into the upstream &lt;a href="https://paketo.io"&gt;Paketo buildpacks&lt;/a&gt; I have learned so much. The next step is to prove that we can create the pipelines that can deliver a multi-architecture image.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Skip to the &lt;a href="https://github.com/dashaun/java-native-builder-multiarch"&gt;Quick Start here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Docker manifest
&lt;/h2&gt;

&lt;p&gt;In order to see the architecture of an image, you can use the &lt;code&gt;docker manifest&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Inspect shows the image architecture
docker manifest inspect --verbose dashaun/java-native-builder-arm64:7.37.0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Inspecting the ARM64 builder that was created in earlier article&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Create a new manifest list
&lt;/h2&gt;

&lt;p&gt;The process for slapping docker images together is pretty simple. Ideally you should be using the “same” image, but we are just proving a point here.&lt;/p&gt;

&lt;p&gt;My theory is that if I provide an &lt;code&gt;arm64&lt;/code&gt; architecture and an &lt;code&gt;amd64&lt;/code&gt; architecture to the same manifest list, that it will work as expected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# create a new manifest with a name and tag
docker manifest create dashaun/java-native-builder-multiarch:7.37.0 \
# add ARM64 builder
--amend dashaun/java-native-builder-arm64:7.37.0 \
# add Paketo tiny builder for AMD64
--amend paketobuildpacks/builder:tiny

# push the manifest to the repository
docker manifest push dashaun/java-native-builder-multiarch:7.37.0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;That’s it!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  inspect the manifest list - the builder
&lt;/h2&gt;

&lt;p&gt;Now you can inspect the manifest and see that it has packaged ARM64 and AMD64 architectures. This capability has been available for years. It is also surprisingly simple to accomplish as you can see.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker manifest inspect --verbose dashaun/java-native-builder-multiarch:7.37.0


[
    {
        "Ref": "docker.io/dashaun/java-native-builder-arm64:7.37.0",
        "Descriptor": {
            "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
            "digest": "sha256:80771c9c2efee25020ba60e320c41cc385a333434ad2982ed7326a0a413b9ae7",
            "size": 5150,
            "platform": {
                "architecture": "arm64",
                "os": "linux"
            }
        },
        "SchemaV2Manifest": {
            "schemaVersion": 2,
            "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
            "config": {
                "mediaType": "application/vnd.docker.container.image.v1+json",
                "size": 12587,
                "digest": "sha256:8cd1ead83689b853055ac2de0cc07c5f3c9d8d087b2ac97e838551fe8e962e00"
            },
            "layers": [
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 27195998,
                    "digest": "sha256:4e7e0215f4adc2c48ad9cb3b3781e21d474b477587f85682c2e2975ae91dce9d"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 4348,
                    "digest": "sha256:fc2e670f062f6edbb1b3be6aae88cbc0978a5273314c365bc4e99d861dfb5ff1"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 103281689,
                    "digest": "sha256:cba3892e6fcca4b47983803d53b777bc05476639fcfc1a2d4f384eac40363677"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 179,
                    "digest": "sha256:f5230b5f167cfc41fb9f96d53de0d9c5832e3b03e3a705052cf42ceada13aea9"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 197,
                    "digest": "sha256:357fefdf9bc907107a38600cf8d79c713346dc97370273d1aa79635d97a2f6f9"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 8870380,
                    "digest": "sha256:0ab7ccc1e1a42589b53d1397672009a979b296933efc276d79d3a2cdc336656c"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2498256,
                    "digest": "sha256:fa161ac7a0015773c3f6890d6f1824957a6e21cee5a9bbf8ddc60e4e6d30a3ed"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 1806073,
                    "digest": "sha256:bdfdd20caee6a7044607d11d9a4f758a007ad2d61399ea5e3db22a7037ab4975"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 3273385,
                    "digest": "sha256:bc251569386a8e5fd513c85d9c51e76a258f0e59d0f945e185e101930012c9db"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 1509592,
                    "digest": "sha256:caeca36964d2da6c2b88abd998281e4fd5b708cfdd1440486f6acf7bc569292e"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 3191207,
                    "digest": "sha256:f840d9ee444653d04a2181d1d99e4f579d01b56349cce9325c6dade9af410998"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 3273637,
                    "digest": "sha256:b4f56cede28073295dc750e93678876a55b9fdafd97c940b97dc9a01ae345663"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2387292,
                    "digest": "sha256:cebaf5f7c6e3350f5973f2c77f9ba90138d5a6bb2f1eb9e86084c8cf9f6117c6"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 4208510,
                    "digest": "sha256:47be0bf349071cb594970ef2d18f383b91231645ba49f27b5b39b47d9090aedc"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 1818619,
                    "digest": "sha256:5844db3d59f2bdc13aa19a6fd09789cf4a12aa87088759840a79c10eb01f93c5"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 1569855,
                    "digest": "sha256:89975d6b7daf9b8cf8b1a8350461e9e009b0ffc2a482becb9e1073adc3475153"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2413551,
                    "digest": "sha256:aca3b8db4220fa7d69bf9cbd0bebc048cfa381174929828affb820c5b6b0f505"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2480839,
                    "digest": "sha256:71bd4e702bfc97f1db60e6a5ac364897b2818dc2f92f1bf9d78c2935a1ae125d"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2521983,
                    "digest": "sha256:3e1f506f69017dbcedb2a2b022ff0d6e63d4c0cd44e32fdcf6cc9e39b2416ade"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2475996,
                    "digest": "sha256:f617bf8af0912672e16ed61332d6e7ad1f0ffc4fffe049da45ea670a1c441afd"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 362,
                    "digest": "sha256:0e3fabdd36281c4c1c946d09854510dc82ffd61476d62aaa474b3c64d8969ae3"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 151,
                    "digest": "sha256:9602e7831cd64261f173d4789e26f9cada67107ba1688409f7781bd737792b58"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 32,
                    "digest": "sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1"
                }
            ]
        }
    },
    {
        "Ref": "docker.io/paketobuildpacks/builder:tiny",
        "Descriptor": {
            "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
            "digest": "sha256:e5b4e4e720598e905baa793a94259ee75827949a6ba22a3d3196eb332e475dd6",
            "size": 9773,
            "platform": {
                "architecture": "amd64",
                "os": "linux"
            }
        },
        "SchemaV2Manifest": {
            "schemaVersion": 2,
            "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
            "config": {
                "mediaType": "application/vnd.docker.container.image.v1+json",
                "size": 64488,
                "digest": "sha256:94a3f804e111904682577130709e0cac6e0541e6b1931c1f9aa4f27326c974fc"
            },
            "layers": [
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 29589398,
                    "digest": "sha256:38496a9cab3e2bb43fa8ae1d45c3ddc1d2f89328e1f3973f029949b8cb2dd5fe"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 247,
                    "digest": "sha256:2e7826560210e2f0d4249f9ea20651fecd45306c2482767274c8c37289c23788"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 316,
                    "digest": "sha256:6013ff26a0374342ff4848b3171ddbe396413d80faa2b1ee67ca9afbfa64cafc"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 106179950,
                    "digest": "sha256:87196f2fd40c0ee5587ff771878aad41b42c1d29628c75fff9206b5c0b77f016"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 188,
                    "digest": "sha256:d61afba38b8e093dfc46b8e81c141b2d7eddc0903b0fc530b3af36a46a144af7"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2744757,
                    "digest": "sha256:856e5ee7330534a520c3fd1d90260e9a5e99bfc182e0c2c3b18f7fea06f0bb0e"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 807,
                    "digest": "sha256:7eededf5887404e40dfc0d1d533fb9db3fe6b725213e4f3edda1ca1f5b1492c4"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 197,
                    "digest": "sha256:357fefdf9bc907107a38600cf8d79c713346dc97370273d1aa79635d97a2f6f9"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 9753557,
                    "digest": "sha256:d0d113e4e2bd21dbaa2f66e687ec4a23e4e83331b7845b85d0c10de1da05b08d"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2574003,
                    "digest": "sha256:41869a3aefd1a5bf8db003eb401d1af5ef2568c92262c3038f553d38145f36a1"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2573999,
                    "digest": "sha256:053ee41df41d6484ffec64fda64937a6418a1404f602487019fccddbad2958de"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 4641532,
                    "digest": "sha256:0fec499a25de5a35aa814bed46943a93c94d0e6785eedc679874ec3da04bc748"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2525673,
                    "digest": "sha256:c7b3308e13d3f30bde70d2293590aefdb95e52784b8bb840e13c587d354604e6"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 8714351,
                    "digest": "sha256:51918c870f73c8ceffc527e79041e08d3101beeabd0c0bc44555b6faf1188cdd"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 3197061,
                    "digest": "sha256:fbb9179cbbb1aa191e9ec19e77b7e6226b97ba8ac9d382822970ddcc61ce05e2"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2661004,
                    "digest": "sha256:38876f988da32a7ef093d5245f6923bb9b748362834345a3e8995f72ef49e168"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2547018,
                    "digest": "sha256:b847bb2fe3fdc6bd69cd7d690bcef5a1399310ce17bea49bbd1d5fd3641d0140"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 3291941,
                    "digest": "sha256:78b11fcb7ca30ba09defc8dcfc1298ea20b970430d9836b4bc7c404840b49a03"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 3255182,
                    "digest": "sha256:18ee4cd834fc95727859c15eaedc1f5670c4e9f3f74e3f45a108d5b9167344ab"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 1576728,
                    "digest": "sha256:ad443f24b1ed77880e534a0c1aca0ca5a722e866b7611a85e9fd7ef3463dea08"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 1511595,
                    "digest": "sha256:a6cd17527f03923a723839bdbe57ec200a008de6c8b35c0c4d900a675adac014"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2689335,
                    "digest": "sha256:cd146e648d04aaf6161526eb8be96d3bf9c8fc22e433c4e6834dc972b4f09830"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 3478686,
                    "digest": "sha256:bf32d3cbc5fb2d1c54c54f964b11e10d70c58f340dc17857d45db246807bcca6"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2639800,
                    "digest": "sha256:c505716a4281aec3fc577e417a29d23a19d1ff720f498aef49b9ed362ab53d88"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 3382413,
                    "digest": "sha256:17c8e16edff8afd8ef3b3b1d1d061351245287c59c6ab8846c1af94b414e1865"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 555,
                    "digest": "sha256:57bf259ba83920a4e2575582423c084670209a37fdb503fbbc7e10d75a5419d0"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2798929,
                    "digest": "sha256:e71af6bec187b3f6627f52f6f2808c6b946b5cc09b7f4a6ee006cc5557254ebc"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 1678930,
                    "digest": "sha256:fcf29a1baad8cb3d657d685b47ab630602a5c47b333f7ed9d7cbcae68a300801"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 1826608,
                    "digest": "sha256:fad10dc586613d133e71639507d157251d8d533d9c94c3897ed5ae6c557bcdf7"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2637303,
                    "digest": "sha256:bc22ffea56cce18044465269f6958bfb8ef37e182c82c6ab9f2821525c034717"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 1623998,
                    "digest": "sha256:63fd16f5b2cc4af356f18b61281870994919fcb17f3a51f490fc09b6cd5e0cfe"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 3091878,
                    "digest": "sha256:71dea8ea27aab08e92be2cb1c61ba12693f8dc622575cd9087e689fdabd048fd"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 8496432,
                    "digest": "sha256:547d0874d2b5a13d766fc98a54725cce8b5ec50af624d5c21b971ca0e668d7e0"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2644647,
                    "digest": "sha256:27bd211db33f03f1ad558807c8312a3bf537e154b591f7067a7eab8d9364f10b"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 5318,
                    "digest": "sha256:3455451f8d3fd909057c5f94d9c34b5618fa6f62db51ed540cd7931c146a5fd6"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 3472177,
                    "digest": "sha256:a77b05080df7a983ee586813839673e2dfdb852c87589ddf0900517bc928b779"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 8659224,
                    "digest": "sha256:6a58fb7cc75d73d08a6d85d995ad767e5693c4afd8b4f94f89f61018a3925c67"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 5136,
                    "digest": "sha256:437d9ac90cf3a6df605fbc9b691455242c3f4d7a3ba89b683daa5885314f1909"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 4385434,
                    "digest": "sha256:52814f0ca0c9d85074d817b558ccb3583cdb394d1ec02cf3e45e860b24ef3f7b"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 1838119,
                    "digest": "sha256:7e8facf10ccafea1b9688a4a4ba424d36f92e3e4cea1e913577bb45eb5bdc5f9"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 2464280,
                    "digest": "sha256:b8531cb5032999225be8589ab8bec5ea275fffb47353863c29d1afcdf7966104"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 3468583,
                    "digest": "sha256:55e985d488da8faeaa9772b7cfb3073d458fa626c89a390b292ab879be30f157"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 214,
                    "digest": "sha256:7d37e76963e86dbc76a9cbd3a6afa21c127bb790f77415b608da57daa9019f10"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 187,
                    "digest": "sha256:3aaaa9c943efae7533b9a28a28a676354866cad58208bcd7988b055c754653f0"
                },
                {
                    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                    "size": 32,
                    "digest": "sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1"
                }
            ]
        }
    }
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  validation
&lt;/h2&gt;

&lt;p&gt;Create a Spring Boot 3 application with &lt;code&gt;web&lt;/code&gt; and &lt;code&gt;actuator&lt;/code&gt; which is enough for a simple test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create a Spring Boot 3 application
curl https://start.spring.io/starter.tgz -d dependencies=web,actuator -d javaVersion=17 -d bootVersion=3.0.0-SNAPSHOT -d type=maven-project | tar -xzf -

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;I’m using SNAPSHOT, because YOLO, but RC2 is already available!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Add a profile to the pom.xml, that will use the &lt;code&gt;multi-arch&lt;/code&gt; builder that we created above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Remove the last line of the pom.xml file (on Mac OS X)
sed -i '' -e '$ d' pom.xml
# Add the new profile to the end of the pom.xml
echo "
  &amp;lt;profiles&amp;gt;
    &amp;lt;profile&amp;gt;
      &amp;lt;id&amp;gt;dashaun&amp;lt;/id&amp;gt;
      &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
          &amp;lt;plugin&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;configuration&amp;gt;
              &amp;lt;image&amp;gt;
                &amp;lt;builder&amp;gt;dashaun/java-native-builder-multiarch:7.37.0&amp;lt;/builder&amp;gt;
              &amp;lt;/image&amp;gt;
            &amp;lt;/configuration&amp;gt;
          &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
      &amp;lt;/build&amp;gt;
    &amp;lt;/profile&amp;gt;
  &amp;lt;/profiles&amp;gt;
&amp;lt;/project&amp;gt;" &amp;gt;&amp;gt; pom.xml 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your project will use the multi-architecture builder that created.&lt;/p&gt;

&lt;h2&gt;
  
  
  optional
&lt;/h2&gt;

&lt;p&gt;To watch, and be amazed, by the correct images being pulled down to your machine, run these commands to remove any unused images from your machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker kill $(docker ps -q)
docker system prune -a --volumes

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  build on AMD64 or ARM64
&lt;/h2&gt;

&lt;p&gt;The magical moment! You can do this from AMD64 or ARM64.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./mvnw -Pnative,dashaun spring-boot:build-image

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should have an image created. One layer of that image, is a statically linked binary for your architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  inspect the new image.
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# find the local image
docker images | grep demo
# Look at the architecture for the image
docker inspect demo:0.0.1-SNAPSHOT | jq '.[0].Architecture'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;| jq.[0].Architecture&lt;/code&gt; can be replaced with &lt;code&gt;| grep Architecture&lt;/code&gt; if you don’t have &lt;code&gt;jq&lt;/code&gt; installed&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  run and test the image
&lt;/h2&gt;

&lt;p&gt;Run the OCI image with &lt;code&gt;docker&lt;/code&gt; to start up the server. It should start quickly!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Forward the port, run in the background, but see the startup time
docker run -p 8080:8080 demo:0.0.1-SNAPSHOT 
# Check the endpoint to validate
http :8080/actuator/health

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/dashaun/java-native-builder-multiarch"&gt;GitHub dashaun/java-native-builder-multiarch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/r/dashaun/java-native-builder-multiarch"&gt;Docker dashaun/java-native-builder-multiarch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dashaun/paketo-arm64"&gt;dashaun/paketo-arm64&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dashaun.com/posts/paketo-aarch64-builder-spring-boot-3-rc1/"&gt;Related Post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://twitter.com/dashaun/status/1591432189488803840"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M6az9bBH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dashaun.com/posts/multiarch-builder-poc/images/itsworking.png" alt="Its working" width="800" height="978"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;I want to hear from you! All of my social links are &lt;a href="https://dashaun.com"&gt;here at dashaun.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Issues and feedback can be left in the &lt;a href="https://github.com/dashaun/java-native-builder-multiarch"&gt;GitHub dashaun/java-native-builder-multiarch&lt;/a&gt; repository.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A new builder for Spring Boot 3 RC1 on ARM64</title>
      <dc:creator>DaShaun</dc:creator>
      <pubDate>Thu, 10 Nov 2022 11:18:05 +0000</pubDate>
      <link>https://dev.to/dashaun/a-new-builder-for-spring-boot-3-rc1-on-arm64-4k31</link>
      <guid>https://dev.to/dashaun/a-new-builder-for-spring-boot-3-rc1-on-arm64-4k31</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I’m a fan of using buildpacks. I’ve been &lt;a href="https://dashaun.com/posts/springboot-arm64-image/"&gt;using&lt;/a&gt; and updating the &lt;a href="https://github.com/dmikusa/paketo-arm64"&gt;paketo-arm64 repository started by Daniel Mikusa&lt;/a&gt;. With Spring Boot 3 going GA, very soon, more people are wanting to use buildpacks with their M1 machines. I feel pressure, in a great way, to get a new version released that includes the latest version of GraalVM.&lt;/p&gt;

&lt;p&gt;Because I’m not doing this regularly, I forget the steps that I take to create a new build. So this post, is really a reminder-to-self, but hopefully it helps someone else also.&lt;/p&gt;

&lt;p&gt;You can follow along with this on &lt;code&gt;M1&lt;/code&gt;,&lt;code&gt;Raspberry Pi&lt;/code&gt;, or a free-tier &lt;code&gt;ARM64&lt;/code&gt; instance from Oracle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite
&lt;/h2&gt;

&lt;p&gt;I’ve been setting up a temporary ARM64 machine on Oracle Cloud for ARM64/aarch64 builds. The repository I use is &lt;a href="https://github.com/dashaun/oci-arm64-gha-runner-terraform"&gt;here&lt;/a&gt;. I should probably talk about that in another post, also.&lt;/p&gt;

&lt;p&gt;My first step was to deploy that machine, so it can be used to build the builder! Once I got the machine up and connected to my repository, I was ready to update the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make changes
&lt;/h2&gt;

&lt;p&gt;First I just made changes to the versions in &lt;a href="https://raw.githubusercontent.com/dashaun/paketo-arm64/main/.github/workflows/paketo-arm64.yml"&gt;my GitHub workflow&lt;/a&gt;. That worked and pushed out a new image, but it wasn’t enough.&lt;/p&gt;

&lt;p&gt;I had to re-read the workflow to understand what I was missing.&lt;/p&gt;

&lt;p&gt;For each of the files in the &lt;code&gt;arm64-toml&lt;/code&gt; of &lt;a href="https://github.com/dashaun/paketo-arm64"&gt;the repository&lt;/a&gt; I needed to update to the latest versions. This is a tedious, and currently manual, process that requires copy, paste, merge and then creating sha256 values.&lt;/p&gt;

&lt;p&gt;For these versions, it was extra messy, because naming conventions changed since my last release. In some places &lt;code&gt;arm64&lt;/code&gt; was replaced with &lt;code&gt;aarch64&lt;/code&gt; as one example.&lt;/p&gt;

&lt;p&gt;Additionally, some dependencies had even more releases, and I decided to go with the &lt;code&gt;full&lt;/code&gt; option when it was available.&lt;/p&gt;

&lt;p&gt;The last real time-suck was the &lt;code&gt;sha&lt;/code&gt; values. In the GitHub releases, the sha values are provided as &lt;code&gt;sha1sum&lt;/code&gt; values. In the builder metadata, it requires &lt;code&gt;sha256&lt;/code&gt; values. Since I couldn’t find &lt;code&gt;sha256&lt;/code&gt; values published anywhere, I had to download the dependencies and calculate the values manually. For each dependency update, &lt;code&gt;curl&lt;/code&gt; then &lt;code&gt;shasum&lt;/code&gt;, which can be error prone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -L https://github.com/bell-sw/Liberica/releases/download/8u352+8/bellsoft-jdk8u352+8-linux-aarch64.tar.gz -O
shasum -a 256 bellsoft-jdk8u352+8-linux-aarch64.tar.gz

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully, this post and the small updates I made to the &lt;code&gt;README.md&lt;/code&gt; will remind me next time. I should probably figure out a way to automate some of that. Maybe a CLI?&lt;/p&gt;

&lt;h2&gt;
  
  
  Create an application image
&lt;/h2&gt;

&lt;p&gt;Create a Spring Boot 3 application with &lt;code&gt;web&lt;/code&gt; and &lt;code&gt;actuator&lt;/code&gt; which is enough for a simple test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create a Spring Boot 3 application
curl https://start.spring.io/starter.tgz -d dependencies=web,actuator -d javaVersion=17 -d bootVersion=3.0.0-SNAPSHOT -d type=maven-project | tar -xzf -

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the pom.xml replace this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;build&amp;gt;
    &amp;lt;plugins&amp;gt;
        &amp;lt;plugin&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;
        &amp;lt;/plugin&amp;gt;
    &amp;lt;/plugins&amp;gt;
&amp;lt;/build&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;build&amp;gt;
    &amp;lt;plugins&amp;gt;
        &amp;lt;plugin&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;configuration&amp;gt;
                &amp;lt;image&amp;gt;
                    &amp;lt;builder&amp;gt;dashaun/java-native-builder-arm64:7.37.0&amp;lt;/builder&amp;gt;
                &amp;lt;/image&amp;gt;
            &amp;lt;/configuration&amp;gt;
        &amp;lt;/plugin&amp;gt;
    &amp;lt;/plugins&amp;gt;
&amp;lt;/build&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build an image using the image builder that we have created and configured.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./mvnw -Pnative spring-boot:build-image

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run and test the image
&lt;/h2&gt;

&lt;p&gt;Run the OCI image with &lt;code&gt;docker&lt;/code&gt; to start up the server. It should start quickly!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Forward the part, run in the background, but see the startup time
docker run -p 8080:8080 demo:0.0.1-SNAPSHOT &amp;amp;
# Check the endpoint to validate
http http :8080/actuator/health

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;Because I’m done, and moved &lt;a href="https://hub.docker.com/r/dashaun/java-native-builder-arm64"&gt;builder version 7.37.0 to prod&lt;/a&gt;, I also cleaned up my &lt;code&gt;terraform&lt;/code&gt; deployment.&lt;/p&gt;

&lt;p&gt;Another huge “Thanks” to &lt;a href="https://twitter.com/dmikusa"&gt;Daniel Mikusa&lt;/a&gt; for all of his help.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/r/dashaun/java-native-builder-arm64"&gt;dashaun/java-native-builder-arm64&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dashaun/paketo-arm64"&gt;dashaun/paketo-arm64&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dashaun/oci-arm64-gha-runner-terraform"&gt;dashaun/oci-arm64-gha-runner-terraform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dashaun.com/posts/springboot-arm64-image/"&gt;Related Post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>springboot</category>
      <category>buildpack</category>
      <category>arm64</category>
      <category>m1</category>
    </item>
    <item>
      <title>Spring Boot StackPath Terraform</title>
      <dc:creator>DaShaun</dc:creator>
      <pubDate>Tue, 25 Oct 2022 16:19:03 +0000</pubDate>
      <link>https://dev.to/dashaun/spring-boot-stackpath-terraform-2hak</link>
      <guid>https://dev.to/dashaun/spring-boot-stackpath-terraform-2hak</guid>
      <description>&lt;p&gt;This is another article based on recent &lt;a href="https://bit.ly/spring-office-hours"&gt;Spring Office Hours&lt;/a&gt; sessions. Spring Boot provides several effective ways to deliver applications, to production, efficiently. There are many situations where one of the &lt;code&gt;hyperscale&lt;/code&gt; cloud providers is not an option, or the best choice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dashaun.com/posts/spring-boot-kamatera-terraform/"&gt;Previously, I looked at Kamatera.&lt;/a&gt;This time, I’m going to use &lt;a href="https://stackpath.com"&gt;StackPath&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/kWVv0U1Bvq0"&gt;I did the work during a live stream, so you can see exactly how easy and exciting this was.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial Thoughts
&lt;/h2&gt;

&lt;p&gt;I figured that going down this path would get easier with each provider. So far that has been true. I’m learning more about Terraform and getting more comfortable. I’m able to map the different concepts and building blocks a little easier with each rep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting an account
&lt;/h2&gt;

&lt;p&gt;As you would expect, nothing out of the ordinary when trying to setup an account. I couldn’t find a free tier or discount code, but I didn’t look very hard.&lt;a href="https://dashaun.com"&gt;Reach out to me&lt;/a&gt; if you know of something that I can share. Billing info is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stackpath Terraform Provider
&lt;/h2&gt;

&lt;p&gt;Having a Terraform Provider is what I have set as the bare minimum for this exercise. The &lt;a href="https://registry.terraform.io/providers/stackpath/stackpath/latest/docs"&gt;StackPath Provider&lt;/a&gt; was surprising. I consider myself a slightly above average Terraform user. I have never experienced this as the &lt;code&gt;default&lt;/code&gt; behavior for a &lt;code&gt;Provider&lt;/code&gt; and I am impressed.&lt;/p&gt;

&lt;p&gt;The provider only required three arguments for configuration. I decided to use the environment variable approach rather than passing in variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STACKPATH_STACK_ID
STACKPATH_CLIENT_ID
STACKPATH_CLIENT_SECRET

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For the &lt;code&gt;STACKPATH_STACK_ID&lt;/code&gt; I used the &lt;code&gt;stack slug&lt;/code&gt; from the &lt;code&gt;DASHBOARD&lt;/code&gt;. I created the &lt;code&gt;STACKPATH_CLIENT_ID&lt;/code&gt; and &lt;code&gt;STACKPATH_CLIENT_SECRET&lt;/code&gt; from the &lt;code&gt;API ACCESS&lt;/code&gt; option of the dashboard.&lt;/p&gt;

&lt;p&gt;When I ran the &lt;code&gt;terraform plan&lt;/code&gt; and &lt;code&gt;terraform apply&lt;/code&gt; they were so fast I thought it was broken. I had guessed at the value to use for &lt;code&gt;STACKPATH_STACK_ID&lt;/code&gt; and figured that I must be doing something wrong. Nope. Their platform API defaults to an &lt;code&gt;async&lt;/code&gt; behavior that doesn’t wait for object creation to be completed. Instead, your actions complete, and you can run &lt;code&gt;terraform refresh&lt;/code&gt; to get the status of its creation.&lt;/p&gt;

&lt;p&gt;I’ve used other &lt;code&gt;Providers&lt;/code&gt; that provide this as an option. In this case, while I was learning and iterating frequently, it felt amazing.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://asciinema.org/a/JqexvsUYphyGVpSuEOADpfbnM?autoplay=1&amp;amp;amp%3BstartAt=03" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--jywtYaQQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://asciinema.org/a/JqexvsUYphyGVpSuEOADpfbnM.png" height="181" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://asciinema.org/a/JqexvsUYphyGVpSuEOADpfbnM?autoplay=1&amp;amp;amp%3BstartAt=03" rel="noopener noreferrer" class="c-link"&gt;
          Terraform Init, Terraform Apply via StackPath Provider - asciinema.org
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--XuZRMMKY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://asciinema.org/images/favicon-2d62dafa447cf018340b7121007568e3.png%3Fvsn%3Dd" width="32" height="32"&gt;
        asciinema.org
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;To check on the status I used &lt;code&gt;terraform refresh&lt;/code&gt; and in this mode, it felt like the right way to do things.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://asciinema.org/a/jUlDDHoeox4SXBpfFHzPPPD37?autoplay=1" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PFo8p0j4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://asciinema.org/a/jUlDDHoeox4SXBpfFHzPPPD37.png" height="181" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://asciinema.org/a/jUlDDHoeox4SXBpfFHzPPPD37?autoplay=1" rel="noopener noreferrer" class="c-link"&gt;
          Terraform Refresh via StackPath Provider - asciinema.org
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--XuZRMMKY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://asciinema.org/images/favicon-2d62dafa447cf018340b7121007568e3.png%3Fvsn%3Dd" width="32" height="32"&gt;
        asciinema.org
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Accessing the service felt snappy.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://asciinema.org/a/LHmJDSfJXSG9WTRDOXoYtDBc9?autoplay=1&amp;amp;amp%3BstartAt=2" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Yw3lkH2z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://asciinema.org/a/LHmJDSfJXSG9WTRDOXoYtDBc9.png" height="181" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://asciinema.org/a/LHmJDSfJXSG9WTRDOXoYtDBc9?autoplay=1&amp;amp;amp%3BstartAt=2" rel="noopener noreferrer" class="c-link"&gt;
          Using Curl to Validate Workload deployed to StackPath - asciinema.org
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--XuZRMMKY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://asciinema.org/images/favicon-2d62dafa447cf018340b7121007568e3.png%3Fvsn%3Dd" width="32" height="32"&gt;
        asciinema.org
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Cleaning up, was just as fast, so iterating through the struggles was relatively painless.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://asciinema.org/a/dK1ARCkLHZNp2UQaPozfFgNo0" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ugYM1h3I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://asciinema.org/a/dK1ARCkLHZNp2UQaPozfFgNo0.png" height="181" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://asciinema.org/a/dK1ARCkLHZNp2UQaPozfFgNo0" rel="noopener noreferrer" class="c-link"&gt;
          Terraform Destroy via StackPath Provider - asciinema.org
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--XuZRMMKY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://asciinema.org/images/favicon-2d62dafa447cf018340b7121007568e3.png%3Fvsn%3Dd" width="32" height="32"&gt;
        asciinema.org
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Struggle
&lt;/h2&gt;

&lt;p&gt;I spent a bunch of time not realizing that I needed the &lt;code&gt;stackpath_compute_network_policy&lt;/code&gt; to allow public traffic. On this platform, ports are not exposed to the public by default. Even though I struggled, this made me feel a little more secure. Simply because I am forced to be specific about what I’m allowing. Additionally, the container doesn’t have remote access enabled by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Differences
&lt;/h2&gt;

&lt;p&gt;Deploying a VM that can run Docker is one thing. Deploying a &lt;code&gt;container&lt;/code&gt; to a &lt;code&gt;platform&lt;/code&gt; is a different pattern. While I was wondering through the documentation, I was very interested. There are some very advanced and mature capabilities available. This is clearly a platform that is designed to support short-lived and very dynamic workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I only scratched the service here, but it worked, and it worked quickly. There are some very interesting architectures that can be accomplished with &lt;code&gt;StackPath&lt;/code&gt; and I’m excited to go further. I didn’t know what to expect on this journey. I can say that &lt;code&gt;StackPath&lt;/code&gt; his raised the bar for my expectations going forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Turn
&lt;/h2&gt;

&lt;p&gt;Take the &lt;a href="https://github.com/dashaun/spring-boot-stackpath-terraform"&gt;repository&lt;/a&gt; for a spin and try it out for yourself. Let me know what you think.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/dashaun/spring-boot-stackpath-terraform"&gt;https://github.com/dashaun/spring-boot-stackpath-terraform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/kWVv0U1Bvq0"&gt;YouTube Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitch.tv/javagrunt"&gt;Javagrunt on Twitch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Spring Boot Kamatera Terraform</title>
      <dc:creator>DaShaun</dc:creator>
      <pubDate>Mon, 24 Oct 2022 16:19:03 +0000</pubDate>
      <link>https://dev.to/dashaun/spring-boot-kamatera-terraform-2of5</link>
      <guid>https://dev.to/dashaun/spring-boot-kamatera-terraform-2of5</guid>
      <description>&lt;p&gt;Recently, during the &lt;a href="https://bit.ly/spring-office-hours"&gt;Spring Office Hours&lt;/a&gt;, we have been discussing &lt;code&gt;Spring to Production&lt;/code&gt; as a topic. There are so many ways to get Spring Boot application to production. If your Spring Boot application is delivered as a container, all you really need is a Docker or Kubernetes dial tone.&lt;/p&gt;

&lt;p&gt;In this post, I’m starting from nothing, and delivering a Spring Boot application to &lt;a href="https://kamatera.com"&gt;Kamatera&lt;/a&gt;. I’ve never used Kamatera before this, so I’m going document the entire process, and experience, for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting an account
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://kamatera.com"&gt;Kamatera&lt;/a&gt; provides a &lt;code&gt;30-Day Free Trial&lt;/code&gt; which sounds wonderful! After validating my email address, I was required to add a billing profile. This makes sense. However, before signing up for the free trial, I did verify that there was a &lt;a href="https://registry.terraform.io/providers/Kamatera/kamatera/latest/docs"&gt;Terraform provider for Kamatera&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While I was adding my billing profile, I saw more details of the 30-Day free trial.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;30 days Free Usage:
1 Cloud Server (of up to 100 USD)
1000 GB Cloud Block Storage
1000 GB Outgoing Internet Traffic

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is plenty to work with, so I continued to proceed. The only option I had was to use a credit card. The process was pretty painless and only took a couple of minutes.&lt;/p&gt;

&lt;p&gt;The UI is easy to understand and navigate. I just don’t want to use the UI. I want to automate all the things. Now that my account is set up, I want to set up my infrastructure as code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kamatera Terraform Provider
&lt;/h2&gt;

&lt;p&gt;A quick glance at the &lt;a href="https://github.com/Kamatera/terraform-provider-kamatera/blob/master/README.md#usage-guide"&gt;Terraform Provider for Kamatera usage guide&lt;/a&gt;and I see that I need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KAMATERA_API_CLIENT_ID
KAMATERA_API_SECRET

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;a href="https://console.kamatera.com"&gt;Kamatera console&lt;/a&gt; I easily found where I needed to go &lt;a href="https://console.kamatera.com/keys"&gt;to add keys&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I clicked the &lt;code&gt;+ Create New Key&lt;/code&gt; button. A &lt;code&gt;description&lt;/code&gt; box is presented. I put &lt;code&gt;Spring Boot to Production with Kamatera&lt;/code&gt; in the description and clicked &lt;code&gt;Create Key&lt;/code&gt; to move forward. At that point, I am provided with my &lt;code&gt;Client ID&lt;/code&gt; and &lt;code&gt;API Secret&lt;/code&gt; which I then copy to a safe place.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/Kamatera/terraform-provider-kamatera/blob/master/README.md#usage-guide"&gt;Terraform Provider for Kamatera usage guide&lt;/a&gt; also provided an example Terraform file. I copied that and separated their &lt;code&gt;main.tf&lt;/code&gt; into different files, that makes things easier for me to understand later. I started a &lt;a href="https://github.com/dashaun/spring-boot-kamatera-terraform"&gt;github repository&lt;/a&gt; to capture my changes.&lt;/p&gt;

&lt;p&gt;At this point, I determined that I couldn’t configure Docker as an option via Terraform using one of their images. They have a tool that generates Terraform files, but the image ID never worked for me. I didn’t spend much time investigating, probably user error.&lt;/p&gt;

&lt;p&gt;That is ok, because I can use an executable JAR and deploy that as a service. Or I can just install Docker as part of the startup scripts.&lt;/p&gt;

&lt;p&gt;I chose to use &lt;code&gt;Ubuntu&lt;/code&gt; and their &lt;code&gt;22.04 64bit_optimized&lt;/code&gt; image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker
&lt;/h2&gt;

&lt;p&gt;I attempted to install Docker using the &lt;code&gt;startup_script&lt;/code&gt; value of the &lt;code&gt;kamatera_server&lt;/code&gt; but I struggled with getting that to work consistently. The problem appeared to be timing. I’m still unsure about when the startup script gets executed. I needed to wait for the network, then wait for DNS, and sometimes it would just fail. I couldn’t figure out a way to access the logs during the build process either. At one point, a server appeared to have been built and completed successfully, but the startup script was stuck in a loop, waiting for something. I couldn’t access the server though, and my Terraform was stuck, for 15+ minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interesting Side Note Regarding The Stuck Server
&lt;/h2&gt;

&lt;p&gt;I opened a ticket, asking for the server to be destroyed, for two reasons. When I cancelled the stuck Terraform &lt;code&gt;apply&lt;/code&gt; my local state didn’t show the server, so I couldn’t Terraform &lt;code&gt;destroy&lt;/code&gt; it. In the Kamatera console, the task was showing completed, but the server didn’t show up in my server list, so I couldn’t delete it from there either.&lt;/p&gt;

&lt;p&gt;The response was quick, less than 30 minutes, but confusing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Unfortunately, we do not provide support for Terraform.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/Kamatera/terraform-provider-kamatera"&gt;Terraform Provider&lt;/a&gt; that I’m using, appears to be created by &lt;code&gt;Kamatera&lt;/code&gt; and shows up in the &lt;a href="https://registry.terraform.io/providers/Kamatera/kamatera/latest"&gt;Terraform Registry&lt;/a&gt;. Therefore, I can only assume that the 30-day support is not going to troubleshoot Terraform related issues.&lt;/p&gt;

&lt;p&gt;I later realized that every server creation and destroy sends out an email receipt. I did not get a receipt for the server creation, so maybe, hopefully, their system cleaned it up properly, automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker via remote-exec
&lt;/h2&gt;

&lt;p&gt;I don’t recommend this approach. Nobody recommends this approach. The Terraform documentation states &lt;a href="https://developer.hashicorp.com/terraform/language/resources/provisioners/remote-exec"&gt;Use provisioners as a last resort.&lt;/a&gt;It’s marked &lt;code&gt;Important&lt;/code&gt; and highlighted at the top of the page.&lt;/p&gt;

&lt;p&gt;Well, it is my last resort. The purpose of this exercise was to show that getting Spring to production is doable, and Spring Boot makes it really easy. Different providers are going to have different pain points, but also, different strengths.&lt;/p&gt;

&lt;p&gt;At this point, I use the &lt;code&gt;remote-exec&lt;/code&gt; provisioner to do a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download the &lt;code&gt;Docker&lt;/code&gt; install script via &lt;code&gt;curl&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Execute the install script&lt;/li&gt;
&lt;li&gt;Pull down the &lt;a href="https://hub.docker.com/r/dashaun/spring-boot-native-pi-default"&gt;image&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Run the &lt;a href="https://hub.docker.com/r/dashaun/spring-boot-native-pi-default"&gt;image&lt;/a&gt; on &lt;code&gt;Docker&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using &lt;code&gt;remote-exec&lt;/code&gt; required setting up a &lt;code&gt;connection&lt;/code&gt; to the host. For this example, I chose to use a public/private key pair for access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Execute
&lt;/h2&gt;

&lt;p&gt;In order to take this for a spin yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#clone the repository
git clone https://github.com/dashaun/spring-boot-kamatera-terraform
cd spring-boot-kamatera-terraform
# configure Terraform with your credentials
export KAMATERA_API_CLIENT=...
export KAMATERA_API_SECRET=...
export TF_VAR_ssh_public_key="$(cat ~/.ssh/id_rsa.pub)"
export TF_VAR_ssh_private_key="$(cat ~/.ssh/id_rsa)"
# Initialize Terraform to pull down the provider
terraform init
# Validate your credentials config by using the plan
terraform plan
# Apply the Terraform, ETC &amp;lt; 5min
terraform apply -auto-approve
# Access the Spring Boot application using the newly created server
curl $(terraform output -raw public_ips):8080/actuator/health | jq .

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you are done, clean up behind yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Destroy the Terraform, ETC &amp;lt; 1min
terraform destroy -auto-approve

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;While exploring multi-cloud architectures, I really wanted to get outside my comfort zone. Things like &lt;code&gt;Terraform&lt;/code&gt; and &lt;code&gt;Spring Boot&lt;/code&gt; make getting applications up and available really simple. I am going to continue to explore and experiment with other cloud providers. Soon, I will deploy a reference architecture, with different Spring Boot services, each deployed to different cloud providers. My theory is that you don’t have to be a certified Azure|GCP|AWS cloud architect to be productive with Spring Boot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;I did not harden this deployment, and I wouldn’t call it production ready. If you would like to see me expand and harden this example, please let me know, via the &lt;a href="https://github.com/dashaun/spring-boot-kamatera-terraform"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
