Quarkus - a new try on native images

2023-03-16 - [quarkus, java, jvm, gradle]


Three years ago I did some tests using quarkus, to use on some microservices / pet projects. The commands to make it run using native binary are on this gist.

Today I tried it again, just registering here my steps:

1. Install quarkus

I am using sdkman for it - it is a java version manager, similar to fnm (for node).

It is easy as sdk install quarkus.

2. Create a project

Just need to run:

quarkus create app adamatti.github.io:learn-quarkus --extension='resteasy-reactive' --gradle

Where learn-quarkus is the project name and adamatti.github.io is the main package name.

Yes, I decided to use gradle instead of maven. Not willing to use XML in 2023 :-p

Then I added this extension to build inside a docker container:

gradle addExtension --extensions=quarkus-container-image-docker

3. Run

./gradlew quarkusDev. I can't deny, it is amazing be able to change source files without the need to stop/start the application multiple times

4. Build native

./gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true

With this, you don't need to have graalvm on local machine.

The binary file was created on build folder as learn-quarkus-1.0.0-SNAPSHOT-runner. It took ~4mins on my machine (Apple M1), 40mb is the size.

5. Run the binary in a docker container

... just to make sure it doesn't need any of the dependencies in my local machine (e.g. java) and simulate a real deploy.

docker run --rm -it \
    -p "8080:8080" \
    -v ${PWD}/build/learn-quarkus-1.0.0-SNAPSHOT-runner:/app \
    centos \
    /app -Dquarkus.http.host=0.0.0.0

Extra - version configuration

Just created a .sdkmanrc file to make sure I would use the same versions in the future:

# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=11.0.11.9.1-amzn
gradle=7.5.1
quarkus=3.0.0.Alpha6

Conclusion

  1. Quarkus is really fast, I would love to work with it in production
  2. Really loved the way the resources/controllers are created, e.g.
package adamatti.github.io;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello from RESTEasy Reactive";
    }
}
  1. Loved the tests created with Gherkin syntax:
package adamatti.github.io;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@QuarkusTest
public class GreetingResourceTest {

    @Test
    public void testHelloEndpoint() {
        given()
          .when().get("/hello")
          .then()
             .statusCode(200)
             .body(is("Hello from RESTEasy Reactive"));
    }

}
  1. It also create tests for the native version (powered by the additional annotation):
package adamatti.github.io;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
public class GreetingResourceIT extends GreetingResourceTest {
    // Execute the same tests but in packaged mode.
}
  1. Micronault is still my preferred spring replacement, but this is a subject for another topic.

I still curious about Quarkus usage, let's keep watching and see how does it goes.



Return to list