Building native images with Clojure and GraalVM.
github.com/clj-easy/graalvm-clojure
- Download GraalVM binaries - https://github.com/graalvm/graalvm-ce-builds/releases
- Extract it:
tar -xvzf graalvm-ce-java11-linux-amd64-21.3.0.tar.gz
- Move it:
mv graalvm-ce-java11-21.3.0/ /usr/lib/jvm/ && cd /usr/lib/jvm
- Check current java alternatives:
update-alternatives --config java
- Add new java alternative with 100 priority:
sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/graalvm-ce-java11-21.3.0/bin/java 100
- Check java version:
java --version
- Create symlink:
ln -s graalvm-ce-java11-21.3.0 graalvm
- Add env variables to
~/.bashrc
file:
export GRAALVM_HOME=/usr/lib/jvm/graalvm
- Reload
source ~/.bashrc
- Update PATH for the current session:
export PATH=$GRAALVM_HOME/bin:$PATH
, didn't save it to .bashrc since it is breaking update-alternatives switching between java versions. - Test that
gu
command is available
Run: gu install native-image
Check it's available: native-image
Assuming you have Leiningen installed: sudo apt install leiningen
Run: lein new app hello-world
Build: cd hello-world && lein uberjar
Run and measure time: time java -jar target/uberjar/hello-world-0.1.0-SNAPSHOT-standalone.jar
Build:
native-image --report-unsupported-elements-at-runtime \
--initialize-at-build-time \
--no-server \
-jar target/uberjar/hello-world-0.1.0-SNAPSHOT-standalone.jar \
-H:Name=./target/hello-world
Run and measure time: time target/hello-world
GraalVM options - https://www.graalvm.org/reference-manual/native-image/Options/
- Download and install Java 17.
- Add new java alternative with priority 200:
sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/graalvm-ce-java17-21.3.0/bin/java 200
- Select new java:
sudo update-alternatives --config java
- Check current version:
java --version
- Update symlink:
sudo ln -s graalvm-ce-java17-21.3.0 graalvm
- Check that native-image is not installed for this java version
With Java 17 GraalVM I had to switch to root user in order to install native-image:
7. Switch to root: sudo su
8. Set env var for current session:
export GRAALVM_HOME=/usr/lib/jvm/graalvm-ce-java17-21.3.0
export PATH=$GRAALVM_HOME/bin:$PATH
- Install native-image:
gu install native-image
- Exit from root:
exit
- Check that native-image available
Tip: to remove java alternative run: sudo update-alternatives --remove java /usr/lib/jvm/graalvm-ce-java11-21.3.0/bin/java
Docker commands:
- List all docker images:
docker images
- Build a new docker image:
docker build . -t image-name
- Delete docker image by ID:
docker rmi image-id
- Dangling docker images none:none - https://projectatomic.io/blog/2015/07/what-are-docker-none-none-images/
- Cleanup dangling docker images:
docker rmi $(docker images -f "dangling=true" -q) --force
, but that drops stage cache. - Images none:none remain until old containers that were created from them still exists, even if stopped.Source
- To clear all dangling images without associated containers:
docker image prune
Tip: to speed up docker build, use .dockerignore - https://docs.docker.com/engine/reference/builder/#dockerignore-file
Tip: Multistage builds, and run to specific stage - https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage
TODO: Try buildkit - https://docs.docker.com/engine/reference/builder/#buildkit
- Use JRE instead of JDK for the final stage - https://adoptium.net/releases.html?variant=openjdk17&jvmVariant=hotspot
- Use Adoptium Docker Hub - https://hub.docker.com/_/eclipse-temurin
- Use alpine linux images - https://hub.docker.com/layers/eclipse-temurin/library/eclipse-temurin/17-jre-alpine/images/sha256-839f3208bfc22f17bf57391d5c91d51c627d032d6900a0475228b94e48a8f9b3?context=explore
- Use scratch image for native apps - https://hub.docker.com/_/scratch
- Check installed jenv versions:
jenv versions
- Download GraalVM binaries - https://github.com/graalvm/graalvm-ce-builds/releases
- Extract it:
tar -xvzf graalvm-ce-java11-22.1.0.tar.gz
- Remove quarantine attribute on bits:
sudo xattr -r -d com.apple.quarantine path/to/graalvm/folder/
- Check where jenv stores java versions:
jenv which java
- Move new GraalVM JDK to the jenv versions folder:
mv ~/graalvm-ce-java11-22.1.0 ~/.jenv/versions/graalvm-ce-java11-22.1.0
- Add new JDK to jenv:
jenv add ~/.jenv/versions/graalvm-ce-java11-22.1.0
- Check that it was added:
jenv versions
- Use the new GraalVM JDK globally:
jenv global graalvm-ce-java11-22.1.0
- Check current java version:
java -version
- Add env variables to
~/.bashrc
file:
export GRAALVM_HOME=~/.jenv/versions/graalvm-ce-java11-22.1.0
- Reload
source ~/.bashrc
- Update PATH for the current session:
export PATH=$GRAALVM_HOME/bin:$PATH
, didn't save it to .bashrc since it is breaking jenv versions. - Test that
gu
command is available
Run: gu install native-image
Check it's available: native-image
In order to run native image with Docker from scratch, it needs to be static, meaning it will include all the dependencies that normally should be provided by OS environment.
To build static image add this param: --static
Note: as of now (Jul, 20222) MacOS doesn't support that option with error: DARWIN does not support building static executable images.
To allow app quit by pressing Ctrl + C this options needs to be added: --install-exit-handlers
If your app making http calls, this option needs to be added: --enable-url-protocols=http,https