Skip to content

Commit

Permalink
Make step buiding with Paketo Buildpacks optional and requiring Graal…
Browse files Browse the repository at this point in the history
…VM for JDK 21
  • Loading branch information
olyagpl authored and krisfoster committed Oct 11, 2024
1 parent da3b9fe commit 9e59e90
Showing 1 changed file with 70 additions and 68 deletions.
138 changes: 70 additions & 68 deletions native-image/spring-boot-webserver/README.md
Original file line number Diff line number Diff line change
@@ -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.

Expand All @@ -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
```
Expand Down Expand Up @@ -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
<configuration>
<image>
<builder>paketobuildpacks/builder-jammy-buildpackless-tiny</builder>
<buildpacks>
<buildpack>paketobuildpacks/oracle</buildpack>
<buildpack>paketobuildpacks/java-native-image</buildpack>
</buildpacks>
</image>
</configuration>
```
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.

Expand Down Expand Up @@ -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._

Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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?_
Expand Down Expand Up @@ -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
<configuration>
<image>
<builder>paketobuildpacks/builder-jammy-buildpackless-tiny</builder>
<buildpacks>
<buildpack>paketobuildpacks/oracle</buildpack>
<buildpack>paketobuildpacks/java-native-image</buildpack>
</buildpacks>
</image>
</configuration>
```
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.
Expand Down

0 comments on commit 9e59e90

Please sign in to comment.