Quarkus and IBM Cloud Code Engine
Published on 11/09/2021
10 min read
In category
development
Quarkus is one of the famous framework for modern Kubernetes native solutions. IBM Cloud Code Engine is the managed offering for serverless platforms. Let's bring this together and build and run a Quarkus application with IBM Cloud Code Engine.
Overview
IBM Cloud Code Engine provides with a managed Kubernetes environment the possibility to build and run applications and jobs in the serverless manner. Explanation of the features and more details are published in the [docu and getting started]](https://cloud.ibm.com/docs/codeengine). Due the fact, that the workload is running in a Kubernetes environment is container image the base artifact. IBM Cloud Code Engine (CE) supports the workflow to build an image from source code using a Dockerfile or with the Buildpacks and afterwards to create and publish an application from this image. In addition all configurations for how to deploy, routing, access and how/when to scale is part of the serverless solution, here IBM Cloud Code Engine. The managed Kubernetes environment is a secured multi-tenant isolated environment with Knative, Istio and much more capabilities, details are explained in the architectural docu.
The workflow to build and publish of an app will be explained with the help of a Quarkus application.
The following walkthrough will
- builds the Quarkus application using the given Dockerfile
- pushes the new container image to the internal Container Registry of IBM Cloud
- creates and publishes an application from the container image
Preparation
For the walkthrough a Quarkus application is needed, with a Dockerfile to build and package the application. The Dockerfile strategy is here selected, even IBM Cloud Code Engine supports Cloud Native Buildpacks. But Cloud Native Buildpacks/Paketo does not support currently the Quarkus framework.
For this reason a multi-stage Dockerfile will be used, which builds in the first stage the application and afterwards the container holding the runtime and resulting application.
Dockerfile.jvm_multi...
FROM docker.io/adoptopenjdk/maven-openjdk11 as BUILD
COPY src /usr/src/app/src
COPY ./pom.xml /usr/src/app
WORKDIR /usr/src/app
RUN mvn package -Dmaven.test.skip=true
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4
ARG JAVA_PACKAGE=java-11-openjdk-headless
ARG RUN_JAVA_VERSION=1.3.8
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
# Install java and the run-java script
# Also set up permissions for user `1001`
RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
&& microdnf update \
&& microdnf clean all \
&& mkdir /deployments \
&& chown 1001 /deployments \
&& chmod "g+rwX" /deployments \
&& chown 1001:root /deployments \
&& curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
&& chown 1001 /deployments/run-java.sh \
&& chmod 540 /deployments/run-java.sh \
&& echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/conf/security/java.security
# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --from=BUILD /usr/src/app/target/quarkus-app/lib/ /deployments/lib/
COPY --from=BUILD /usr/src/app/target/quarkus-app/*.jar /deployments/
COPY --from=BUILD /usr/src/app/target/quarkus-app/app/ /deployments/app/
COPY --from=BUILD /usr/src/app/target/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080
USER 1001
ENTRYPOINT [ "/deployments/run-java.sh" ]
The Dockerfile is used in the build step of CE.
Code Engine Walkthrough
The following walkthrough will guide how to build and publish the application using the GitHub repository and Dockerfile.
-
use IBM Cloud Code Engine
- Set some constraints like region
-r
and resource group-g
- create a Code Engine (ce) project (here:
demo-ce
) - create API Key to use for Container Registry access (see link:https://cloud.ibm.com/docs/codeengine?topic=codeengine-deploy-app-crimage#deploy-app-crimage-cli[docu])
- create registry secret from the API Key
- create a build config named
demo-ce-quarkus-build
using Dockerfile strategy - create a build run from the build config, which package and publish container image
- create a secret holding information which will be exposed as environment variables to the app
- create an application from the generated container image
- Set some constraints like region
The result is a running application reachable via a publicly accessible URL.
# Set region and a custom resource group
ibmcloud target -r eu-de
ibmcloud target -g rg-demo-ce
# #### Code Engine specific
# Create a project
ibmcloud ce project create --name demo-ce
Creating project 'demo-ce'...
ID for project 'demo-ce' is '47459f93-6284-4dde-b473-de6ce9720a62'.
Waiting for project 'demo-ce' to be active...
Now selecting project 'demo-ce'.
OK
# ...or select an existing project
ibmcloud ce project select -n demo-ce
Selecting project 'demo-ce'...
OK
# Create API Key which will be used for working with container registry
ibmcloud iam api-key-create own-api-key -d "Demo CE API Key" --file key_file
# Create a registry secret to push the generated images in
ibmcloud ce registry create --name demo-ce-registry-secret --server de.icr.io --username iamapikey
# Create a build configuration using Buildpacks (not available for Quarkus yet)
ibmcloud ce build create --name demo-ce-quarkus-build --image de.icr.io/demo-ce/quarkus-playground:latest --registry-secret demo-ce-registry-secret --source https://github.com/haf-tech/quarkus-playground --strategy buildpacks
# Create a build configuration using Dockerfile
ibmcloud ce build create --name demo-ce-quarkus-build --image de.icr.io/demo-ce/quarkus-playground:latest --registry-secret demo-ce-registry-secret --source https://github.com/haf-tech/quarkus-playground --strategy dockerfile --dockerfile src/main/docker/Dockerfile.jvm_multi
# Check build config and details
ibmcloud ce build list
Listing builds...
OK
Name Status Reason Image Build Strategy Age Last Build Run Name Last Build Run Age
demo-ce-quarkus-build Succeeded all validations succeeded de.icr.io/demo-ce/quarkus-playground:latest dockerfile-medium 6d demo-ce-quarkus-build-run-210911-151208098 4h58m
ibmcloud ce build get --name demo-ce-quarkus-build
Getting build 'demo-ce-quarkus-build'
OK
Name: demo-ce-quarkus-build
ID: ff174f37-0e54-4b22-aaa5-2d34860fa179
Project Name: demo-ce
Project ID: 1ae76b8e-1750-4b1a-8ad8-df0e1c5301ed
Age: 6d
Created: 2021-09-05T19:52:05Z
Status: Succeeded
Reason: all validations succeeded
Last Build Run:
Name: demo-ce-quarkus-build-run-210911-151208098
Age: 4h59m
Created: 2021-09-11T15:12:13Z
Image: de.icr.io/demo-ce/quarkus-playground:latest
Registry Secret: demo-ce-registry-secret
Build Strategy: dockerfile-medium
Timeout: 10m0s
Source: https://github.com/haf-tech/quarkus-playground
Commit: main
Dockerfile: src/main/docker/Dockerfile.jvm_multi
Build Runs:
Name Status Image Age
demo-ce-quarkus-build-run-210911-151208098 All Steps have completed executing de.icr.io/demo-ce/quarkus-playground:latest 4h59m
# Create a build run from the build configuration
ibmcloud ce buildrun submit --build demo-ce-quarkus-build
# Details of build run
ibmcloud ce buildrun list
Listing build runs...
OK
Name Status Image Build Name Age
demo-ce-quarkus-build-run-210905-17420916 Failed de.icr.io/demo-ce/quarkus-playground:latest demo-ce-quarkus-build 42s
ibmcloud ce buildrun get --name demo-ce-quarkus-build-run-210905-17420916
Getting build run 'demo-ce-quarkus-build-run-210905-17420916'...
OK
Name: demo-ce-quarkus-build-run-210905-17420916
ID: e84ce96f-481a-4fa3-b3ed-818106578586
Project Name: demo-ce
Project ID: 1ae76b8e-1750-4b1a-8ad8-df0e1c5301ed
Age: 100s
Created: 2021-09-05T17:42:09Z
Summary: Failed to execute build run
Status: Failed
Reason: BuildRun failed to build and push the container image, for detailed information: 'ibmcloud ce buildrun logs -n demo-ce-quarkus-build-run-210905-17420916', for troubleshooting information visit: https://cloud.ibm.com/docs/codeengine?topic=codeengine-troubleshoot-build#ts-build-bldpush-stepfail
Image: de.icr.io/demo-ce/quarkus-playground:latest
# ...see if status is Succeeded
ibmcloud ce buildrun list
Listing build runs...
OK
Name Status Image Build Name Age
demo-ce-quarkus-build-run-210905-17420916 Failed de.icr.io/demo-ce/quarkus-playground:latest demo-ce-quarkus-build 50m
demo-ce-quarkus-build-run-210905-182716641 Succeeded de.icr.io/demo-ce/quarkus-playground:latest demo-ce-quarkus-build 4m57s
# ...again details of the build run
ibmcloud ce buildrun get --name demo-ce-quarkus-build-run-210905-182716641
Getting build run 'demo-ce-quarkus-build-run-210905-182716641'...
OK
Name: demo-ce-quarkus-build-run-210905-182716641
ID: 180042fd-7db1-4a34-b4f1-b809f1f7e414
Project Name: demo-ce
Project ID: 1ae76b8e-1750-4b1a-8ad8-df0e1c5301ed
Age: 5m47s
Created: 2021-09-05T18:27:16Z
Summary: Succeeded
Status: Succeeded
Reason: All Steps have completed executing
Image: de.icr.io/demo-ce/quarkus-playground:latest
# Create a secret with the relevant configuration which will be injected as env variables to the app
vi secrets_multi.txt
ibmcloud ce secret create --name demo-ce-quarkus-secret --from-env-file secrets_multi.txt
Creating generic secret 'demo-ce-quarkus-secret'...
OK
# Create an app from the image
ibmcloud ce application create --name demo-ce-quarkus \
--image de.icr.io/demo-ce/quarkus-playground:latest --registry-secret demo-ce-registry-secret \
--min-scale 0 --max-scale 3 \
--cpu 0.25 --memory 0.5G \
--concurrency 10 \
--port 8080 \
--env-from-secret demo-ce-quarkus-secret
Creating application 'demo-ce-quarkus'...
The Route is still working to reflect the latest desired specification.
Configuration 'demo-ce-quarkus' is waiting for a Revision to become ready.
Ingress has not yet been reconciled.
Waiting for load balancer to be ready.
Run 'ibmcloud ce application get -n demo-ce-quarkus' to check the application status.
OK
https://demo-ce-quarkus.e19mnwb24sf.eu-de.codeengine.appdomain.cloud
This results in an application with 0 running instances. The first request of the exposed URL will start the application. Before the first request, follow the logs of the application and observe how the first request will start the application.
ibmcloud ce app logs -f -n demo-ce-quarkus
Getting logs for all instances of application 'demo-ce-quarkus'...
OK
demo-ce-quarkus-00007-deployment-665867c88f-2fmf5/user-container: exec java -Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager -XX:+ExitOnOutOfMemoryError -cp . -jar /deployments/quarkus-run.jar
...
After a few minutes without requests the workload will be automatically scaled down. For details and also config parameters consult the docu about scaling.
Excursus: Simple CI/CD with GitHub Actions
Currently IBM Cloud Code Engine does not support a trigger to update a build configuration and start a new BuildRun, however this feature is in development, stay tuned.
In order to achieve an intermediate solution GitHub Action is used. Every push to a branch/tag triggers a new workflow run with at minimum following steps
- Install tooling (IBM Cloud CLI and plugins)
-
IBM Cloud Code Engine specific steps
- Prepare project
- create or update build configuration
- submit a new BuildRun
- create or update application
- clean up
The definition of the workflow is published in the GitHub repository of the exemplary application.
Ecosystem
IBM Cloud Code Engine offers many more features than have been listed here, like cron jobs, events & subscriptions. Also the offerings is well integrated in the ecosystem of IBM Cloud like Logging, Monitoring or Cloud Object Storage.
Summary
In the event one does not want to manage infrastructure, storage, server and/or runtime than is a serverless offering an option. IBM Cloud Code Engine is one of the managed serverless offering on the cloud market. With few steps is it possible deploy and publish a Quarkus application - without modification in source code or neither create runtime configuration nor Kubernetes specific configurations. The offering provides all the feature to build and publish, routing and exposing access, scale up and down - so that one can totally focus on business needs, on the source code.