Skip to main content
Redhat Developers  Logo
  • Products

    Featured

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat OpenShift AI
      Red Hat OpenShift AI
    • Red Hat Enterprise Linux AI
      Linux icon inside of a brain
    • Image mode for Red Hat Enterprise Linux
      RHEL image mode
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • Red Hat Developer Hub
      Developer Hub
    • View All Red Hat Products
    • Linux

      • Red Hat Enterprise Linux
      • Image mode for Red Hat Enterprise Linux
      • Red Hat Universal Base Images (UBI)
    • Java runtimes & frameworks

      • JBoss Enterprise Application Platform
      • Red Hat build of OpenJDK
    • Kubernetes

      • Red Hat OpenShift
      • Microsoft Azure Red Hat OpenShift
      • Red Hat OpenShift Virtualization
      • Red Hat OpenShift Lightspeed
    • Integration & App Connectivity

      • Red Hat Build of Apache Camel
      • Red Hat Service Interconnect
      • Red Hat Connectivity Link
    • AI/ML

      • Red Hat OpenShift AI
      • Red Hat Enterprise Linux AI
    • Automation

      • Red Hat Ansible Automation Platform
      • Red Hat Ansible Lightspeed
    • Developer tools

      • Red Hat Trusted Software Supply Chain
      • Podman Desktop
      • Red Hat OpenShift Dev Spaces
    • Developer Sandbox

      Developer Sandbox
      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Secure Development & Architectures

      • Security
      • Secure coding
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
      • View All Technologies
    • Start exploring in the Developer Sandbox for free

      sandbox graphic
      Try Red Hat's products and technologies without setup or configuration.
    • Try at no cost
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • Java
      Java icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • API Catalog
    • Product Documentation
    • Legacy Documentation
    • Red Hat Learning

      Learning image
      Boost your technical skills to expert-level with the help of interactive lessons offered by various Red Hat Learning programs.
    • Explore Red Hat Learning
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

4 ways to deploy Quarkus applications in OpenShift Container Platform 4

June 12, 2024
Francisco De Melo Junior Alexander Barbosa Ayala
Related topics:
DevOpsQuarkus
Related products:
Red Hat build of QuarkusRed Hat OpenShift Container Platform

