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
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
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
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
You need an application in a runnable JAR file.
Now we need to create a Dockerfile. The following file is the minimum file you need to run your application in a docker container.
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
Now we can run docker build -t myapp_on_crac . to build the docker image
Start your application in a docker container
Run your docker container with:
docker run -it –privileged –rm –name my_app_on_crac my_app_on_crac
In the docker container run:
java -XX:CRaCCheckpointTo=/opt/crac-files -jar MY-APP.jar
Note the PID of the program.
Leave the shell window open and the application running.
Create the checkpoint
Open another shell window
In this window run:
docker exec -it -u root my_app_on_crac /bin/bash
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)
Take the PID that you noted from the other shell window and create the checkpoint by executing jcmd PID JDK.checkpoint
If everything is ok, you should see that in the first shell window the checkpoint was created and your application was closed
Now the docker container running in the first shell window contains the checkpoint in the /opt/crac-files folder
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
Now we need to save the current state of the docker container incl. the checkpoint. For this we need the CONTAINER_ID.
Open a new shell window and execute docker ps -a and note the CONTAINER_ID of the container that ran your app
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.
Now we can stop the docker container by executing exitin the first shell window
Run the docker container from the checkpoint
docker run -it –privileged –rm –name my_app_on_crac my_app_on_crac:checkpoint java -XX:CRaCRestoreFrom=/opt/crac-files
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)
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
The post How to Run a Java Application with CRaC in a Docker Container appeared first on foojay.