Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
6d6bd58
add InstantOn instruction
gkwan-ibm Nov 14, 2024
0401679
add InstantOn instruction
gkwan-ibm Nov 14, 2024
294fd3a
add InstantOn instruction
gkwan-ibm Nov 14, 2024
68e5801
add InstantOn instruction
gkwan-ibm Nov 14, 2024
7cd5048
add InstantOn instruction
gkwan-ibm Nov 15, 2024
4ef0168
add InstantOn instruction
gkwan-ibm Nov 15, 2024
45e71c9
add InstantOn instruction
gkwan-ibm Nov 15, 2024
ce65160
add InstantOn instruction
gkwan-ibm Nov 15, 2024
327d638
add InstantOn instruction
gkwan-ibm Nov 15, 2024
2494e4f
add InstantOn instruction
gkwan-ibm Nov 15, 2024
e870137
add InstantOn instruction
gkwan-ibm Nov 15, 2024
5c54bb1
Update testApp.sh
gkwan-ibm Nov 15, 2024
d70e079
Update testApp.sh
gkwan-ibm Nov 15, 2024
6081e69
Merge pull request #200 from OpenLiberty/gkwan-ibm-InstantOn-test
gkwan-ibm Nov 19, 2024
1b3c129
Update README.adoc
gkwan-ibm Nov 21, 2024
032cc83
address SME review (#201)
gkwan-ibm Nov 22, 2024
7a38931
Update test.yml
gkwan-ibm Nov 22, 2024
c47d3f1
Update README.adoc
gkwan-ibm Dec 3, 2024
8e33b73
Update README.adoc
gkwan-ibm Dec 3, 2024
4653066
address sme comment
gkwan-ibm Dec 3, 2024
964cf35
address sme comment
gkwan-ibm Dec 3, 2024
201d06c
Update README.adoc
gkwan-ibm Dec 3, 2024
42735a9
Update README.adoc
gkwan-ibm Dec 3, 2024
7fb9f4c
Update README.adoc
gkwan-ibm Dec 3, 2024
c98540a
Update README.adoc
gkwan-ibm Dec 3, 2024
e82288b
address sme comment
gkwan-ibm Dec 3, 2024
0a0dabb
address sme comment
gkwan-ibm Dec 3, 2024
6c30691
Update README.adoc
gkwan-ibm Dec 4, 2024
6155a13
Update README.adoc
gkwan-ibm Dec 4, 2024
885103d
Update README.adoc
gkwan-ibm Dec 4, 2024
117e559
Update README.adoc
gkwan-ibm Dec 4, 2024
77b5267
Update README.adoc
gkwan-ibm Dec 4, 2024
64ca07e
address final content review
gkwan-ibm Dec 4, 2024
009a32f
Merge branch 'staging' into gkwan-ibm-InstantOn
gkwan-ibm Dec 4, 2024
45763d6
Update Dockerfile
gkwan-ibm Jan 6, 2025
8caeecd
Update Dockerfile
gkwan-ibm Jan 6, 2025
0f60379
address final content review
gkwan-ibm Jan 6, 2025
dbcd15e
Update test.yml
gkwan-ibm Jan 6, 2025
8c09055
Update README.adoc
gkwan-ibm Jan 6, 2025
bc6b6a3
Merge branch 'staging' into gkwan-ibm-InstantOn
gkwan-ibm Jan 7, 2025
2c9ea07
Update README.adoc
gkwan-ibm Jan 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
distribution: 'semeru'
java-version: 17
java-version: 21
- run: unset _JAVA_OPTIONS
- name: Run tests
run: sudo -E ../scripts/testApp.sh
Expand Down
158 changes: 147 additions & 11 deletions README.adoc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2019, 2023 IBM Corporation and others.
// Copyright (c) 2019, 2024 IBM Corporation and others.
// Licensed under Creative Commons Attribution-NoDerivatives
// 4.0 International (CC BY-ND 4.0)
// https://creativecommons.org/licenses/by-nd/4.0/
Expand All @@ -10,9 +10,9 @@
:projectid: spring-boot
:page-duration: 20 minutes
:page-releasedate: 2019-11-04
:page-majorupdateddate: 2023-11-15
:page-majorupdateddate: 2024-12-02
:page-description: Learn how to containerize, package, and run a Spring Boot application on Open Liberty.
:page-tags: ['Docker']
:page-tags: ['docker']
:page-related-guides: ['rest-intro', 'containerize']
:page-permalink: /guides/{projectid}
:common-includes: https://raw.githubusercontent.com/OpenLiberty/guides-common/prod
Expand All @@ -29,7 +29,7 @@ Learn how to containerize, package, and run a Spring Boot application on Open Li

== What you'll learn

The starting point of this guide is the finished application from the https://spring.io/guides/gs/spring-boot/[Building an Application with Spring Boot^] guide. If you are not familiar with Spring Boot, complete that guide first. Java 17 is required to run this project.
The starting point of this guide is the finished application from the https://spring.io/guides/gs/spring-boot/[Building an Application with Spring Boot^] guide. If you are not familiar with Spring Boot, complete that guide first. Java 21 is required to run this project.

You will learn how to use the `springBootUtility` command to deploy a Spring Boot application in Docker on Open Liberty without modification. This command stores the dependent library JAR files of the application to the target library cache, and packages the remaining application artifacts into a thin application JAR file.

Expand Down Expand Up @@ -124,7 +124,7 @@ Navigate to the `start` directory.
----

Dockerfile
[source, Text, linenums, role='code_column']
[source, Text, linenums, role='code_column']
----
include::finish/Dockerfile[]
----
Expand Down Expand Up @@ -155,13 +155,13 @@ Your `springboot` image appears in the list of Docker images:
[role='no_copy']
```
REPOSITORY TAG IMAGE ID CREATED SIZE
springboot latest d3ffdaa81854 27 seconds ago 596MB
springboot latest 3a5492c0cbeb 27 seconds ago 485MB
```

Now, you can run the Spring Boot application in a Docker container:
[role='command']
```
docker run -d --name springBootContainer -p 9080:9080 -p 9443:9443 springboot
docker run -d --name springBootContainer --rm -p 9080:9080 -p 9443:9443 springboot
```

Before you access your application from the browser, run the `docker ps` command to make sure that your container is running:
Expand All @@ -175,7 +175,7 @@ You see an entry similar to the following example:
[role='no_copy']
----
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e33532aa07d6 springboot "/opt/ibm/docker/doc…" 7 seconds ago Up 2 seconds 0.0.0.0:9080->9080/tcp, 0.0.0.0:9443->9443/tcp springBootContainer
e33532aa07d6 springboot "/opt/ol/helpers/run…" 7 seconds ago Up 2 seconds 0.0.0.0:9080->9080/tcp, 0.0.0.0:9443->9443/tcp springBootContainer
----

You can watch the application start by monitoring the logs:
Expand All @@ -184,6 +184,16 @@ You can watch the application start by monitoring the logs:
docker logs springBootContainer
```

Wait for the following message, which indicates that Liberty’s startup is complete in several seconds:
[role='no_copy']
----
...
CWWKZ0001I: Application thin-guide-spring-boot-0.1.0 started in 5.542 seconds.
...
CWWKF0011I: The defaultServer server is ready to run a smarter planet.
The defaultServer server started in 7.121 seconds.
----

// Static guide instruction
ifndef::cloud-hosted[]
After the application starts, go to the http://localhost:9080/hello[^] URL to access the application.
Expand All @@ -198,16 +208,142 @@ curl http://localhost:9080/hello
```
endif::[]

=== Tearing down the Docker container
After you are finished checking out the application, stop your container by running the following command:

[role='command']
```
docker stop springBootContainer
```

ifndef::cloud-hosted[]
== Faster starting up the container with InstantOn - Optional

Open Liberty InstantOn provides fast startup times for MicroProfile and Jakarta EE applications. In this section, you’ll learn how to build an InstantOn image that provides fast startup times. Your application can start in milliseconds, without compromising on throughput, memory, development-production parity, or Java language features.

To stop and remove your container, run the following commands:
If you are working on a Linux system with kernel version 5.9 or greater, you can continue with this section; otherwise, go to the <<running-the-application-on-open-liberty>> section. You can run the following command to check out the kernel version of your system:

[role='command']
```
uname -r
```

The https://openliberty.io/docs/latest/reference/feature/crac.html[Coordinated Restore at Checkpoint^] (`crac`) feature enables applications to use Liberty’s implementation of the https://javadoc.io/doc/org.crac/crac/1.4.0/index.html[org.crac^] APIs. The Spring Framework hooks into the checkpoint and restore when the `org.crac` APIs are enabled.

[role="code_command hotspot file=0", subs="quotes"]
----
#Replace the `Dockerfile` in the `start` directory.#
`Dockerfile`
----

Dockerfile
[source, Text, linenums, role='code_column']
----
include::instantOn/Dockerfile[]
----

crac.xml
[source, xml, linenums, role='code_column']
----
include::finish/src/main/liberty/instantOn/crac.xml[]
----

To enable the `crac` feature, add the [hotspot=cracXml file=0]`COPY` command that copies the provided `crac.xml` configuration file to the Liberty `configDropins` configuration directory. The crac.xml file enables the [hotspot=crac file=1]`crac` feature to the Liberty instance.

Run the following command to rebuild the Docker image:
[role='command']
```
docker build -t springboot .
```

To take a checkpoint of the application process with the `afterAppStart` option, run the following command:

[role='command']
```
docker run \
--name springBootCheckpointContainer \
--privileged \
--env WLP_CHECKPOINT=afterAppStart \
springboot
```

When the application process checkpoint completes, the `springBootCheckpointContainer` application container is stopped and exits. The stopped `springBootCheckpointContainer` container contains the data from the InstantOn checkpoint process. To take this checkpoint process data and commit it to an application container image layer, run the following commands:

[role='command']
```
docker commit springBootCheckpointContainer springboot-instanton
docker rm springBootCheckpointContainer
```

The stopped `springBootCheckpointContainer` container is no longer needed and can safely be removed.

To verify that the InstantOn image is built, run the `docker images` command to list all local Docker images:

[role='command']
```
docker images
```

Your `springboot-instanton` image appears in the list of Docker images. It shows a faster startup time than the original `springboot` image.

[role='no_copy']
```
REPOSITORY TAG IMAGE ID CREATED SIZE
springboot-instanton latest c4aabcdd64bf 20 seconds ago 577MB
springboot latest 3a5492c0cbeb 14 minutes ago 485MB
```

Run the `springboot-instanton` InstantOn application image by the following command:

[role='command']
```
docker run \
--rm -d \
--name springBootContainer \
--cap-add=CHECKPOINT_RESTORE \
--cap-add=SETPCAP \
--security-opt seccomp=unconfined \
-p 9080:9080 \
springboot-instanton
```

Run the following command to see the container logs:

[role='command']
```
docker logs springBootContainer
```

You see more logs from Spring for restoring. Liberty’s startup is complete in less than a second:

[role='no_copy']
----
2024-11-22T16:33:43.349Z INFO 1027 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Restarting Spring-managed lifecycle beans after JVM restore
...
2024-11-22T16:33:43.562Z INFO 1027 --- [ecutor-thread-1] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 135784 ms
2024-11-22T16:33:43.568Z INFO 1027 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Spring-managed lifecycle restart completed (restored JVM running for 525 ms)
...
CWWKZ0001I: Application thin-guide-spring-boot-0.1.0 started in 0.585 seconds.
...
CWWKF0011I: The defaultServer server is ready to run a smarter planet.
The defaultServer server started in 0.323 seconds.
----

Go to the http://localhost:9080/hello[^] URL to access the application.

After you are finished checking out the application, stop your container by running the following command:

[role='command']
```
docker stop springBootContainer
docker rm springBootContainer
```

If you use Podman instead of Docker, you can build your InstantOn image in a simplified way. Read the https://openliberty.io/docs/latest/instanton.html#checkpoint_script[Building the InstantOn image with Podman and the checkpoint.sh script^] documentation.

To learn more about the Liberty InstantOn feature, see the https://openliberty.io/docs/latest/instanton.html[Faster startup for containerized applications with Open Liberty InstantOn^] documentation.

endif::[]


== Running the application on Open Liberty

Next, you will run the Spring Boot application locally on Open Liberty by updating the `pom.xml` file.
Expand Down
4 changes: 2 additions & 2 deletions finish/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Stage and thin the application
# tag::OLimage1[]
FROM icr.io/appcafe/open-liberty:full-java17-openj9-ubi as staging
FROM icr.io/appcafe/open-liberty:full-java21-openj9-ubi-minimal as staging
# end::OLimage1[]

# tag::copyJar[]
Expand All @@ -17,7 +17,7 @@ RUN springBootUtility thin \

# Build the image
# tag::OLimage2[]
FROM icr.io/appcafe/open-liberty:kernel-slim-java17-openj9-ubi
FROM icr.io/appcafe/open-liberty:kernel-slim-java21-openj9-ubi-minimal
# end::OLimage2[]

ARG VERSION=1.0
Expand Down
2 changes: 1 addition & 1 deletion finish/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<description>Demo project for Spring Boot</description>

<properties>
<java.version>17</java.version>
<java.version>21</java.version>
</properties>

<dependencies>
Expand Down
10 changes: 10 additions & 0 deletions finish/src/main/liberty/instantOn/crac.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<server description="Enable the org.crac API">

<featureManager>
<!-- tag::crac[] -->
<feature>crac-1.4</feature>
<!-- end::crac[] -->
</featureManager>

</server>
58 changes: 58 additions & 0 deletions instantOn/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Stage and thin the application
# tag::OLimage1[]
FROM icr.io/appcafe/open-liberty:full-java21-openj9-ubi-minimal as staging
# end::OLimage1[]

# tag::copyJar[]
COPY --chown=1001:0 target/guide-spring-boot-0.1.0.jar \
/staging/fat-guide-spring-boot-0.1.0.jar
# end::copyJar[]

# tag::springBootUtility[]
RUN springBootUtility thin \
--sourceAppPath=/staging/fat-guide-spring-boot-0.1.0.jar \
--targetThinAppPath=/staging/thin-guide-spring-boot-0.1.0.jar \
--targetLibCachePath=/staging/lib.index.cache
# end::springBootUtility[]

# Build the image
# tag::OLimage2[]
FROM icr.io/appcafe/open-liberty:kernel-slim-java21-openj9-ubi-minimal
# end::OLimage2[]

ARG VERSION=1.0
ARG REVISION=SNAPSHOT

LABEL \
org.opencontainers.image.authors="Your Name" \
org.opencontainers.image.vendor="Open Liberty" \
org.opencontainers.image.url="local" \
org.opencontainers.image.source="https://github.com/OpenLiberty/guide-spring-boot" \
org.opencontainers.image.version="$VERSION" \
org.opencontainers.image.revision="$REVISION" \
vendor="Open Liberty" \
name="hello app" \
version="$VERSION-$REVISION" \
summary="The hello application from the Spring Boot guide" \
description="This image contains the hello application running with the Open Liberty runtime."

# tag::serverXml[]
RUN cp /opt/ol/wlp/templates/servers/springBoot3/server.xml /config/server.xml
# end::serverXml[]

# tag::cracXml[]
COPY --chown=1001:0 src/main/liberty/instantOn/crac.xml \
/config/configDropins/defaults/crac.xml
# end::cracXml[]

RUN features.sh

# tag::libcache[]
COPY --chown=1001:0 --from=staging /staging/lib.index.cache /lib.index.cache
# end::libcache[]
# tag::thinjar[]
COPY --chown=1001:0 --from=staging /staging/thin-guide-spring-boot-0.1.0.jar \
/config/dropins/spring/thin-guide-spring-boot-0.1.0.jar
# end::thinjar[]

RUN configure.sh
41 changes: 36 additions & 5 deletions scripts/testApp.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ set -euxo pipefail
docker pull -q icr.io/appcafe/open-liberty:kernel-slim-java17-openj9-ubi

docker build -t springboot .
docker run -d --name springBootContainer -p 9080:9080 -p 9443:9443 springboot
docker run -d --name springBootContainer --rm -p 9080:9080 -p 9443:9443 springboot

sleep 60
sleep 40

status="$(curl --write-out "%{http_code}\n" --silent --output /dev/null "http://localhost:9080/hello")"
if [ "$status" == "200" ]; then
Expand All @@ -29,18 +29,49 @@ else
echo ENDPOINT NOT OK
docker exec springBootContainer cat /logs/messages.log
docker stop springBootContainer
docker rm springBootContainer
exit 1
fi

docker exec springBootContainer cat /logs/messages.log | grep product
docker exec springBootContainer cat /logs/messages.log | grep java

docker stop springBootContainer
docker rm springBootContainer

uname -r

docker run --name springBootCheckpointContainer --privileged --env WLP_CHECKPOINT=afterAppStart springboot
docker commit springBootCheckpointContainer springboot-instanton
docker rm springBootCheckpointContainer
docker images
docker run --rm -d \
--name springBootContainer \
--cap-add=CHECKPOINT_RESTORE \
--cap-add=SETPCAP \
--security-opt seccomp=unconfined \
-p 9080:9080 \
springboot-instanton
docker logs springBootContainer
sleep 15
status="$(curl --write-out "%{http_code}\n" --silent --output /dev/null "http://localhost:9080/hello")"
docker stop springBootContainer
if [ "$status" == "200" ]; then
echo ENDPOINT OK
else
echo "$status"
echo ENDPOINT NOT OK
exit 1
fi

./mvnw -ntp liberty:start
curl http://localhost:9080/hello
status="$(curl --write-out "%{http_code}\n" --silent --output /dev/null "http://localhost:9080/hello")"
if [ "$status" == "200" ]; then
echo ENDPOINT OK
else
echo "$status"
echo ENDPOINT NOT OK
./mvnw -ntp liberty:stop
exit 1
fi
./mvnw -ntp liberty:stop

if [ ! -f "target/GSSpringBootApp.jar" ]; then
Expand Down
Loading
Loading