Friends of OpenJDK Today

How to Run a Java Application with CRaC in a Docker Container

February 01, 2023

Author(s)

  • Avatar photo
    Gerrit Grunwald

    JUG Leader, Java Champion, Speaker, Author, ❤️ Java(FX) and coding in general

CRaC (Coordinated Restore at Checkpoint) is an OpenJDK project that was developed by Azul to solve the problem of "slow" startup times of the Java Virtual Machine in a microservice environment.

The most up-to-date guidelines can be found on "Coordinated Restore at Checkpoint Usage Guidelines" in the Azul Docs.

When the JVM runs your application code, it does things like interpreting, compiling and optimizing code to make your application run as fast as possible under the given workload. This is great but can take some time and especially when you run short lived microservices you don't want to wait until the JVM has produced the most optimized code.

The checkpoint-restore mechanism is nothing new and most of you already know and use it daily. If you work on your laptop and close the lid, the operating systems detects that an stores it's current state to disk. Once you open up the lid again, the operating system restores the saved state from disk.
CRaC provides the same mechanism but for the JVM and your running application.

You start your application, apply some workload to it (to make sure the important parts of your code will be touched and with that optimized by the JVM) and then create a checkpoint. This will close all open resources like open files and socket connections and will then store the state of the JVM including your application to disk.

After that, you can restore the state of the JVM including the state of your application from that stored checkpoint as often as you like.

And with this, CRaC not only is capable of solving the startup time problem but can also solve the application warmup time problem because you can create the checkpoint whenever you like.

More on CRaC

If you want to learn more about the project, here are some blogposts with more explanations

Superfast Application Startup: Java on CRaC

Introducing the OpenJDK “Coordinated Restore at Checkpoint” Project

Azul Docs: Running CRaC in a Virtualized Environment (Docker)

Videos on CRaC

There are also several recorded sessions from either my colleague Simon Ritter or myself, that you can find on youtube. Here are just two of them

Java on CRaC (Simon Ritter at Devoxx Belgium)

What the CRaC (Gerrit Grunwald at Voxxed Athens)

CRaC GitHub Page

If you would like to know more about the implementation or if you would like to download the OpenJDK build that incl. CRaC support you might want check out the github page we have created

Github Page

Preparations

The idea is to have an application or service that consists of a single executable JAR file.

The plan is to make you use your own application and use it for this test but if you simply would like to play around with CRaC you can also use one of my demos that you will find here.

Note: CRaC is only available for Linux runing on an x64 (Intel/AMD) machine which is the configuration that is mainly used on todays cloud providers.

Create the docker image

  1. You need an application in a runnable JAR file.
  2. Now we need to create a Dockerfile. The following file is the minimum file you need to run your application in a docker container.
FROM ubuntu:20.04

ENV JAVA_HOME /opt/jdk
ENV PATH $JAVA_HOME/bin:$PATH

RUN apt-get update -y

ADD "https://github.com/CRaC/openjdk-builds/releases/download/17-crac%2B3/openjdk-17-crac+3_linux-x64.tar.gz" $JAVA_HOME/openjdk.tar.gz
RUN tar --extract --file $JAVA_HOME/openjdk.tar.gz --directory "$JAVA_HOME" --strip-components 1; rm $JAVA_HOME/openjdk.tar.gz;

RUN mkdir -p /opt/crac-files

COPY build/libs/MY-APP.jar /opt/app/MY-APP.jar
  1. Now we can run docker build -t myapp_on_crac . to build the docker image.

Start your application in a docker container

  1. Run your docker container with:
    docker run -it --privileged --rm --name my_app_on_crac my_app_on_crac
  2. In the docker container run:
    cd /opt/app
    java -XX:CRaCCheckpointTo=/opt/crac-files -jar MY-APP.jar
    
  1. Note the PID of the program.
  2. Leave the shell window open and the application running.

Create the checkpoint

  1. Open another shell window.
  2. In this window run:
    docker exec -it -u root my_app_on_crac /bin/bash
  3. Now it's up to you when you would like to create the checkpoint (e.g. apply some workload to your app to make sure everything is compiled and optimized).
  4. Take the PID that you noted from the other shell window and create the checkpoint by executing jcmd PID JDK.checkpoint
  5. If everything is ok, you should see that in the first shell window the checkpoint was created and your application was closed.
  6. Now the docker container running in the first shell window contains the checkpoint in the /opt/crac-files folder.
  7. Now you can close the second shell window by executing exit to get back to your machine.

Commit the current state of the docker container

  1. Now we need to save the current state of the docker container incl. the checkpoint. For this we need the CONTAINER_ID.
  2. Open a new shell window and execute docker ps -a and note the CONTAINER_ID of the container that ran your app.
  3. By running
    docker commit CONTAINER_ID my_app_on_crac:checkpoint

    in the second shell window, we can commit the current state of the container to the state checkpoint.

  4. Now we can stop the docker container by executing exitin the first shell window.

Run the docker container from the checkpoint

  1. Run:
    docker run -it --privileged --rm --name my_app_on_crac my_app_on_crac:checkpoint java -XX:CRaCRestoreFrom=/opt/crac-files
  2. Your application should now start much faster from the saved checkpoint.

Note: You can run the docker container also on MacOS or Windows, as long as the machine you are running it on has a x64 cpu architecture (Intel/AMD).

Final words

If you play around with CRaC and stumble upon problems, PLEASE let us know, we only provide the solution but you are the ones that need to use it and we simply have no idea what your application is doing.

In case of problems the best thing to do is to file an issue over at github.

Happy cracing! 😁

Topics:

Related Articles

View All

Author(s)

  • Avatar photo
    Gerrit Grunwald

    JUG Leader, Java Champion, Speaker, Author, ❤️ Java(FX) and coding in general

Comments (2)

Your email address will not be published. Required fields are marked *

Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language.

Save my name, email, and website in this browser for the next time I comment.

Matteo

When restoring, I believe the command ought to be:

docker run -it --privileged --rm --name my_app_on_crac my_app_on_crac:checkpoint
java -XX:CRaCRestoreFrom=/opt/crac-files

with a new line, otherwise you’d get the error from the docker daemon “open cppath: No such file or directory” as it’s parsing java… as part of the docker run command 🙂

This was a great tutorial, thank you!

Avatar photo
Gerrit Grunwald

I usually run it from a shell script without the need for a new line but if it works for you with the new line…great 🙂 Thank’s for the heads up, appreciated.

Subscribe to foojay updates:

https://foojay.io/feed/
Copied to the clipboard