Cloud-native application made easy: part three, build, deploy Quarkus application to Openshift

In this part of these series, I am going to build a simple Quarkus web application and deploy it into Minishift. First of all, a few words about Quarkus. Quarkus, an open-source framework adapted to GraalVM and HotSpot to write Java application. It offers super-fast application boot time and low memory footprint. This makes the framework ideal for creating cloud-native application which can run on Docker or any container orchestration like Openshift or K8.

GraalVM is a universal and polyglot virtual machine (JavaScript, Python, Ruby, R, Java, Scala, Kotlin). The GraalVM (specifically Substrate VM) makes possible the ahead-of-time (AOT) compilation, converting the bytecode into native machine code, resulting in a binary that can be executed natively.

So, we are going to do the following things:

  1. Build a simple cloud-native application based on Quarkus

  2. Next, we will produce a Native image

  3. Then, we will create a container image using native executable and run on Docker.

  4. Finally, we will deploy our application on Minishift.

Before you start, a few considerations need to be taken into account to build and run the Quarkus application.

  1. JDK. Open JDK or Oracle JDK 11 or above

  2. Maven version 3.6.3 or above

  3. A installed GraalVM

  4. A installed container runtime (i.e.Docker)

  5. A installed Minishift (please follow the link, if you need to install Minishift for the first time)

  6. Any text editor

Now that we understand the basic tools we need for our first Quarkus application, it's time to dig in and start working with the platform.

The complete source code of the article is available in the GitHub repository.

Step 1. Creating the Application.

Open a terminal and run the following Maven command to create a Quarkus project.

mvn io.quarkus:quarkus-maven-plugin:1.5.2.Final:create \
    -DprojectGroupId=com.blu.std \
    -DprojectArtifactId=quarkus-getquote \
    -DclassName="com.blu.std.quarkus.TodaysQuote" \
    -Dpath="/quotes"

The above command will create a complete maven project with a Java class named "TodaysQuote" exposed on /quotes. Also, an application configuration file and examples of Docker files also created in /src/main/docker directory. Take a few moments and check the project structure.


Step 2. Add a REST endpoint.

Modify the "TodaysQuote" Java class and add the following code snippet

private static final Logger LOGGER = LoggerFactory.getLogger(TodaysQuote.class);

@ConfigProperty(name = "suffix_quote")
private String suffix_quote;

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/todays")
public String getQuote(){
    LOGGER.info("/getQuote method invoked!");
    final String[] todaysQuote = new String[]{
            "Today you are you!",
            "Today was good.",
            "Today is the only day.",
            "What is not started today is never finished tomorrow."
    };
    final int rnd = new Random().nextInt(todaysQuote.length);

    return suffix_quote + " : " + todaysQuote[rnd];

@ConfigProperty annotation will help us to read the configuration from the application.properties file. Next, we added a vanilla Java method named "getQuote" exposed on "/todays" endpoint, which will return a 'Quote' randomly at a time.

Note that, this is not a best practice to add implementation code directly on resource class, instead, Quarkus suggest to use Service class and inject it into the resource classes. Please see the Quarkus getting started guide for detailed information.

Everything looks good so far, at this point add the following property into the application.properties file.

suffix_quote=Today's quote is

That's it, you now have a working example of a cloud-native application or microservice. The project will have built an Application jar file for the sample application. Run it to check that everything works correctly.

Step 3. Compile, build, and run the Application.

To build the project, run the following command from the project home directory.

mvn clean install

At this point, the project is ready to run. Execute the following command from the project home directory.

java -jar ./target/quarkus-getquote-1.0-SNAPSHOT-runner.jar

You should see output similar to the following:

Use curl in another shell and put the service through its paces:

curl -w "\n" http://localhost:8080/quotes/todays
Today's quote is : What is not started today is never finished tomorrow.

This is not a very exciting service, but it servers a basic example to build a container with.

Note that, Quarkus provides hot deployment with background compilation, which means that whenever you modify any Java classes or resources in your project and refresh your browser (or re-invoke the service), these changes will automatically take effect. To run the application on hot deployment mode use the following command:
./mvnw compile quarkus:dev

where mvnw is a maven wrapper similar to Gradle wrapper. This allows you to run the Maven project without having Maven installed and present on the path. It downloads the correct Maven version if it's not found.

Step 4. Creating a native image.

Now that our application is up and running, it's time for creating a Native image of the application. The native image will contain the application code, required libraries, and a reduced version of VM for running the application. This smaller VM will reduce the application bootstrap time and minimize the disk and memory footprint.

As we mentioned before, we need GraalVM to produce a Native image of the application. Download the GraalVM distribution from the Github. I am using community version 20.1.0 for macOS darwin (version 19.* does not work for me).

Unarchive the GraalVM distribution somewhere in your file system and set the GRAALVM_HOME environmental variable to the GraalVM installation directory. For macOS, point the variable to the Home sub-directory as follows:

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

Optionally, you may need to install Xcode if you didn't it before.

Now install the native-image tool using gu install. Run the following command:

${GRAALVM_HOME}/bin/gu install native-image

Now that, you have the GraalVM installed and configured, it's time to create our native image.

Stop the application by entering Crtl+C command, and execute the following command:

mvn package -Pnative

The command takes a few seconds to complete (for me, it takes 1:38 min, seems I have to upgrade my workstation;-) ).