Share:

    As explained in Deploying your Quarkus applications to OpenShift, there are several approaches for deploying in Red Hat OpenShift Container Platform (RHOCP) 4. Each situation might require different a approach from the ones listed in this article given different (project) requirements.

    When doing Quarkus builds for OpenShift, there are several approaches. One of the simplest is the Quarkus Maven plug-in, meaning that the usage of quarkus-openshift extension considerably facilitates the deployment.

    Either via pom.xml setting the following dependency:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-openshift</artifactId>
    </dependency>

    Or by adding the extension manually via the command line interface (CLI command) using the Maven Wrapper: 

    <-- Below has the latest Quarkus version -->
    ./mvnw com.redhat.quarkus.platform:quarkus-maven-plugin:3.8.4.redhat-00002:add-extension -Dextensions="io.quarkus:quarkus-openshift"

    Note that Quarkus 3+ should work with OpenJDK 17. Below is a full example using Quarkus CLI:

    $ cd quarkus-example
    ls
    mvnw  mvnw.cmd  pom.xml  README.md  src  target <--- this will be created on the build
    $ quarkus build -Dquarkus.openshift.deploy=true
    ...
    $ oc get is
    NAME                   IMAGE REPOSITORY                                                                                                                          UPDATED
    openjdk-17             registry.access.redhat.com/ubi8/openjdk-17                                         
    quarkus-example  image-registry.openshift-image-registry.svc:5000/quarkus-cli/openshift-quickstart
    ...
    $ oc get build
    NAME                     TYPE     FROM     STATUS     STARTED          DURATION
    quarkus-example-1   Source   Binary   Complete   10 minutes ago   35s
    ...
    $ oc get bc
    NAME                   TYPE     FROM     LATEST
    quarkus-example   Source   Binary   1 <------------- binary
    $ oc get pod
    NAME                            READY   STATUS      RESTARTS   AGE
    quarkus-example-1-8r2kw    1/1     Running     0          4m49s <--- application
    quarkus-example-build    0/1     Completed   0          5m27s <--- build

    Note that above, -Dquarkus.openshift.deploy=true  is equivalent to -Dquarkus.kubernetes.deployment-target=openshift plus -Dquarkus.kubernetes.deploy=true.

    Use the verbose details to verify the deployment in RHOCP 4:

    [INFO] [io.quarkus.container.image.openshift.deployment.OpenshiftProcessor] Applied: ImageStream openjdk-17
    [INFO] [io.quarkus.container.image.openshift.deployment.OpenshiftProcessor] Applied: ImageStream quarkus-example
    [INFO] [io.quarkus.container.image.openshift.deployment.OpenshiftProcessor] Applied: BuildConfig quarkus-example

    However, the source builds S2I cannot be done when, for instance, the Quarkus application already comes built as a JAR file. There are a few alternatives you can take to deploy an application in RHOCP 4. Three main options are presented below.

    • Build from source in the RHOCP pod: In this option, you provide the source and the pod build.
    • Inject the JAR: Build local and inject the resulting JAR: Those options you provide the jar/uber-JAR and the injection happens in an image.
      • a) Build local and inject the quarkus-app directory.
      • b) Build local and inject the uber-JAR jar.
    • Inject the JAR: Build local and inject the resulting JAR, but using Dockerfile (or Containerfile)

    Additionally, to have a complete and thorough post, I will also cover a Tekton alternative, which is presented in a very summarized approach and can inject the source or the JAR.

    Approach 1: Build from the source in the RHOCP pod

    The user provides the source for the build in the first option, and the build happens in OCP 4.

    The following is an example of creating a BuildConfig with the ImageStream as output, output-quarkus-sample:

    kind: BuildConfig
    apiVersion: build.openshift.io/v1
    metadata:
      name: quarkus-test-build
      namespace: quarkus
    spec:
      runPolicy: "Serial" 
      triggers: 
        - type: "GitHub"
          github:
            secret: "secret101"
        - type: "Generic"
          generic:
            secret: "secret101"
        - type: "ImageChange"
      source: 
        git:
          uri: https://github.com/FranciscoMeloJr/quarkus-tests.git
          ref: "main"
        contextDir: quarkus-tests
      strategy: 
        sourceStrategy:
          from:
            kind: ImageStreamTag
            namespace: openshift
            name: 'openjdk-11-runtime:1.16-1.1696518675'
      output: 
        to:
          kind: ImageStreamTag
          name: output-quarkus-sample:latest <--------------------------------- create this separated

    Approach 2: Binary input - Build local and inject the Quarkus application as binary, either as directory or uber-jar

    Approach 2a: Build local and inject the Quarkus application as a directory:

    In this option, the user provides the Quarkus application in a directory, such as the one below:

    $ pwd
    /path/quarkus-app
    $ls 
    app  lib  quarkus  quarkus-app-dependencies.txt  quarkus-run.jar

    Create namespace:

    # Create project
    $ oc new-project binaryopenjdk-scenario2a 
    $ oc project binaryopenjdk-scenario2a)
    # create no content directory:
    $ mkdir /tmp/nocontent

    Import image:

    $ oc import-image ubi8/openjdk-11:1.17-1.1693366250 --from=registry.access.redhat.com/ubi8/openjdk-11:1.17-1.1693366250 --confirm

    Create BuildConfig:

    $ oc new-app binaryopenjdk-scenario2a/openjdk-11:1.17-1.1693366250~/tmp/nocontent --name=example-jdk11-rhel7
    ...
    Java Applications 
        ----------------- 
        Platform for building and running plain Java applications (fat-jar and flat classpath)

    Start to build with JAR in the directory, which is sent as binary to the build.

    $ oc start-build example-jdk11-rhel7 --from-dir=./quarkus-app
    ...
    Uploading directory "quarkus-app" as binary input for the build ...
    build.build.openshift.io/example-jdk11-rhel7-2 started

    The above command specifies the directory: ./quarkus-app, which will be archived and used as a binary input for the build. This means it will do the build using the directory quarkus-app as input, after the BuildConfig is created. The deployed pod will have the complete directory inside /deployments:

    ### Result:
    $ oc get pod
    NAME                                   READY   STATUS      RESTARTS   AGE
    example-jdk11-rhel7-55         1/1     Running     0          80m
    [container]$ oc rsh example-jdk11-rhel7-55
    [container] cd /deployment; ls
    /app  /data  /lib  /quarkus  quarkus-app-dependencies.txt  quarkus-run.jar

    Approach 2b: Build local and inject the uber-JAR directly

    Build JAR:

    $ mvn clean package -Dquarkus.package.type=uber-jar

    Create namespace:

    $ oc new-project binaryopenjdk-scenario2b
    $ oc project binaryopenjdk-scenario2b
    # create no content directory:
    $ mkdir /tmp/nocontent

    Import image:

    $ oc import-image ubi8/openjdk-11:1.17-1.1693366250 --from=registry.access.redhat.com/ubi8/openjdk-11:1.17-1.1693366250 --confirm

    Create BuildConfig:

    $ oc new-app binaryopenjdk-scenario2b/openjdk-11:1.17-1.1693366250~/tmp/nocontent --name=example-jdk11-rhel7

    Start to build with JAR:

    $ oc start-build example-jdk11-rhel7 --from-file=./application-runner.jar
    Uploading file "application-runner.jar" as binary input for the build ...
    Uploading finished
    build.build.openshift.io/example-jdk11-rhel7-2 started

    The above command specifies the file: application-runner.jar, which will be used as a binary input for the build—only one file. This means it will do the build using only the jar application-runner.jar as input, after the BuildConfig is created.

    The deployed pod will contain only the binary jar deployed inside /deployments:

    ### Result:
    $ oc get pod
    NAME                                   READY   STATUS      RESTARTS   AGE
    example-jdk11-rhel7-21         1/1     Running     0          80m
    [container]$ oc rsh example-jdk11-rhel7-21
    [container] cd /deployment; ls
    /data  application-runner.jar

    Approach 3: Build locally and inject the resulting JAR using Dockerfile

    spec:
    nodeSelector: null
    output:
    to:
      kind: ImageStreamTag
      name: 'wget-app:latest'
    resources: {}
    successfulBuildsHistoryLimit: 5
    failedBuildsHistoryLimit: 5
    strategy:
    type: Docker
    dockerStrategy:
    from:
      kind: ImageStreamTag
      namespace: openshift
      name: 'openjdk-11:1.17-1.1693366250'
      postCommit: {}
    source:
      type: Dockerfile
    dockerfile: >-
      FROM registry.access.redhat.com/ubi8/openjdk-11:1.17-1.1693366250
      USER root
      RUN touch version.txt
      RUN echo 'Scenario 1p' > version.txt
      RUN mv version.txt $JBOSS_HOME/version.txt
      RUN microdnf -y install wget
      RUN microdnf -y install unzip
      RUN wget https://github.com/path/application/quarkus-app.zip -O quarkus-app.zip
      RUN mv quarkus-app.zip /deployments
      RUN unzip /deployments/quarkus-app.zip -d /deployments
      RUN ls /deployments/
      CMD ["java","-jar","/deployments/quarkus-app/quarkus-run.jar"]
    runPolicy: Serial

    That possibility is listed as an alternative on the S2I OpenShift possibilities as inject the JAR.

    Do not try to run the runner JAR as an uber-JAR, as it won’t work:

    $ java -jar quarkus-run.jar 
    Error: Could not find or load main class io.quarkus.bootstrap.runner.QuarkusEntryPoint
    Caused by: java.lang.ClassNotFoundException: io.quarkus.bootstrap.runner.QuarkusEntryPoint

    An additional approach: Using Tekton build

    For RHOCP 4 builds with Tekton, after installing the OpenShift Pipelines Operator, follow the steps below.

    You can build a pipeline by calling a few simple tasks such as below:

    apiVersion: tekton.dev/v1beta1
    kind: Pipeline
    metadata:
      labels:
        app.kubernetes.io/instance: test-and-build-pipeline
        pipeline.openshift.io/type: quarkus-example-tekton
      name: test-and-build-reproducer
      namespace: quarkus-example-tekton
    spec:
      workspaces:
        - name: shared-workspace
        - name: maven-settings
      params:
      - name: image-tag
        type: string
        default: "latest"
      - name: repo-url
        description: The source repository's url
        type: string
        default: "https://github.com/example/quarkus-application.git"
      - name: app-dir
        type: string
        default: "app"
      tasks:
      - name: task-execute
        taskRef:
          name: execute-maven-task
          kind: Task
        runAfter:
          - fetch-app-source
        params:
          - name: GOALS
            value: 
              - verify
          - name: CONTEXT_DIR
            value: "$(params.app-dir)"
        workspaces:
          - name: maven-settings
            workspace: maven-settings
          - name: source
            workspace: shared-workspace
      - name: build-service
        taskRef:
          name: execute-maven-task
          kind: Task
        runAfter:
          - test-service
        params:
        - name: GOALS
          value:
            - package
            - "-Dmaven.test.skip=true"
        - name: CONTEXT_DIR
          value: "$(params.app-dir)"
        workspaces:
        - name: source
          workspace: shared-workspace
        - name: maven-settings
          workspace: maven-settings
    ...
    ...
    apiVersion: tekton.dev/v1beta1
    kind: Task
    metadata:
      name: execute-maven-task
    spec:
      description: This Task can be used to run a Maven build.
      params:
        - default: >-
            registry.redhat.io/ubi8/openjdk-17@sha256:0d12c4097e098b62f78a7a31c0d711d78e1e5a53f4c007b9a5fc6cc6ab4dc018
          description: Maven base image
          name: MAVEN_IMAGE
          type: string
        - default:
          - package
          description: maven goals to run
          name: GOALS
          type: array
        - default: ''
          description: The Maven repository mirror url
          name: MAVEN_MIRROR_URL
          type: string
      steps:
        - image: 'registry.access.redhat.com/ubi8/ubi-minimal:8.2'
          name: mvn-settings
          resources: {}
          script: >
            #!/usr/bin/env bash
            [[ -f $(workspaces.maven-settings.path)/settings.xml ]] && \
            exit 0
           apiVersion: tekton.dev/v1beta1
    ...
    ...
    kind: Task
    metadata:
      name: get-source-with-git
    spec:
      stepTemplate:
        name: "tekton-home-dir"
        env:
          - name: "HOME"
            value: "/tekton/home"
      params:
        - name: repo-url
          description: The source repository's url (http|ssh)
          type: string
          default: "<changeme>"
        - name: image-tag
          description: Git commit id to be cloned
          type: string
          default: ""
        - name: app-dir
          description: application directory
          type: string
          default: "app"
        - name: GIT_BASE_IMAGE
          description: The git base image
          type: string
          default: registry.redhat.io/openshift-pipelines/pipelines-git-init-rhel8@sha256:89fc179cd82c8ddf010af89213d3f2..
      workspaces:
        - name: source
          description: The git repo will be cloned onto the volume backing this Workspace.
      steps:
        - name: git-clone
          workingDir: /workspace
          image: $(params.GIT_BASE_IMAGE)
          script: |
            #!/usr/bin/env sh
            set -eu
    
            if [[ -d $(workspaces.source.path)/$(params.app-dir) ]]; then
              rm -rf "$(workspaces.source.path)/$(params.app-dir)"
            fi
    
            git config --global --add safe.directory "$(workspaces.source.path)/$(params.app-dir)"
            git clone $(params.repo-url) $(workspaces.source.path)/$(params.app-dir)
            cd $(workspaces.source.path)/$(params.app-dir)
            git reset --hard $(params.image-tag)
            git filter-branch --subdirectory-filter quarkus

    The generic example above, i.e., this approach, can be generalized for any build in Tekton given that the only part that differs is the use of the Quarkus plug-in in the Maven build in the pom.xml.

    In summary, we have the following options:

    ApproachRequirements
    Build from the source in OCP BuildConfigUser needs to have the source
    Build local and inject: jarUser needs to be able to build the application locally
    Build local and inject: uber-jarUser needs to be able to build the application as uber-jar 
    Build local and inject jar via Dockerfile buildUser needs to be able to build the application locally and make OCP 4 fetch it
    Build in OCP 4 using TektonUser needs to have the source and knowledge on Tekton for the build 

    Additional resources

    The examples above are straightforward and do not have a multi-stage build or a pre-build image (for instance, a pre-build image to be consumed by Tekton), and this was done on purpose to simplify the explanation. Naturally, BuildConfig and Tekton can have complex pipelines including multi-stage builds and on-the-fly addition/injections.

    Also, as a disclaimer, the Images' Tags might be outdated depending on the publication of this article.

    To learn more, read Deploying your Quarkus applications to OpenShift.

    Finally, for monitoring, see about options on quarkus.io such as JFR and collecting heap files, e.g., for native builds: -Dquarkus.native.monitoring=jfr, heapdump.

    For any other specific inquiries and issues, please open a case with Red Hat support. Our global team of experts JVM team and Shift-DevOps can help you with any issues.

    Special thanks to Jordan Bell for his input and contributions on Tekton/Shift build issues.

    Related Posts

    • Red Hat OpenShift Container Platform Load Testing Tips

    • Deploy Red Hat AMQ Streams and Fuse on OpenShift Container Platform 4

    • Wiping the Slate Clean with the OpenShift Container Platform

    • Supersonic, Subatomic gRPC services with Java and Quarkus

    • Securely connect Quarkus and Red Hat Data Grid on Red Hat OpenShift

    • Getting started with Tekton on Red Hat OpenShift

    Recent Posts

    • Storage considerations for OpenShift Virtualization

    • Upgrade from OpenShift Service Mesh 2.6 to 3.0 with Kiali

    • EE Builder with Ansible Automation Platform on OpenShift

    • How to debug confidential containers securely

    • Announcing self-service access to Red Hat Enterprise Linux for Business Developers

    What’s up next?

    Learn how to deploy and update a distributed application on-the-fly using OpenShift Dev Spaces and Eclipse JKube in this Learning Path.

    Start the activity
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2025 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue