Skip to main content
Redhat Developers  Logo
  • AI

    Get started with AI

    • Red Hat AI
      Accelerate the development and deployment of enterprise AI solutions.
    • AI learning hub
      Explore learning materials and tools, organized by task.
    • AI interactive demos
      Click through scenarios with Red Hat AI, including training LLMs and more.
    • AI/ML learning paths
      Expand your OpenShift AI knowledge using these learning resources.
    • AI quickstarts
      Focused AI use cases designed for fast deployment on Red Hat AI platforms.
    • No-cost AI training
      Foundational Red Hat AI training.

    Featured resources

    • OpenShift AI learning
    • Open source AI for developers
    • AI product application development
    • Open source-powered AI/ML for hybrid cloud
    • AI and Node.js cheat sheet

    Red Hat AI Factory with NVIDIA

    • Red Hat AI Factory with NVIDIA is a co-engineered, enterprise-grade AI solution for building, deploying, and managing AI at scale across hybrid cloud environments.
    • Explore the solution
  • Learn

    Self-guided

    • Documentation
      Find answers, get step-by-step guidance, and learn how to use Red Hat products.
    • Learning paths
      Explore curated walkthroughs for common development tasks.
    • Guided learning
      Receive custom learning paths powered by our AI assistant.
    • See all learning

    Hands-on

    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.
    • Interactive labs
      Learn by doing in these hands-on, browser-based experiences.
    • Interactive demos
      Click through product features in these guided tours.

    Browse by topic

    • AI/ML
    • Automation
    • Java
    • Kubernetes
    • Linux
    • See all topics

    Training & certifications

    • Courses and exams
    • Certifications
    • Skills assessments
    • Red Hat Academy
    • Learning subscription
    • Explore training
  • Build

    Get started

    • Red Hat build of Podman Desktop
      A downloadable, local development hub to experiment with our products and builds.
    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.

    Download products

    • Access product downloads to start building and testing right away.
    • Red Hat Enterprise Linux
    • Red Hat AI
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat Developer Toolset

    References

    • E-books
    • Documentation
    • Cheat sheets
    • Architecture center
  • Community

    Get involved

    • Events
    • Live AI events
    • Red Hat Summit
    • Red Hat Accelerators
    • Community discussions

    Follow along

    • Articles & blogs
    • Developer newsletter
    • Videos
    • Github

    Get help

    • Customer service
    • Customer support
    • Regional contacts
    • Find a partner

    Join the Red Hat Developer program

    • Download Red Hat products and project builds, access support documentation, learning content, and more.
    • Explore the benefits

Ramp up on Quarkus: A Kubernetes-native Java framework