The above command will also produce /target/quarkus-getquote-1.0-SNAPSHOT-runner file which is bigger than regular JAR file (in my cases, its 27,8 Mb). You can run the native image by executing the following command:

./target/quarkus-getquote-1.0-SNAPSHOT-runner

The application should start almost instantaneously. In my cases, the startup time is 0.014s.

Step 5. Build a container image

At this point, we built a native image of the application for a macOS operating system and can run as a regular application without using the java -jar command. Next, we will build a container image that will run on docker.

First, start your Docker desktop and run the following command:

mvn package -Pnative -Dquarkus.native.container-build=true

The above command will instruct the Maven build to produce an executable from inside a container. Then, build the image with:

docker build -f src/main/docker/Dockerfile.native -t quarkus/quarkus-getquote .

We used the Dockerfile.native file which was generated during the Maven project generation. The file is located in the src/main/docker directory with the following content:

FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1
WORKDIR /work/
RUN chown 1001 /work \
    && chmod "g+rwX" /work \
    && chown 1001:root /work
COPY --chown=1001:root target/*-runner /work/application

EXPOSE 8080
USER 1001

CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

Check the image on the docker registry as shown below:

Now, run the container as follows:

docker run -i --rm -p 8080:8080 quarkus/quarkus-getquote

The container boot time is incredibly low: 0.063s

shamim-2:quarkus-getquote shamim$ docker run -i --rm -p 8080:8080 quarkus/quarkus-getquote
__  ____  __  _____   ___  __ ____  ______
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2020-07-10 09:41:22,719 INFO  [io.quarkus] (main) quarkus-getquote 1.0-SNAPSHOT native (powered by Quarkus 1.6.0.Final) started in 0.063s. Listening on: http://0.0.0.0:8080
2020-07-10 09:41:22,719 INFO  [io.quarkus] (main) Profile prod activated.
2020-07-10 09:41:22,719 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]

Test the application with the CURL command as shown before:

shamim-2:~ shamim$ curl -w "\n" http://localhost:8080/quotes/todays
Today's quote is : Today was good.

Step 6. Deploy the application to Openshift/Minishift.

The final step, first, start your Openshift cluster. I am going to use my Minishift single node cluster.

We are going to use the Quarkus OpenShift extension to deploy the application to the Openshift cluster. To add the Openshift extension, run the following command from the project home directory:

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

The above command will add a new maven dependency into the pom.xml file.

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

Alternatively, you can include the -Dextensions="openshift" argument to add the Quarkus OpenShift extension when you create a new Maven project.

Add the following properties into the src/main/resources/application.properties file:

# enable us to use untrusted certificate
quarkus.kubernetes-client.trust-certs=true
# instruct the Openshift to use Open JDK 11 Red Hat Enterprise Linux 7 image
quarkus.s2i.base-jvm-image=registry.access.redhat.com/openjdk/openjdk-11-rhel7
# Create a OpenShift route to invoke the service from the outside
quarkus.openshift.expose=true

Save the changes to the application.properties file.

Add a new Openshift project:

oc new-project quarkus-project

Now, run the following command to deploy the Quarkus project to Minishift.

mvn clean package -Dquarkus.kubernetes.deploy=true

To display the name and route of the deployed application, enter the following command:

oc get route 

You can also check the full URL to the application on the minishift web console as shown in the next screenshot.

To test the service, create a REST request on the service route's /quotes/todays endpoint.

shamim-2:~ shamim$ curl -w "\n" http://quarkus-getquote-quarkus-project.192.168.64.14.nip.io//quotes/todays
Today's quote is : Today you are you!

Summary

In this blog post, we learned how to build and deploy a basic Quarkus application to the Minishift cluster. First, we developed a Quarkus application and run on several modes (standalone, native, and docker). Later, we deploy the application to the Openshift cluster using the Quarkus Openshift extension.

Homework.


1. Modify the application to use a companion bean and inject the Bean to the resource.


2. Use ConfigMap to use the application properties on Openshift.


If you like the article, please like and share it with others. Happy Reading!

Please Note

email us at:

  • Twitter
  • LinkedIn
Join our mailing list

© 2020 Shamim bhuiyan