Tuesday, March 23, 2021

Building Native Quarkus Apps

 6

Building Native Quarkus Apps

Let’s now produce a native executable for our application. It improves the startup time of the application, and produces a minimal disk and memory 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. This is accomplished using Mandrel.

Mandrel is a downstream distribution of the GraalVM community edition. Mandrel’s main goal is to provide a native-image release specifically to support Quarkus. The aim is to align the native-image capabilities from GraalVM with OpenJDK and Red Hat Enterprise Linux libraries to improve maintainability for native Quarkus applications.

native

GraalVM is already installed for you. Inspect the value of the GRAALVM_HOME variable in the Terminal with:

echo $GRAALVM_HOME

Build the image

Within the pom.xml is the declaration for the Quarkus Maven plugin which contains a profile for native-image:

  <profiles>
    <profile>
      <id>native</id>
      <activation>
      ...
      </activation>
      <build>
      ...
      <properties>
        <quarkus.package.type>native</quarkus.package.type>
      </properties>
    </profile>
  </profiles>

We use a profile because, you will see very soon, packaging the native image takes a few seconds. However, this compilation time is only incurred once, as opposed to every time the application starts, which is the case with other approaches for building and executing JARs.

Create a native executable by using the Build Native App link on the right:

livecoding

This will take about 2-3 minutes to finish. Wait for it!. In the end you should get a BUILD SUCCESS message.

Since we are on Linux in this environment, and the OS that will eventually run our application is also Linux, we can use our local OS to build the native Quarkus app. If you need to build native Linux binaries when on other OS’s like Windows or Mac OS X, you can use -Dquarkus.native.container-runtime=[podman | docker]. You’ll need either Docker or Podman installed depending on which runtime you want to use!

The output of the native build is a native Linux binary, which you can see using the readelf command. Run this in a Terminal:

readelf -h $CHE_PROJECTS_ROOT/quarkus-workshop-m1m2-labs/target/*-runner

you’ll see:

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  ....

It’s a binary that can only run on Linux, but as you’ll see in a moment, this native executable starts up very fast and takes up little memory.

Run native image

Since our environment here is Linux, you can just run it. In the terminal, run:

$CHE_PROJECTS_ROOT/quarkus-workshop-m1m2-labs/target/people-1.0-SNAPSHOT-runner -Dquarkus.http.port=8081 
We use port 8081 here to avoid conflicting with our already-running development mode Quarkus app.

Notice the amazingly fast startup time:

2020-11-04 23:24:38,770 INFO  [io.quarkus] (main) people 1.0-SNAPSHOT native (powered by Quarkus x.x.x.) started in 0.018s. Listening on: http://0.0.0.0:8081

That’s 16 milliseconds to start up.

And extremely low memory usage as reported by the Linux ps utility. While the app is running, open another Terminal and run:

ps -o pid,rss,command -p $(pgrep -f runner)

You should see something like:

    PID   RSS COMMAND
   1108 61196 /projects/quarkus-workshop-m1m2-labs/target/people-1.0-SNAPSHOT-runner -Dquarkus.http.port=8081

This shows that our process is taking around 60 MB of memory (Resident Set Size, or RSS). Pretty compact!

The RSS and memory usage of any app, including Quarkus, will vary depending your specific environment, and will rise as the application experiences load.

Make sure the app is still working as expected (we’ll use curl this time to access it directly). In a new Terminal run:

curl http://localhost:8081/hello/greeting/quarkus

You should see:

hello quarkus from <your-hostname>

Nice!

Cleanup

Go to the Terminal in which you ran the native app and press CTRL+C to stop our native app. Be sure to leave your Live Coding Terminal open!

Congratulations!

You’ve now built a Java application as an executable JAR and a Linux native binary. We’ll explore the benefits of native binaries later in when we start deploying to Kubernetes.

No comments:

Post a Comment