diff --git a/native-image/spring-boot-webserver/README.md b/native-image/spring-boot-webserver/README.md
index 2033908..9003311 100644
--- a/native-image/spring-boot-webserver/README.md
+++ b/native-image/spring-boot-webserver/README.md
@@ -1,6 +1,6 @@
# Multicloud Apps with GraalVM - Up and Running
-This workshop is for developers looking to understand how to **build size-optimized cloud native Java applications** using [GraalVM Native Image](https://www.graalvm.org/jdk21/reference-manual/native-image/).
+This workshop is for developers looking to understand how to **build size-optimized cloud native Java applications** using [GraalVM Native Image](https://www.graalvm.org/jdk23/reference-manual/native-image/).
In this workshop, you will discover ways to minimize application footprint using different Native Image linking options and packaging into various base containers. You will run a Spring Boot web server application hosting the GraalVM documentation website.
@@ -24,7 +24,6 @@ In this workshop you will:
* `musl` toolchain
* Container runtime such as [Rancher Desktop](https://docs.rancherdesktop.io/getting-started/installation/) or [Docker](https://www.docker.com/gettingstarted/) installed and running
* [GraalVM for JDK 23](https://www.graalvm.org/downloads/) or later. We recommend using [SDKMAN!](https://sdkman.io/). (For other download options, see [GraalVM Downloads](https://www.graalvm.org/downloads/).)
-
```bash
sdk install java 23-graal
```
@@ -133,67 +132,7 @@ The `ENTRYPOINT` for the application would be `java` from the custom runtime.
```
Jlink shrank the container by **46MB**.
-## **STEP 3**: Build and Run a Native Image Inside a Container Using Paketo Buildpacks
-
-In this step, you will compile this Spring Boot application ahead of time with GraalVM Native Image and run it using Paketo Buildpacks container images.
-
-### Explanation
-
-Spring Boot supports building a native image in a container using the [Paketo Buildpack for Oracle](https://github.com/paketo-buildpacks/oracle) which provides Oracle GraalVM Native Image.
-
-The Paketo builder pulls the [Jammy Tiny Stack image](https://github.com/paketo-buildpacks/builder-jammy-tiny) (Ubuntu distroless-like image) which contains no buildpacks.
-Then you point the **builder** image to the **creator** image.
-For this workshop, you point to the [Paketo Buildpack for Oracle](https://github.com/paketo-buildpacks/oracle) explicitly requesting the Native Image tool.
-
-If you open the _pom.xml_ file, you see the `spring-boot-maven-plugin` declaration added for you:
-```xml
-
-
- paketobuildpacks/builder-jammy-buildpackless-tiny
-
- paketobuildpacks/oracle
- paketobuildpacks/java-native-image
-
-
-
-```
-When `java-native-image` is requested, the buildpack downloads Oracle GraalVM, which includes Native Image.
-The [Paketo documentation provides several examples](https://paketo.io/docs/howto/java/#build-an-app-as-a-graalvm-native-image-application) that show you how to build applications with Native Image using buildpacks.
-
-> Note that if you do not specify Oracle's buildpack, it will pull the default buildpack, which can result in reduced performance.
-
-### Action
-
-1. Build a native executable for this Spring application using the Paketo buildpack:
- ```bash
- ./mvnw -Pnative spring-boot:build-image
- ```
-
-2. Once the build completes, a container image _0.0.1-SNAPSHOT_ should be available. Run it, mapping the ports:
- ```bash
- docker run --rm -p8080:8080 docker.io/library/webserver:0.0.1-SNAPSHOT
- ```
-
- The application is running from the native image inside a container. The container started in just **0.031 seconds**!
-
-3. Open a browser and navigate to [localhost:8080/](http://localhost:8080/). You see the GraalVM documentation pages served.
-
-4. Return to the terminal and stop the running container by clicking CTRL+C.
-
-5. Check the size of this container image:
- ```bash
- docker images
- ```
- The expected output is:
- ```
- REPOSITORY TAG IMAGE ID CREATED SIZE
- webserver distroless-java-base.jlink 687f7683ad58 31 minutes ago 192MB
- webserver debian-slim.jar 5c69f06a3972 2 hours ago 238MB
- webserver 0.0.1-SNAPSHOT 0660806da4a2 44 years ago 163MB
- ```
- The new container, tagged as _0.0.1-SNAPSHOT_, is much smaller now **163MB**.
-
-## **STEP 4**: Build a Native Image Locally and Run Inside a Container (Default Configuration)
+## **STEP 3**: Build a Native Image Locally and Run Inside a Container (Default Configuration)
In this step, you will create a native image with the default configuration on a host machine, and only run it inside a container.
@@ -256,7 +195,7 @@ Learn more in ["Distroless" Container Images](https://github.com/GoogleContainer
The expected size is **125M**.
Note that the static resources are "baked" into this native executable and added 44M to its size.
-## **STEP 5**: Build a Size-Optimized Native Image Locally and Run Inside a Container
+## **STEP 4**: Build a Size-Optimized Native Image Locally and Run Inside a Container
_This is where the fun begins._
@@ -342,7 +281,7 @@ The script _build-dynamic-image.sh_, available in this repository for your conve
The size decreased from **125M** (`webserver`) to **92M** (`webserver.dynamic-optimized`) by applying the file size optimization.
-## **STEP 6**: Build a Size-Optimized Mostly Static Native Image Locally and Run Inside a Container
+## **STEP 5**: Build a Size-Optimized Mostly Static Native Image Locally and Run Inside a Container
In this step, you will build a **mostly static** native image, with the file size optimization on, on a host machine, then package it into a container image that provides `glibc`, and run.
@@ -428,7 +367,7 @@ A separate Maven profile exists for this step:
The size of the mostly static native image (`webserver.mostly-static`) has not changed much, and is around **93MB**.
-## **STEP 7**: Build a Size-Optimized Fully Static Native Image Locally and Run Inside a Container
+## **STEP 6**: Build a Size-Optimized Fully Static Native Image Locally and Run Inside a Container
In this step, you will build a **fully static** native image, with the file size optimization on, on a host machine, then package it into a _scratch_ container.
@@ -528,7 +467,7 @@ A separate Maven profile exists for this step:
The size of the mostly static native image (`webserver.static`) has not changed, and is around **93MB**.
-## **STEP 8**: Compress a Static Native Image with UPX and Run Inside a Container
+## **STEP 7**: Compress a Static Native Image with UPX and Run Inside a Container
_What can you do next to reduce the size even more?_
@@ -594,7 +533,70 @@ It can significantly reduce the executable size, but note, that UPX loads the ex
The container size reduced dramatically to just **36.2MB**.
The application and container image's size have been shrunk to the minimum.
-## **STEP 9**: Clean up (Optional)
+## **STEP 8**: (Optional) Build and Run a Native Image Inside a Container Using Paketo Buildpacks
+
+You can also compile this Spring Boot application ahead of time with GraalVM Native Image and run it using Paketo Buildpacks container images.
+
+> Prerequisite: [GraalVM for JDK 21](https://www.graalvm.org/downloads/). We recommend using [SDKMAN!](https://sdkman.io/). (For other download options, see [GraalVM Downloads](https://www.graalvm.org/downloads/).)
+ ```bash
+ sdk install java 21-graal
+ ```
+
+### Explanation
+
+Spring Boot supports building a native image in a container using the [Paketo Buildpack for Oracle](https://github.com/paketo-buildpacks/oracle) which provides Oracle GraalVM Native Image.
+
+The Paketo builder pulls the [Jammy Tiny Stack image](https://github.com/paketo-buildpacks/builder-jammy-tiny) (Ubuntu distroless-like image) which contains no buildpacks.
+Then you point the **builder** image to the **creator** image.
+For this workshop, you point to the [Paketo Buildpack for Oracle](https://github.com/paketo-buildpacks/oracle), explicitly requesting the Native Image tool.
+
+If you open the _pom.xml_ file, you see the `spring-boot-maven-plugin` declaration added for you:
+```xml
+
+
+ paketobuildpacks/builder-jammy-buildpackless-tiny
+
+ paketobuildpacks/oracle
+ paketobuildpacks/java-native-image
+
+
+
+```
+When `java-native-image` is requested, the buildpack downloads Oracle GraalVM, which includes Native Image.
+The [Paketo documentation provides several examples](https://paketo.io/docs/howto/java/#build-an-app-as-a-graalvm-native-image-application) that show you how to build applications with Native Image using buildpacks.
+
+> Note that if you do not specify Oracle's buildpack, it will pull the default buildpack, which can result in reduced performance.
+
+### Action
+
+1. Build a native executable for this Spring application using the Paketo buildpack:
+ ```bash
+ ./mvnw -Pnative spring-boot:build-image
+ ```
+
+2. Once the build completes, a container image _0.0.1-SNAPSHOT_ should be available. Run it, mapping the ports:
+ ```bash
+ docker run --rm -p8080:8080 docker.io/library/webserver:0.0.1-SNAPSHOT
+ ```
+
+ The application is running from the native image inside a container. The container started in **0.031 seconds**.
+
+3. Open a browser and navigate to [localhost:8080/](http://localhost:8080/). You see the GraalVM documentation pages served.
+
+4. Return to the terminal and stop the running container by clicking CTRL+C.
+
+5. Check the size of this container image:
+ ```bash
+ docker images
+ ```
+ The expected output is:
+ ```
+ REPOSITORY TAG IMAGE ID CREATED SIZE
+ webserver 0.0.1-SNAPSHOT 0660806da4a2 44 years ago 163MB
+ ```
+ The new container, tagged as _0.0.1-SNAPSHOT_, is **163MB**.
+
+## **STEP 9**: (Optional) Clean up
To clean up all images, run the `./clean.sh` script provided for that purpose.