Let’s try Open Liberty InstantOn on Intel Mac
What is Liberty InstantOn ?
Liberty InstantOn was announced as a beta feature on September 29, 2022. It is a technology that provides a full-featured cloud-native Java runtime supporting MicroProfile and Jakarta WebProfile APIs that enables applications to start in hundreds of milliseconds. InstantOn is currently available as a special beta release container image.
When using Serverless technology in a container environment, the startup time is important. The response time includes the time it takes for the container process to start. So the startup time directly affects the quality of service.
Many efforts have been made to reduce the startup time for Java applications. For example, one of the efforts is to use the capabilities of GraalVM to transform the application into a native executable. However, GraalVM does not allow all Java features to be used, so it is not possible to convert widely used Java EE or Jakarta EE applications into executables.
Liberty InstantOn takes a totally different approach to reduce the startup time. It takes advantage of the Linux CRIU (Checkpoint/Restore In Userspace) technology. CRIU is a set of functions for recording (Checkpoint) the information of the running process in a file and restoring (Restore) the process from the file.
Open Liberty with an Eclipse OpenJ9 VM incorporates CRIU technology to get a checkpoint when the application finishes initializing. By committing the container in this state and resuming it from there, it can be started in a lightning fast time.
Let’s try InstantOn on Intel Mac
The InstantOn steps in the blog article Liberty InstantOn startup for cloud native Java applications are based on the Red Hat Enterprise Linux. The same experience can be achieved on an Intel Mac with macOS Monterey (version 12.x). This article shares the steps to experience the exciting technology on Mac. Currently, InstantOn feature is not available on M1 aarch64 architecture.
The InstantOn sample environment is published as a container image from IBM Cloud Registry. As the container execution environment, we can use podman, which one can install via Homebrew by brew install podman
. On Mac, we needed to tweak the steps a little bit to see the InstantOn in action.
Preparing the Podman
Since InstantOn uses the CAP_CHECKPOINT_RESTORE function of the Linux kernel, the InstantOn feature does not work properly if podman is started in rootless mode, Also, once the virtual environment (podman machine) has been started in rootless mode, it will fail even if it is run in rootful mode. The solution is to create a new dedicated virtual machine. It may be necessary to remove existing VM by podman machine list
and podman machine rm
commands.
The followng steps create a podman virtual environment and start it in rootful mode. We will configure it to connect to a virtual machine by default.
$ podman machine init rootful
Extracting compressed file
Image resized.
Machine init complete
To start your machine run:
podman machine start rootful
$ podman machine set --rootful rootful
$ podman machine start rootful
Starting machine "rootful"
Waiting for VM ...
Mounting volume... /Users/takakiyo:/Users/takakiyo
API forwarding listening on: /var/run/docker.sock
Docker API clients default to this address. You do not need to set DOCKER_HOST.
Machine "rootful" started successfully
$ podman system connection default rootful-root
The following is version of podman used for this article.
$ podman version
Client: Podman Engine
Version: 4.3.0
API Version: 4.3.0
Go Version: go1.18.7
Built: Tue Oct 18 13:55:57 2022
OS/Arch: darwin/amd64
Server: Podman Engine
Version: 4.3.0
API Version: 4.3.0
Go Version: go1.18.7
Built: Fri Oct 21 04:16:35 2022
OS/Arch: linux/amd64
Cloning and building the test application
Let’s clone the sample application from GitHub and build it.
$ git clone https://github.com/openliberty/guide-getting-started.git
Cloning into 'guide-getting-started'...
remote: Enumerating objects: 2747, done.
remote: Counting objects: 100% (537/537), done.
remote: Compressing objects: 100% (275/275), done.
remote: Total 2747 (delta 172), reused 447 (delta 116), pack-reused 2210
Receiving objects: 100% (2747/2747), 859.87 KiB | 2.74 MiB/s, done.
Resolving deltas: 100% (1097/1097), done.
$ cd guide-getting-started/finish
$ mvn package
[INFO] Scanning for projects...
(...)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.240 s
[INFO] Finished at: 2022-10-16T21:09:55+09:00
[INFO] ------------------------------------------------------------------------
Create a container image
To use the InstantOn image, rewrite the first line of the Dockerfile in the same directory with beta`
tag. If you want to play around, look inside this image and do your experiment!
FROM icr.io/appcafe/open-liberty:beta
Next, we are going to build a container image.
$ podman build -t getting-started .
STEP 1/7: FROM icr.io/appcafe/open-liberty:beta
Trying to pull icr.io/appcafe/open-liberty:beta...
Getting image source signatures
Copying blob sha256:3d49a5e804a4e5da1ee053e0dd6fda7c4011458bf43f658d45a7fe5d064d0a5f
(...)
Copying blob sha256:b23a0409c41c442e8f1bf00d2649fa127f63f92e131d5ccf39a1d0ae82ec3cd6
Copying blob sha256:308dc9b7079f15af4e4f23cab1fd5082fadf4052d237959e3bdd4c8fa73a6346
Copying config sha256:7cd2ddfe28da75e669998130b99bb7fb48e255ba9d9f776804b78d630f2e0469
Writing manifest to image destination
Storing signatures
STEP 2/7: ARG VERSION=1.0
--> 3816b6a9a20
STEP 3/7: ARG REVISION=SNAPSHOT
--> b82ea29da9b
STEP 4/7: LABEL org.opencontainers.image.authors="Your Name" org.opencontainers.image.vendor="IBM" org.opencontainers.image.url="local" org.opencontainers.image.source="https://github.com/OpenLiberty/guide-getting-started" org.opencontainers.image.version="$VERSION" org.opencontainers.image.revision="$REVISION" vendor="Open Liberty" name="system" version="$VERSION-$REVISION" summary="The system microservice from the Getting Started guide" description="This image contains the system microservice running with the Open Liberty runtime."
--> 1781202e3e0
STEP 5/7: COPY --chown=1001:0 src/main/liberty/config/ /config/
--> 3d515ebf80e
STEP 6/7: COPY --chown=1001:0 target/*.war /config/apps/
--> b56dbcc57b8
STEP 7/7: RUN configure.sh
COMMIT getting-started
--> 612b43d3e78
Successfully tagged localhost/getting-started:latest
612b43d3e785166c3d9c05c315944921333748dba432a5b53640ea240f77092c
If you run it normally, it will start Open Liberty and the application as usual.
$ podman run -it --name getting-started --rm -p 9080:9080 getting-started
WARNING: Unknown module: jdk.management.agent specified to --add-exports
WARNING: Unknown module: jdk.attach specified to --add-exports
Launching defaultServer (Open Liberty 22.0.0.11-beta/wlp-1.0.69.cl221020220912-1100) on Eclipse OpenJ9 VM, version 17.0.5-ea+2 (en_US)
CWWKE0953W: This version of Open Liberty is an unsupported early release version.
[AUDIT ] CWWKE0001I: The server defaultServer has been launched.
[AUDIT ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/checkpoint.xml
[AUDIT ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/keystore.xml
[AUDIT ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/open-default-port.xml
[AUDIT ] CWWKZ0058I: Monitoring dropins for applications.
[AUDIT ] CWWKT0016I: Web application available (default_host): http://de537b960bc9:9080/ibm/api/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://de537b960bc9:9080/health/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://de537b960bc9:9080/metrics/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://de537b960bc9:9080/dev/
[AUDIT ] CWWKZ0001I: Application guide-getting-started started in 1.978 seconds.
[AUDIT ] CWWKF0012I: The server installed the following features: [cdi-3.0, checkpoint-1.0, concurrent-2.0, distributedMap-1.0, jndi-1.0, json-1.0, jsonb-2.0, jsonp-2.0, monitor-1.0, mpConfig-3.0, mpHealth-4.0, mpMetrics-4.0, restfulWS-3.0, restfulWSClient-3.0, servlet-5.0, ssl-1.0, transportSecurity-1.0].
[AUDIT ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 6.851 seconds.
Even without InstantOn, the application starts in 6 to 7 seconds in my environment. Not bad at all. From the command prompt in another window, use the curl command to confirm that the application started successfully.
$ curl http://localhost:9080/dev/system/properties
If you press Ctrl+C in the window that started the container, the container in which Liberty is running stops.
^C[AUDIT ] CWWKE0085I: The server defaultServer is stopping because the JVM is exiting.
[AUDIT ] CWWKE1100I: Waiting for up to 30 seconds for the server to quiesce.
[AUDIT ] CWWKT0017I: Web application removed (default_host): https://de537b960bc9:9443/dev/
[AUDIT ] CWWKT0017I: Web application removed (default_host): https://de537b960bc9:9443/health/
[AUDIT ] CWWKT0017I: Web application removed (default_host): https://de537b960bc9:9443/metrics/
[AUDIT ] CWWKT0017I: Web application removed (default_host): https://de537b960bc9:9443/ibm/api/
[AUDIT ] CWWKZ0009I: The application guide-getting-started has stopped successfully.
[AUDIT ] CWWKE0036I: The server defaultServer stopped after 2 minutes, 32.806 seconds.
Checkpoint the application
Now let’s get a checkpoint. Since various privileges are required, we will run with the --privileged
option. By specifying afterAppStart
for the environment variable WLP_CHECKPOINT
, Open Liberty can save the checkpoint when the application initialization was completed.
$ podman run --name getting-started-checkpoint-container --privileged --env WLP_CHECKPOINT=afterAppStart getting-started
Performing checkpoint --at=afterAppStart
WARNING: Unknown module: jdk.management.agent specified to --add-exports
WARNING: Unknown module: jdk.attach specified to --add-exports
Launching defaultServer (Open Liberty 22.0.0.11-beta/wlp-1.0.69.cl221020220912-1100) on Eclipse OpenJ9 VM, version 17.0.5-ea+2 (en_US)
CWWKE0953W: This version of Open Liberty is an unsupported early release version.
[AUDIT ] CWWKE0001I: The server defaultServer has been launched.
[AUDIT ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/checkpoint.xml
[AUDIT ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/keystore.xml
[AUDIT ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/open-default-port.xml
[AUDIT ] CWWKZ0058I: Monitoring dropins for applications.
[AUDIT ] CWWKT0016I: Web application available (default_host): http://940fd476eccc:9080/ibm/api/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://940fd476eccc:9080/health/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://940fd476eccc:9080/metrics/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://940fd476eccc:9080/dev/
[AUDIT ] CWWKZ0001I: Application guide-getting-started started in 1.340 seconds.
[AUDIT ] CWWKC0451I: A server checkpoint was requested. When the checkpoint completes, the server stops.
/opt/ol/wlp/bin/server: line 946: 130 Killed "${JAVA_CMD}" "$@" >> "${CHECKPOINT_CONSOLE_LOG}" 2>&1 < /dev/null
This starts the application container and proceeds to start the application. After the application has started the runtime will perform a checkpoint of the process. When the process state has been saved the container exits. Since the container was started without --rm
this time, the stopped container remains available for inspection. This stopped container, named getting-started-checkpoint-container
, contains the checkpoint process state information.
$ podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
940fd476eccc localhost/getting-started:latest /opt/ol/wlp/bin/s... 4 minutes ago Exited (0) 4 minutes ago getting-started-checkpoint-container
The following command commits the container into a new image. This new image, named getting-started-instanton
, will contain the checkpoint process state for the application. This process state is then used to quickly start the application when the getting-started-instanton
image is run as a container.
$ podman commit getting-started-checkpoint-container getting-started-instanton
a856d767b8c31718dfbc6e60f742675448086fb4421490b5bfde6d3392d2f879
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/getting-started-instanton latest a856d767b8c3 7 seconds ago 990 MB
localhost/getting-started latest 1049db82664e 31 minutes ago 890 MB
icr.io/appcafe/open-liberty beta 7cd2ddfe28da 2 weeks ago 864 MB
Starting Open Liberty using the InstantOn feature
Now it’s time to execute InstantOn. When you start Liberty using this image, the server will start in a flash.
% podman run -it --rm --privileged -p 9080:9080 getting-started-instanton
[AUDIT ] CWWKZ0001I: Application guide-getting-started started in 0.066 seconds.
[AUDIT ] CWWKC0452I: The Liberty server process resumed operation from a checkpoint in 0.131 seconds.
[AUDIT ] CWWKF0012I: The server installed the following features: [cdi-3.0, checkpoint-1.0, concurrent-2.0, distributedMap-1.0, jndi-1.0, json-1.0, jsonb-2.0, jsonp-2.0, monitor-1.0, mpConfig-3.0, mpHealth-4.0, mpMetrics-4.0, restfulWS-3.0, restfulWSClient-3.0, servlet-5.0, ssl-1.0, transportSecurity-1.0].
[AUDIT ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 0.167 seconds.
Liberty started in 0.1-0.2 seconds in my environment. If you access it with the curl command or browser, you can see that the application is running successfully. Stop Liberty with Ctrl+C. This image can be used as many times as you want.
Starting Open Liberty using the InstantOn feature without --privileged
Running fully privileged containers is not recommended. The best practice is to instead reduce the elevated privileges down to only what is required to run the container.
It is possible to run podman with unconfined --security-opt options below also worked on the Mac OS mentioned below. For more details of the parameters and the input file, refer to the original InstantOn blog .
podman command with unconfined --security-opt
options
$ podman run \
--rm \
--cap-add=CHECKPOINT_RESTORE \
--cap-add=NET_ADMIN \
--cap-add=SYS_PTRACE \
--security-opt seccomp=unconfined \
--security-opt systempaths=unconfined \
--security-opt apparmor=unconfined \
-p 9080:9080 \
getting-started-instanton
[AUDIT ] CWWKZ0001I: Application guide-getting-started started in 0.101 seconds.
[AUDIT ] CWWKC0452I: The Liberty server process resumed operation from a checkpoint in 0.229 seconds.
[AUDIT ] CWWKF0012I: The server installed the following features: [cdi-3.0, checkpoint-1.0, concurrent-2.0, ... transportSecurity-1.0].
[AUDIT ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 0.283 seconds
podman command with seccomp to only required system calls.
$ podman run \
--rm \
--cap-add=CHECKPOINT_RESTORE \
--cap-add=NET_ADMIN \
--cap-add=SYS_PTRACE \
--security-opt seccomp=/Users/[email protected]/InstantOn/guide-getting-started/finish/criuRequiredSysCalls.json \
-v /proc/sys/kernel/ns_last_pid:/proc/sys/kernel/ns_last_pid \
-p 9080:9080 \
getting-started-instanton
[AUDIT ] CWWKZ0001I: Application guide-getting-started started in 0.101 seconds.
[AUDIT ] CWWKC0452I: The Liberty server process resumed operation from a checkpoint in 0.220 seconds.
[AUDIT ] CWWKF0012I: The server installed the following features: [cdi-3.0, checkpoint-1.0, concurrent-2.0, distributedMap-1.0, jndi-1.0, json-1.0, jsonb-2.0, jsonp-2.0, monitor-1.0, mpConfig-3.0, mpHealth-4.0, mpMetrics-4.0, restfulWS-3.0, restfulWSClient-3.0, servlet-5.0, ssl-1.0, transportSecurity-1.0].
[AUDIT ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 0.262 seconds.
The podman command may no longer need to mount ns_last_pid
nor seccomp
parameter at a newer OS version. The following CHECKPOINT_RESTORE command worked on macOS Monterey 12.6.
podman run \
--rm \
--cap-add=CHECKPOINT_RESTORE \
--cap-add=NET_ADMIN \
--cap-add=SYS_PTRACE \
-p 9080:9080 \
getting-started-instanton
The above command ran successfully on the following MacOS version.
$ sw_vers
ProductName: macOS
ProductVersion: 12.6
BuildVersion: 21G115
As a final step, stop the virtual environment with podman machine stop rootful
command and restore the default connection with podman system connection default podman-machine-default
command.