Creating Your Own Jenkins JNLP Slave Container for GraalVM

In the journey of Quarkus project implementation you will need to consider what is the CI/CD implementation. The very first come to the picture is how to implement the CI part.

Jenkins GraalVM JNLP Slave Container

This is also part of my attempt to implement the first part of my GitOps architecture in my previous article. Naturally I am choosing Jenkins as my CI server because I am more familiar with this tool.

The very first thing we need is the Jenkins JNLP slave container for GraalVM to build the Quarkus native runnable.

However, Jenkins has not officially released any slave container for this yet as I checked in the Docker Hub when this is written. So, I decided to build one for myself, after many googling and killing of brain cells.

Creating GraalVM JPNL Jenkins Container

The following shows the Dockerfile for my jpnl-agent-graalvm container image.

FROM jenkinsci/jnlp-slave
ARG version=1.0.0

# --- command: docker build -f ./Dockerfile -t jnlp-agent-graalvm .
LABEL Author="CK Gan" Email="chengkuan@gmail.com" Description="Jenkins jnlp agent with Graalvm." Version="$version"

USER root

ENV GRAALVM_BASE /opt/graalvm
ENV GRAALVM_HOME $GRAALVM_BASE/graalvm-ce-java11-20.0.0
ENV JAVA_HOME $GRAALVM_HOME
ENV PATH $JAVA_HOME/bin:$PATH

# --- commented out. Uncomment to do direct curl download the GraalVM
# RUN mkdir $GRAALVM_BASE && curl -o $GRAALVM_BASE/graalvm-ce-java11-linux-amd64-20.0.0.tar.gz -L https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-20.0.0/graalvm-ce-java11-linux-amd64-20.0.0.tar.gz && cd $GRAALVM_BASE && tar xvf $GRAALVM_BASE/graalvm-ce-java11-linux-amd64-20.0.0.tar.gz --directory $GRAALVM_BASE

# --- Pre downloaded GraalVM and copy over locally
RUN mkdir $GRAALVM_BASE && mkdir $GRAALVM_HOME
COPY ./graalvm-ce-java11-20.0.0 $GRAALVM_HOME/

# --- install build essentails for GraalVM Native build
RUN apt-get -y update && apt-get -y install build-essential gcc libz-dev && apt-get clean && chmod -R g+rw $GRAALVM_HOME && gu install native-image

I have a local copy of the GraalVM files in the same directory as the Dockerfile. You can curl the file and extract it directly when building the Dockerfile but I only need to download once by using local files.

In the directory containing the Dockerfile and Graalvm files, run the following command to build the container image.

docker build -f ./Dockerfile -t jnlp-agent-graalvm .

Jenkins requires a proper image registry to provision the agent/slave container during build time. So I am using a local Docker container registry for this purpose. I run the following commands to tag the new image and push it to this local container image registry.

docker image tag jnlp-agent-graalvm localhost:5000/jnlp-agent-graalvm:latest
 
docker image push localhost:5000/jnlp-agent-graalvm:latest

Configure Jenkins Server with The New JNLP GraalVM Container

If your Jenkins server does not have the Docker plugin, please proceed to install one as per the following screen shot.

Jenkins Docker plugin

The following shows the Docker container configuration.

Jenkins GraalVM Docker configuration
Jenkins GraalVM Docker configuration
Jenkins GraalVM Docker agent templates
Jenkins GraalVM Docker agent templates

Jenkins Pipelines

The following is the snippet of the Jenkins pipelines to test the GraalVM slave container. Obviously you also need to have your Quarkus source code available, which I am not going to show here.

def mvnwCmd = "./mvnw -s ./nexus_settings.xml"

pipeline {
   agent none
   stages(){
      stage('Build Quarkus Native') {
         agent {
            label 'graalvm'
         }
         steps{
            sh "${mvnwCmd} -DskipTests=true package -Pnative"
         }
      }
   }
}

Note: While using the Jenkins to build the Quarkus native runnable, I encountered the following error in the Jenkins build log. This is due to the Jenkins slave container ran out of memory. The error does not reflect the actual problem. I have to increase the Jenkins slave container memory limit to at least 2048Mb and double the swap memory.

I had killed many brain cells to find out the root cause of this problem.

Error: Image build request failed with exit status 137 Failed to execute goal io.quarkus:quarkus-maven-plugin:1.2.1.Final:build (default) on project account-service: Failed to build a runnable JAR: Failed to augment application classes: Build failure: Build failed due to errors

Please refer the following reported issue.

Run The Jenkins Pipelines

I store my Jenkinsfile together with the Quarkus project in source control system. So I just need to create a Jenkins Pipeline project, configure the SCM and Jenkinsfile.

Hit the Build Now link, the following shows the Jenkins GraalVM works charmingly.

[account-service-1.0.0-runner:380] classlist: 11,357.17 ms, 1.00 GB
[account-service-1.0.0-runner:380] (cap): 938.40 ms, 1.00 GB [account-service-1.0.0-runner:380] setup: 3,105.73 ms, 1.00 GB
05:11:56,245 INFO [org.jbo.threads] JBoss Threads version 3.0.0.Final
[account-service-1.0.0-runner:380] (typeflow): 200,313.92 ms, 1.60 GB [account-service-1.0.0-runner:380] (objects): 82,134.71 ms, 1.60 GB [account-service-1.0.0-runner:380] (features): 4,901.89 ms, 1.60 GB [account-service-1.0.0-runner:380] analysis: 295,631.20 ms, 1.60 GB
[account-service-1.0.0-runner:380] (clinit): 18,231.14 ms, 1.60 GB [account-service-1.0.0-runner:380] universe: 68,426.49 ms, 1.60 GB
[account-service-1.0.0-runner:380] (parse): 15,065.46 ms, 1.37 GB
[account-service-1.0.0-runner:380] (inline): 33,952.13 ms, 1.60 GB
[account-service-1.0.0-runner:380] (compile): 144,767.64 ms, 1.60 GB
[account-service-1.0.0-runner:380] compile: 210,844.86 ms, 1.60 GB
[account-service-1.0.0-runner:380] image: 12,034.72 ms, 1.60 GB
[account-service-1.0.0-runner:380] write: 3,546.19 ms, 1.60 GB [account-service-1.0.0-runner:380] [total]: 605,742.25 ms, 1.60 GB
[INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 610929ms [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 10:30 min [INFO] Finished at: 2020-03-23T05:21:46Z [INFO] ------------------------------------------------------------------------

More to Come

As part of GitOps architecture and process, the next step is to look into how to build the container image.

Subscribe to my blog and watch for more articles follow…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s