Quarkus and IBM Cloud Code Engine

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

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.

References

comment

Comments

arrow_back

Previous

Overview of Secret injection solutions

Next

Migrate from Docker to Podman on macOS
arrow_forward