From 6bfdf6786d48ff5c3f88c06d4f7a0b017267a038 Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Thu, 10 Oct 2024 13:47:36 +0300 Subject: [PATCH] Make step buiding with Paketo Buildpacks optional and requiring GraalVM for JDK 21 --- native-image/spring-boot-webserver/README.md | 138 ++++++++++--------- 1 file changed, 70 insertions(+), 68 deletions(-) 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.