April 24, 2020
Saharsh Singh
Related topics:
JavaKubernetesQuarkus
Related products:
Red Hat build of OpenJDKRed Hat build of QuarkusRed Hat JBoss Enterprise Application Platform

    Java has been in a bit of an awkward spot since containers took off a few years ago. In the world of Kubernetes, microservices, and serverless, it has been getting harder and harder to ignore that Java applications are, by today’s standards, bloated. Well, until now. In this article, I explore the basics of Quarkus, a Kubernetes-native Java framework built to specifically address Java’s bloatedness problem.

    Java of yore

    For years, many of us looked the other way when confronted with the bloatedness of Java. Who cares if my server-side app:

    • Needed hundreds of megabytes worth of class files.
    • Created gigabytes worth of runtime memory footprint.
    • Took up to a minute (or five) to start up.

    I definitely didn’t care, because my Java application would then run reliably on a powerful piece of hardware or virtual machine for months, if not years, serving hundreds of requests concurrently. Not to mention, as a language, Java gave organizations pretty much everything they needed to maintain software for a long time using a large team of professionals with varying levels of skills.

    The Java Virtual Machine (JVM) has long promised and been delivered as a "write once, run (almost) anywhere" platform. Type safety, object-oriented programming support, and an unrivaled set of options in tooling and libraries have long made Java an excellent choice for team-based software development. Further, with enterprise-grade application servers (for example, EAP, WebLogic, and Tomcat), organizations also had a resilient and feature-rich platform for their Java web applications. These applications simply needed to comply with JavaEE standards around describing deployment concerns (think web.xml).

    Any JavaEE-compliant application server would then take care of operational concerns like security, logging, connecting to databases/queues, and scaling. It’s no surprise that for years Java has dominated the programming language landscape as the de facto standard for the enterprise.

    Kubernetes: The new application server

    It has been observed before that Kubernetes is the new application server. Containers and Kubernetes have taken the "write once run anywhere" paradigm of the JVM and extended it to most other programming languages. Now applications written in any language can leverage Kubernetes for operational concerns and decouple themselves from runtime infrastructure. These applications just have to be delivered in compliant Linux containers.

    With this structure in place, developers can code their applications in their favorite programming language and count on Kubernetes to handle operational concerns like logging, scaling, healing, and networking. Add in the Istio service mesh and you even have out-of-box fault tolerance and application-level metrics without a single line of application code. Today we find ourselves in a tech landscape that overwhelmingly prefers horizontal scaling of automated cattle over vertical scaling of manually cared for pets. Microservices and serverless/Function-as-a-Service (FaaS) applications have become all the rage, and both benefit greatly from low memory footprints and blazing-fast startup times.

    So, with all of this said, it becomes increasingly harder to ignore that my Java container images are even larger in size as well as memory footprint, and they take quite a bit longer to start up, especially when compared to a language like Golang. Modern cloud-native frameworks like Spring Boot or Dropwizard have helped, but startup times are still at least 10 seconds or more, and runtime memory footprint is at least in the hundreds of megabytes.

    Enter Quarkus

    Quarkus aims to tackle the bloatedness problem of Java head-on. Marketed as Supersonic Subatomic Java, Quarkus leverages GraalVM and HotSpot to provide developers with a framework to create applications from Java code with fast boot times and low RSS memory. The following figure from quarkus.io does a good job illustrating the benefits. Notice the drastic difference in both RSS memory and boot time between Quarkus native and the traditional cloud-native stack.

    Screen showing Quarkus metrics

    Source: ">

    OpenJDK and GraalVM

    As evident from the figure above, Quarkus has two modes: JVM and native. The native mode uses GraalVM to create a standalone executable that doesn’t run in a Java VM, and the greatest efficiency gains come from running a Quarkus application in this mode. However, not every JVM feature works in native mode, and the most notorious of these lost features is reflection.

    This fact can be a huge problem as many frameworks and libraries that Java developers depend on for everyday development rely heavily on reflection. GraalVM works around this by allowing classes to be registered for reflection at compile time. While this process can be cumbersome when working directly with GraalVM, Quarkus streamlines the registration process by detecting and auto-registering as many of your code’s reflection candidates as possible.

    While Quarkus does a pretty good job with auto-registering most reflection candidates, you might still run into instances where you have to explicitly register some of your classes using Quarkus’s RegisterForReflection annotation. This process might become more trouble than it's worth in some projects. For this reason, as well as just general flexibility, Quarkus also offers the JVM mode. In JVM mode, Quarkus apps are packaged as JAR files and run on the OpenJDK HotSpot JVM.

    Show me the code!

    So having set the stage, let’s look at some code. To get started with Quarkus, I put together a JAX-RS application following the excellent getting started guides from Quarkus. See my repo for the application's code. This application is a simple service that can be used to store, update, retrieve, and delete arbitrary text values. I mostly just followed the guide as I wrote my code. I built the application out in the following stages.

    Core application

    In this stage, I created the core application with all the API endpoints. I started by generating an app skeleton using the quarkus-maven-plugin and adding the resteasy-jackson extension for JSON support:

    mvn io.quarkus:quarkus-maven-plugin:1.3.2.Final:create \
        -DprojectGroupId=org.saharsh \
        -DprojectArtifactId=sample-quarkus-app \
        -DclassName="org.saharsh.samples.quarkus.resources.ValuesResource" \
        -Dpath="/api/values"
    
    mvn quarkus:add-extension -Dextensions="resteasy-jackson"

    Some changes I made include getting rid of .dockerignore and the Dockerfile examples generated by the quarkus-maven-plugin's create task. Instead, I prefer to use a multi-stage Dockerfile (see JVM and Native) to keep my build concerns in one file. After this, I just added my application code as captured in this tag (or commit).

    Metrics and health checks

    Metrics and health checks are crucial in creating twelve-factor applications. Quarkus leverages Microprofile, which makes adding these features pretty straightforward:

    mvn quarkus:add-extension -Dextensions="metrics"

    See this tag (and commit) for the metrics I added for the application. My application collects timing metrics for all of its exposed API endpoints. It also contains a gauge of the value store’s size. These metrics are published at the /metrics endpoint, which contains base, vendor, and application metrics. Each one of those subgroups also has its own endpoint (for example, /metrics/application):

    mvn quarkus:add-extension -Dextensions="health"

    Similarly, see this tag (and commit) for the health checks. I added a liveness check and a readiness check. The /health endpoint can be accessed for all health checks aggregated into one. However, you typically separate these into liveness and readiness probes. For this reason, /health/live and /health/ready endpoints are also automatically provided.

    Persistence

    The core app I put together in the first stage uses an in-memory storage service. This means that the storage is local to each instance of the application and gets wiped when that instance goes down. To build an actual stateless application that can be scaled up and have persistent storage, let’s offload the application state to a MySQL database:

    mvn quarkus:add-extension -Dextensions="hibernate-orm,jdbc-mysql"

    See this tag (and commit) for changes related to persistence. The highlights are:

    • Making zero code changes to switch to persistent mode because my resource class depends on the StorageService interface abstraction.
    • Picking my storage service implementation at runtime lets me introduce three things:
      • A sample.storage.type property.
      • A producer class to create the right bean based on the property.
      • A Qualifier annotation (ConfiguredStorage) for my resource class to specify that it intends to use the bean produced by the producer class.
    • Leveraging the application.properties pattern to use in-memory storage as the default storage type.

    For this last one, I intend to use environment variables to override these properties and switch over to persistent storage. There is one catch, however. Quarkus does much of its configuration and bootstrap at build time. Most properties will then be read and set during the build-time step. To change them, make sure to repackage your application. In my application.properties file, quarkus.hibernate-orm.dialect, quarkus.datasource.driver, and quarkus.datasource.health.enabled cannot be overridden at runtime. The good news is that the rest can.

    And that’s it

    I have a couple more commits around adding native build support and documentation. However, the application is ready to go. My repo's README.md does a good job of walking through the details of building and running this application locally. You can use the following steps as a reference for running the application on Red Hat OpenShift or Red Hat CodeReady Containers:

    # Create a new project
    oc new-project samples
    
    # Standup MySQL
    oc new-app --name=valuesdb  mysql-ephemeral \
        -p DATABASE_SERVICE_NAME=valuesdb \
        -p MYSQL_ROOT_PASSWORD=password \
        -p MYSQL_USER=valsuser \
        -p MYSQL_PASSWORD=password \
        -p MYSQL_DATABASE=valsdb
    
    # Create the application schema in MySQL
    oc rsh valuesdb-1-[pod_id] bash -c "mysql -uvalsuser -ppassword valsdb"
    mysql> CREATE TABLE vals (
        id BIGINT AUTO_INCREMENT PRIMARY KEY,
        value VARCHAR(255) NOT NULL,
        date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    );
    
    # Create API application from Github repo
    oc new-app --name valuesapi https://github.com/saharsh-samples/sample-quarkus-app
    
    # Expose a route
    oc expose svc/valuesapi && oc get routes
    
    # To use persistent storage, first create a secret containing DB configuration
    oc create secret generic valuesapi-properties \
        --from-literal=SAMPLE_STORAGE_TYPE=persistent \
        --from-literal=QUARKUS_DATASOURCE_URL="jdbc:mysql://valuesdb/valsdb" \
        --from-literal=QUARKUS_DATASOURCE_USERNAME=valsuser \
        --from-literal=QUARKUS_DATASOURCE_PASSWORD=password
    
    # Turn the fields of the secret into environment variables for the API app
    oc set env dc/valuesapi --from=secret/valuesapi-properties
    
    # Add liveness and readiness probes
    oc set probe dc/valuesapi --liveness --get-url=http://:8080/health/live
    oc set probe dc/valuesapi --readiness --get-url=http://:8080/health/ready

    Conclusion

    Quarkus is an exciting new development in the Java ecosystem. I will make sure to share more articles and code as I explore Quarkus in relation to serverless architecture, reactive programming, and Kafka. In the meantime, check out the following links to dig deeper:

    • Official Quarkus website
    • Official Quarkus GitHub
    • Quarkus FAQ
    • Why GraalVM?
    Last updated: February 11, 2024

    Recent Posts

    • Protect data offloaded to GPU-accelerated environments with OpenShift sandboxed containers

    • Case study: Measuring energy efficiency on the x64 platform

    • How to prevent AI inference stack silent failures

    • Preventing GPU waste: A guide to JIT checkpointing with Kubeflow Trainer on OpenShift AI

    • How to manage TLS certificates used by OpenShift GitOps operator

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    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
    © 2026 Red Hat

    Red Hat legal and privacy links

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

    Chat Support

    Please log in with your Red Hat account to access chat support.