Quarkus logo

    As immutable infrastructure was starting to hit its stride four or five years ago, one question Java developers were struggling with was: "How do my microservices have to be optimized in Linux container architecture like faster startup and smaller memory footprint?"

    There were a number of limitations to transforming container-native, microservices-based Java technology at the time. One major reason was that the traditional cloud Java stack had to process most of the required tasks, such as annotation scanning, parsing descriptors at runtime rather than build time, until Quarkus came along.

    Quarkus is a Kubernetes-native Java stack tailored for GraalVM and OpenJDK HotSpot. It’s crafted from best-of-breed Java libraries and standards with the following benefits:

    • A cohesive platform for optimized developer joy
      • Live coding and unified configuration
      • No-hassle native executable generation
    • Container-first and Kubernetes-native Java stack
      • Superfast to startup (i.e., 0.055 Seconds for REST + CRUD)
      • Small memory footprint (i.e., 35 MB for REST + CRUD)
    • Unifies Imperative and Reactive development in the same application
      • Inject the EventBus or the Vertx context
      • Use the technology that fits your use-case
      • Key for reactive systems based on event driven apps
    • Extensions for the latest popular open source projects
    Open source logos

    Start coding

    Let’s get started to develop a simple microservice application to expose the REST endpoint from scratch.

    Bootstrapping the project

    Go to Start Coding page in Quarkus.io to bootstrap the first Quarkus application using RESTEasy JAX-RS and REST Clients Extensions:

    Screenshot of steps

    It generates a ZIP file with:

    • The Maven structure
    • An org.acme.ExampleResource resource exposed on /hello
    • An associated unit test
    • A landing page that is accessible on http://localhost:8080 after starting the application
    • Example Dockerfile files for both native and jvm modes
    • The application configuration file

    Unzip and review skeleton codes via your preferred IDE (i.e., VSCode) like:

    unzip code-with-quarkus.zip && cd code-with-quarkus
    code .

    Once you’ve opened an IDE, look at the pom.xml. You will find the import of the Quarkus BOM, allowing you to omit the version on the different Quarkus dependencies. Additionally, you can see the quarkus-maven-plugin responsible for the packaging of the application and for providing the development mode.

    You can see the quarkus-maven-plugin responsible for the packaging of the application and for providing the development mode.

    Running the application using development mode

    To run the application, you need:

    • JDK 1.8+ installed with JAVA_HOME configured appropriately
    • Apache Maven 3.5.3+

    Now you are ready to run your application. Use: mvn compile quarkus:dev:

    INFO] Scanning for projects...
    INFO] ---------------------< org.acme:code-with-quarkus >---------------------
    [INFO] Building code-with-quarkus 1.0.0-SNAPSHOT
    [INFO] --------------------------------[ jar ]---------------------------------
    [INFO] 
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ code-with-quarkus ---
    [INFO] Using 'UTF-8' encoding to copy filtered resources.
    [INFO] Copying 2 resources
    [INFO] 
    [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ code-with-quarkus ---
    [INFO] Nothing to compile - all classes are up to date
    [INFO] 
    [INFO] --- quarkus-maven-plugin:1.0.0.CR1:dev (default-cli) @ code-with-quarkus ---
    Listening for transport dt_socket at address: 5005
    2019-11-09 08:03:20,900 INFO  [io.qua.dep.QuarkusAugmentor] (main) Beginning quarkus augmentation
    2019-11-09 08:03:21,685 INFO  [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed in 785ms
    2019-11-09 08:03:22,125 INFO  [io.quarkus] (main) Quarkus 1.0.0.CR1 started in 1.364s. Listening on: http://0.0.0.0:8080
    2019-11-09 08:03:22,126 INFO  [io.quarkus] (main) Profile dev activated. Live Coding activated.
    2019-11-09 08:03:22,126 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]
    

    Once the application has started, open a web browser to request the provided endpoint: http://localhost:8080/hello

    Once started, open a web browser to request the provided endpoint:  http://localhost:8080/hello

    Change codes

    Modify the return string to “Welcome, Quarkus Cheat Sheet” in hello() method. Remember to save the file:

    public String hello() {
        return "Welcome, Quarkus Cheat Sheet";
    }

    Go back to the web browser then reload the page. The application will be redeployed magically without restarting the runtime:

    The application will be redeployed magically without restarting the runtime.

    Hit CTRL+C to stop the application, but you can also keep it running and enjoy the blazing fast hot-reload.

    Packaging and run the application

    The application is packaged using mvn clean package -DskipTests. It produces two jar files:

    • code-with-quarkus-1.0.0-SNAPSHOT.jar: Containing just the classes and resources of the projects, it’s the regular artifact produced by the Maven build.
    • code-with-quarkus-1.0.0-SNAPSHOT-runner.jar: An executable jar. Be aware that it’s not an über-jar as the dependencies are copied into the target/lib directory.

    Run the application if the endpoint works at the development mode:

    $ java -jar target/code-with-quarkus-1.0.0-SNAPSHOT-runner.jar
    2019-11-09 08:01:14,240 INFO  [io.quarkus] (main) code-with-quarkus 1.0.0-SNAPSHOT (running on Quarkus 1.0.0.CR1) started in 0.660s. Listening on: http://0.0.0.0:8080
    2019-11-09 08:01:14,289 INFO  [io.quarkus] (main) Profile prod activated. 
    2019-11-09 08:01:14,289 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]
    
    // Run the curl command in a new terminal 
    $ curl http://localhost:8080/hello
    Welcome, Quarkus Cheat Sheet

    Building a native executable

    Let’s now produce a native executable for our application. It improves the startup time of the application and produces a minimal disk footprint. The executable would have everything to run the application including the "JVM" (shrunk to be just enough to run the application) and the application.

    The executable would have everything to run the application including the "JVM" (shrunk to be just enough to run the application) and the application.

    Install GraalVM and configure the environment

    To build a native executable image, you need:

    • Install GraalVM community edition at least version 19.1.1 in GraalVM web site.
    • Run gu install native-image from your GraalVM directory
    • The GRAALVM_HOME environment variable configured as below:

    Linux:

    export GRAALVM_HOME=$HOME/Development/graalvm/

    macOS:

    export GRAALVM_HOME=$HOME/Development/graalvm/Contents/Home/

    Before going further, be sure that the GRAALVM_HOME environment variable is configured appropriately.

    You will use “native” profile to build a native executable image in the pom.xml:

    You will use “native” profile to build a native executable image in the pom.xml.

    Create a native executable and run it

    Run mvn clean package -DskipTests -Pnative. It will take a few minutes to produce the image:

    
    ...
    [code-with-quarkus-1.0.0-SNAPSHOT-runner:86834]     (clinit):     438.26 ms
    [code-with-quarkus-1.0.0-SNAPSHOT-runner:86834]     universe:   1,174.98 ms
    [code-with-quarkus-1.0.0-SNAPSHOT-runner:86834]      (parse):   2,329.86 ms
    [code-with-quarkus-1.0.0-SNAPSHOT-runner:86834]     (inline):   3,247.13 ms
    [code-with-quarkus-1.0.0-SNAPSHOT-runner:86834]    (compile):  27,917.55 ms
    [code-with-quarkus-1.0.0-SNAPSHOT-runner:86834]      compile:  35,768.02 ms
    [code-with-quarkus-1.0.0-SNAPSHOT-runner:86834]        image:   2,067.69 ms
    [code-with-quarkus-1.0.0-SNAPSHOT-runner:86834]        write:     885.91 ms
    [code-with-quarkus-1.0.0-SNAPSHOT-runner:86834]      [total]:  70,647.15 ms
    [INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 73212ms
    [INFO] ------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------
    [INFO] Total time:  01:17 min
    [INFO] Finished at: 2019-11-09T08:05:40+09:00
    [INFO] ------------------------------------------------------------------
    

    Let’s run the native executable:

    
    ./target/code-with-quarkus-1.0.0-SNAPSHOT-runner
    2019-11-09 08:07:24,786 INFO  [io.quarkus] (main) code-with-quarkus 1.0.0-SNAPSHOT (running on Quarkus 1.0.0.CR1) started in 0.013s. Listening on: http://0.0.0.0:8080
    2019-11-09 08:07:24,787 INFO  [io.quarkus] (main) Profile prod activated. 
    2019-11-09 08:07:24,787 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]
    

    It takes just 13 milliseconds to run our microservices. You will find the same result exactly when you go back to the web browser then reload the endpoint page:

    You will find the same result exactly when you go back to the web browser then reload the endpoint page.

    Hit CTRL+C to stop the application before moving to the next step.

    Deploying on Kubernetes

    Now, you will deploy the optimized microservice application on immutable infrastructure, Kubernetes cluster. You can install own Kubernetes cluster here.

    Containerize the application

    The project generation has provided a Dockerfile.native in the src/main/docker directory with the following content:

    FROM registry.access.redhat.com/ubi8/ubi-minimal
    WORKDIR /work/
    COPY target/*-runner /work/application
    RUN chmod 775 /work
    EXPOSE 8080
    CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

    Then, you need to push the Docker image to the image registry of your Kubernetes cluster. Depending on your cluster, there are several ways. For Minikube, execute:

    eval $(minikube docker-env)
    
    docker build -f src/main/docker/Dockerfile.native -t 
    quarkus-cheatsheet/myapp .

    Deploy the application in Kubernetes

    Once the image has been pushed to the Kubernetes image registry, instantiate the application as follows:

    kubectl run quarkus-cheatsheet --image=quarkus-cheatsheet/myapp:latest --port=8080 --image-pull-policy=IfNotPresent
    
    kubectl expose deployment quarkus-cheatsheet --type=NodePort

    The application is now exposed as an internal service. If you are using Minikube, you can access it using:

    curl $(minikube service quarkus-quickstart --url)/hello
    
    Welcome, Quarkus Cheat Sheet

    More Quarkus guides

    The Quarkus site provides additional practical and useful guides on how to develop microservices/cloud-native apps/serverless using Quarkus extensions with common use cases:

    • Contexts and Dependency Injection
    • Using SSL With Native Images
    • Using JWT RBAC
    • Simplified Hibernate ORM with Panache
    • Using Apache Kafka Streams
    • Using Keycloak to Protect JAX-RS Applications
    • Deploying Native Applications on Kubernetes or OpenShift
    • Using OpenTracing and Collecting Metrics
    • Building Applications with Maven
    • Using the Quarkus Extension for Spring DI API
    Last updated: November 13, 2019