Skip to content

Commit

Permalink
Improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
timosalm committed Nov 8, 2024
1 parent 921b876 commit 2f52422
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 35 deletions.
53 changes: 53 additions & 0 deletions .github/workflows/leyden-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Docker

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

on:

push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

env:
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}


jobs:
build:

runs-on: ubuntu-latest
permissions:
contents: read
packages: write
# This is used to complete the identity challenge
# with sigstore/fulcio when running outside of PRs.
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Docker image
id: push
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
file: ./leyden/Dockerfile
push: true
tags: ghcr.io/${{ github.repository }}:hello-world-leyden


53 changes: 18 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,34 @@ Special thanks to [Sébastien Deleuze](https://github.com/sdeleuze/), who is not

## Container image building

*Hint: If you want to skip the container image building, you can use my images by running `export REGISTRY_HOST=harbor.main.emea.end2end.link/going-serverless`, and jump to the "[Running the application on Knative](#running-the-application-on-knative)" section.*
*Hint: If you want to skip the container image building, you can use my images by running `export REGISTRY_HOST=ghcr.io/timosalm/going-serverless:`, and jump to the "[Running the application on Knative](#running-the-application-on-knative)" section.*
```
export REGISTRY_HOST=<your-registry-hostname>(/<project>)
export REGISTRY_HOST=<your-registry-hostname>(/<project>)/
```

### Without optimizations
```
./gradlew bootBuildImage --imageName=$REGISTRY_HOST/hello-world
docker push $REGISTRY_HOST/hello-world
./gradlew bootBuildImage --imageName=${REGISTRY_HOST}hello-world
docker push ${REGISTRY_HOST}hello-world
```

### GraalVM Native Image
The required "org.graalvm.buildtools.native" plugin in build.gradle will be enabled based on the custom "graalvm" profile
```
./gradlew bootBuildImage --imageName=$REGISTRY_HOST/hello-world-native -PbuildProfile=graalvm
docker push $REGISTRY_HOST/hello-world-native
./gradlew bootBuildImage --imageName=${REGISTRY_HOST}hello-world-native -PbuildProfile=graalvm
docker push ${REGISTRY_HOST}hello-world-native
```

### Project CraC
```
capsh --print # Check whether required capabilities are available
docker build . -t $REGISTRY_HOST/hello-world-crac:checkpointer --file crac/Dockerfile
docker run -d --cap-add CHECKPOINT_RESTORE --cap-add SYS_PTRACE --rm --name hello-world-crac-checkpointer $REGISTRY_HOST/hello-world-crac:checkpointer
docker build . -t ${REGISTRY_HOST}hello-world-crac:checkpointer --file crac/Dockerfile
docker run -d --cap-add CHECKPOINT_RESTORE --cap-add SYS_PTRACE --rm --name hello-world-crac-checkpointer ${REGISTRY_HOST}hello-world-crac:checkpointer
# Wait until checkpoint creation succeeded: docker logs $(docker ps -qf "name=hello-world-crac-checkpointer") -f
docker commit --change='ENTRYPOINT ["/opt/app/entrypoint.sh"]' $(docker ps -qf "name=hello-world-crac-checkpointer") $REGISTRY_HOST/hello-world-crac
docker commit --change='ENTRYPOINT ["/opt/app/entrypoint.sh"]' $(docker ps -qf "name=hello-world-crac-checkpointer") ${REGISTRY_HOST}hello-world-crac
docker kill $(docker ps -qf "name=hello-world-crac-checkpointer")
# Test: docker run -d --cap-add CHECKPOINT_RESTORE --cap-add SYS_ADMIN --rm -p 8080:8080 --name hello-world-crac-checkpoint $REGISTRY_HOST/hello-world-crac
docker push $REGISTRY_HOST/hello-world-crac
# Test: docker run -d --cap-add CHECKPOINT_RESTORE --cap-add SYS_ADMIN --rm -p 8080:8080 --name hello-world-crac-checkpoint ${REGISTRY_HOST}hello-world-crac
docker push ${REGISTRY_HOST}hello-world-crac
```

### CDS
Expand All @@ -45,37 +45,20 @@ docker push $REGISTRY_HOST/hello-world-crac
The required BP_JVM_CDS_ENABLED=true and BP_SPRING_AOT_ENABLED env variables for the Cloud Native Buildpack will be
enabled based on the custom "cds" profile in build.gradle.
```
./gradlew bootBuildImage --imageName=$REGISTRY_HOST/hello-world-cds -PbuildProfile=cds
docker push $REGISTRY_HOST/hello-world-cds
./gradlew bootBuildImage --imageName=${REGISTRY_HOST}hello-world-cds -PbuildProfile=cds
docker push ${REGISTRY_HOST}hello-world-cds
```

#### Option 2 with Dockerfile
```
docker build . -t $REGISTRY_HOST/hello-world-cds --file cds/Dockerfile
docker push $REGISTRY_HOST/hello-world-cds
```

## Container image building with kpack

### Without optimizations
```
kp image create hello-world --git https://github.com/timosalm/going-serverless --tag $REGISTRY_HOST/hello-world --env BP_JVM_VERSION=21
```

### GraalVM Native Image
```
kp image create hello-world-native --git https://github.com/timosalm/going-serverless --tag $REGISTRY_HOST/hello-world-native --env BP_JVM_VERSION=21 --env BP_NATIVE_IMAGE=true
```

### CDS
```
kp image create hello-world-native --git https://github.com/timosalm/going-serverless --tag $REGISTRY_HOST/hello-world-native --env BP_JVM_VERSION=21 --env BP_JVM_CDS_ENABLED=true --env BP_SPRING_AOT_ENABLED=true
docker build . -t ${REGISTRY_HOST}hello-world-cds --file cds/Dockerfile
docker push ${REGISTRY_HOST}hello-world-cds
```

## Running the application on Knative
### Without optimizations
```
kn service create hello-world --image $REGISTRY_HOST/hello-world
kn service create hello-world --image ${REGISTRY_HOST}hello-world
kubectl logs -l app=hello-world-00001 -c user-container | grep "Started HelloWorldApplication"
# Started HelloWorldApplication in 4.558 seconds (process running for 5.214)
watch kubectl get pods
Expand All @@ -87,7 +70,7 @@ kubectl top pods -l app=hello-world-00001 --containers

### GraalVM Native Image
```
kn service create hello-world-native --image $REGISTRY_HOST/hello-world-native
kn service create hello-world-native --image ${REGISTRY_HOST}hello-world-native
kubectl logs -l app=hello-world-native-00001 -c user-container | grep "Started HelloWorldApplication"
# Started HelloWorldApplication in 0.238 seconds (process running for 0.247)
watch kubectl get pods
Expand All @@ -111,7 +94,7 @@ kubectl top pods -l app=hello-world-crac-00001 --containers

### CDS
```
kn service create hello-world-cds --image $REGISTRY_HOST/hello-world-cds
kn service create hello-world-cds --image ${REGISTRY_HOST}hello-world-cds
kubectl logs -l app=hello-world-cds-00001 -c user-container | grep "Started HelloWorldApplication"
# Started HelloWorldApplication in 2.769 seconds
watch kubectl get pods
Expand Down
22 changes: 22 additions & 0 deletions leyden/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM debian:latest

ENV JDK_URL=https://download.java.net/java/early_access/leyden/2/openjdk-24-leyden+2-8_linux-x64_bin.tar.gz
ENV JAVA_HOME=/opt/java/openjdk
ENV PATH="$JAVA_HOME/bin:$PATH"

RUN apt-get update && apt-get install -y wget tar && rm -rf /var/lib/apt/lists/*

RUN mkdir -p "$JAVA_HOME" && wget -qO- "$JDK_URL" | tar -xz --strip-components=1 -C "$JAVA_HOME"

RUN mkdir tmp
COPY ./build.gradle ./gradlew ./settings.gradle tmp/
COPY ./gradle tmp/gradle
COPY ./src tmp/src
RUN ./tmp/gradlew assemble

COPY ./leyden/unpack-executable-jar.sh tmp/
RUN ./tmp/unpack-executable-jar.sh -d build-unpacked tmp/build/libs/hello-world-0.0.1-SNAPSHOT.jar
RUN rm -rf tmp
RUN java -Dspring.aot.enabled=true -Dspring.context.exit=onRefresh -XX:CacheDataStore=build-unpacked/application.cds -jar build-unpacked/run-app.jar

CMD ["java", "-Dspring.aot.enabled=true", "-XX:CacheDataStore=build-unpacked/application.cds", "-jar", "build-unpacked/run-app.jar"]
76 changes: 76 additions & 0 deletions leyden/unpack-executable-jar.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env bash
set -e

# https://github.com/sdeleuze/spring-petclinic-data-jdbc/blob/cds/unpack-executable-jar.sh

while test $# -gt 0; do
case "$1" in
-h|--help)
echo "unpack-executable-jar.sh - unpack Spring Boot executable JAR in order to run"
echo "the application efficiently and maximizing CDS effectiveness."
echo " "
echo "my-dir
├── application
│ └── my-app-1.0.0-SNAPSHOT.jar
├── dependencies
│ ├── ...
│ ├── spring-context-6.1.0.jar
│ ├── spring-context-support-6.1.0.jar
│ ├── ...
└── run-app.jar"
echo " "
echo "unpack-executable-jar.sh [options] application.jar"
echo " "
echo "options:"
echo "-d directory Create the files in directory"
echo "-h, --help Show brief help"
exit 0
;;
-d)
shift
if test $# -gt 0; then
export DESTINATION=$1
else
echo "no destination specified"
exit 1
fi
shift
;;
*)
export JAREXE=$1
shift
;;
esac
done

if [ -z "$JAREXE" ]; then
echo "specifying the executable JAR is mandatory"
exit 1
fi

UNPACK_TMPDIR="${TMPDIR}unpack-executable-jar"
if [ -d "$UNPACK_TMPDIR" ]; then rm -Rf "$UNPACK_TMPDIR"; fi

if [ -z "$DESTINATION" ]; then
DESTINATION="$(pwd)"
fi

unzip -q "$JAREXE" -d "$UNPACK_TMPDIR"
mkdir -p "${DESTINATION}/application"
mkdir -p "${DESTINATION}/dependencies"

jar cf "${DESTINATION}/application/$(basename "$JAREXE")" -C "${UNPACK_TMPDIR}/BOOT-INF/classes/" .

MANIFEST_RUN_APP="${UNPACK_TMPDIR}/MANIFEST-RUN-APP.MF"
MAIN_CLASS=$(grep "Start-Class:" "${UNPACK_TMPDIR}/META-INF/MANIFEST.MF" | cut -d ' ' -f 2)

echo "Manifest-Version: 1.0" > "${MANIFEST_RUN_APP}"
echo "Main-Class: ${MAIN_CLASS}" >> "${MANIFEST_RUN_APP}"
echo "Class-Path: application/$(basename "$JAREXE")" >> "${MANIFEST_RUN_APP}"
cut -d '/' -f 3 < "${UNPACK_TMPDIR}/BOOT-INF/classpath.idx" | cut -d '"' -f 1 | while IFS= read -r lib
do
cp -r "${UNPACK_TMPDIR}/BOOT-INF/lib/${lib}" "${DESTINATION}/dependencies/"
echo " dependencies/$lib" >> "${MANIFEST_RUN_APP}"
done

jar cfm "${DESTINATION}/run-app.jar" "${MANIFEST_RUN_APP}"

0 comments on commit 2f52422

Please sign in to comment.