Menu

Quarkus Topic

Part 1: Creating Native Executables with GraalVM

Native compilation is one of Quarkus's killer features, producing ultra-fast, low-memory executables.

GraalVM Setup

Option 1: Install GraalVM locally

bash

# Download GraalVM from https://www.graalvm.org/
# Set GRAALVM_HOME environment variable
export GRAALVM_HOME=/path/to/graalvm

Option 2: Use Quarkus with Mandrel (recommended)

xml

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-native-image</artifactId>
</dependency>

Native Build Configuration

properties

# application.properties - Native build configuration
quarkus.package.type=native
quarkus.native.enabled=true

# Native image optimization
quarkus.native.container-build=true
quarkus.native.java-version=17

# Memory settings for native build
quarkus.native.native-image-xmx=4g

# Reflection configuration (auto-detected in most cases)
quarkus.native.enable-all-security-services=true
quarkus.native.add-all-charsets=true

Building Native Executables

bash

# Build native executable using local GraalVM
./mvnw package -Dnative

# Build native executable in container (no local GraalVM needed)
./mvnw package -Dnative -Dquarkus.native.container-build=true

# For Podman instead of Docker
./mvnw package -Dnative -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=podman

# Build using specific builder image
./mvnw package -Dnative -Dquarkus.native.container-build=true \
  -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel:22.3-java17

Native-Specific Configuration

java

// Register classes for reflection (when auto-detection fails)
@RegisterForReflection(targets = {
    MyCustomClass.class,
    AnotherDTO.class
})
public class ReflectionConfiguration {
}

// Or register at class level
@RegisterForReflection
public class MyCustomClass {
    private String data;
    // getters/setters
}

Testing Native Executables

bash

# Build and run native executable
./mvnw package -Dnative
./target/my-app-1.0.0-runner

# Test the native application
curl http://localhost:8080/api/hello

Part 2: Building Docker Images

Quarkus provides multiple strategies for containerizing applications.

Docker Configuration

properties

# application.properties - Docker image configuration
quarkus.container-image.build=true
quarkus.container-image.group=mycompany
quarkus.container-image.name=my-quarkus-app
quarkus.container-image.tag=1.0.0
quarkus.container-image.registry=quay.io

# Using JVM mode (balanced performance/startup)
quarkus.container-image.builder=jib
quarkus.jib.base-jvm-image=eclipse-temurin:17-jre

# Using Native mode (best startup/memory)
quarkus.package.type=native
quarkus.native.container-build=true
quarkus.container-image.builder=docker

Different Containerization Strategies

1. Using Jib (Recommended for JVM)

properties

# Jib configuration for JVM container
quarkus.container-image.build=true
quarkus.container-image.builder=jib
quarkus.jib.base-jvm-image=eclipse-temurin:17-jre-alpine
quarkus.jib.jvm-arguments=-Djava.util.logging.manager=org.jboss.logmanager.LogManager,-Xmx64m

2. Using Docker (for Native)

properties

# Docker configuration for native container
quarkus.container-image.build=true
quarkus.container-image.builder=docker
quarkus.native.container-build=true

3. Using Buildpacks

properties

# Cloud Native Buildpacks
quarkus.container-image.build=true
quarkus.container-image.builder=buildpacks
quarkus.container-image.group=myorg

Custom Dockerfile Support

src/main/docker/Dockerfile.jvm

dockerfile

FROM eclipse-temurin:17-jre-alpine
WORKDIR /work/
COPY target/*-runner.jar app.jar
RUN chown 1001:1001 app.jar
USER 1001
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]

src/main/docker/Dockerfile.native

dockerfile

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

src/main/docker/Dockerfile.native-micro

dockerfile

# Micro Docker image for native executable
FROM quay.io/quarkus/quarkus-micro-image:2.0
WORKDIR /work/
COPY target/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

Building Container Images

bash

# Build JVM container image
./mvnw clean package -Dquarkus.container-image.build=true

# Build native container image
./mvnw clean package -Dnative -Dquarkus.container-image.build=true

# Push to registry
./mvnw clean package -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true

# Build with custom properties
./mvnw clean package \
  -Dquarkus.container-image.build=true \
  -Dquarkus.container-image.group=mycompany \
  -Dquarkus.container-image.name=myapp \
  -Dquarkus.container-image.tag=v1.0.0

Part 3: Deploying to Various Platforms

Kubernetes Deployment

Dependencies

xml

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

<!-- For OpenShift -->
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-openshift</artifactId>
</dependency>

Kubernetes Configuration

properties

# application.properties - Kubernetes configuration
quarkus.kubernetes.deploy=true
quarkus.kubernetes.deployment-target=kubernetes

# Application metadata
quarkus.application.name=my-quarkus-app
quarkus.application.version=1.0.0

# Container configuration
quarkus.container-image.group=my-namespace
quarkus.container-image.registry=my-registry.com
quarkus.container-image.username=$REGISTRY_USER
quarkus.container-image.password=$REGISTRY_PASSWORD

# Kubernetes resources
quarkus.kubernetes.replicas=3
quarkus.kubernetes.labels.app=my-quarkus-app
quarkus.kubernetes.annotations.priority=high

# Service configuration
quarkus.kubernetes.service-type=ClusterIP
quarkus.kubernetes.ports.http=8080

# Health checks
quarkus.kubernetes.liveness-probe.http-action-path=/q/health/live
quarkus.kubernetes.readiness-probe.http-action-path=/q/health/ready

# Resource limits (for native)
quarkus.kubernetes.resources.limits.memory=64Mi
quarkus.kubernetes.resources.limits.cpu=500m
quarkus.kubernetes.resources.requests.memory=32Mi
quarkus.kubernetes.resources.requests.cpu=100m

Custom Kubernetes Resources

java

@KubernetesClient
@ServiceAccount
@Ingress(path="/")
@RoleBinding(roleRefName = "view", subjects = @Subject(kind = "ServiceAccount", name = "my-service-account"))
public class MyAppKubernetesConfig {
    // Kubernetes resources will be generated automatically
}

OpenShift Deployment

properties

# OpenShift specific configuration
quarkus.openshift.deploy=true
quarkus.openshift.expose=true
quarkus.openshift.route.expose=true
quarkus.openshift.annotations.openshift.io/display-name=My Quarkus App

# S2I (Source-to-Image) build
quarkus.openshift.build-strategy=docker
quarkus.container-image.builder=docker

AWS Lambda Deployment

Dependencies

xml

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-amazon-lambda</artifactId>
</dependency>

<!-- For HTTP via API Gateway -->
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-amazon-lambda-http</artifactId>
</dependency>

<!-- For RESTEasy Reactive -->
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-amazon-lambda-rest</artifactId>
</dependency>

Lambda Configuration

properties

# AWS Lambda configuration
quarkus.lambda.handler=test
quarkus.native.container-build=true

# For HTTP Lambda
quarkus.lambda.http.enabled=true

# Deployment configuration
quarkus.container-image.registry=your-account-id.dkr.ecr.us-east-1.amazonaws.com
quarkus.container-image.name=my-lambda-function

Lambda Handler

java

public class LambdaHandler implements RequestHandler<APIGatewayV2HTTPEvent, APIGatewayV2HTTPResponse> {
    
    private static final QuarkusHttpHandler handler = QuarkusHttpHandlerSupplier.get();
    
    @Override
    public APIGatewayV2HTTPResponse handleRequest(APIGatewayV2HTTPEvent event, Context context) {
        return handler.handleRequest(event, context);
    }
}

// Or for simple functions
public class SimpleLambdaHandler implements RequestHandler<InputObject, OutputObject> {
    @Override
    public OutputObject handleRequest(InputObject input, Context context) {
        return processInput(input);
    }
}

Deploying to AWS Lambda

bash

# Build native image for Lambda
./mvnw clean package -Dnative -Dquarkus.native.container-build=true

# Deploy using SAM (Serverless Application Model)
sam deploy --template-file target/sam.jvm.yaml --stack-name my-quarkus-app

# Or using AWS CDK
cdk deploy

Azure Functions Deployment

Dependencies

xml

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-azure-functions</artifactId>
</dependency>

Azure Configuration

properties

quarkus.azure-functions.auth-level=anonymous
quarkus.package.type=native

Part 4: Quarkus Dev Services

Dev Services automatically provide dev-mode containers for databases, message brokers, and other services.

How Dev Services Works

Dev Services automatically:

  • Detects needed services from dependencies

  • Starts containers in development/test mode

  • Configures your application to connect to them

  • Tears down containers when no longer needed

Database Dev Services

PostgreSQL

properties

# No configuration needed! Dev Services auto-starts PostgreSQL
quarkus.datasource.db-kind=postgresql
quarkus.datasource.devservices.enabled=true
quarkus.datasource.devservices.port=5432
# Optional: use specific image
quarkus.datasource.devservices.image-name=postgres:14

MySQL

properties

quarkus.datasource.db-kind=mysql
quarkus.datasource.devservices.enabled=true

Message Broker Dev Services

Redis

xml

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-redis-client</artifactId>
</dependency>

properties

# Auto-starts Redis container
quarkus.redis.devservices.enabled=true
quarkus.redis.hosts=redis://localhost:6379

Kafka

xml

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-messaging-kafka</artifactId>
</dependency>

properties

# Auto-starts Kafka + ZooKeeper containers
quarkus.kafka.devservices.enabled=true
quarkus.kafka.devservices.port=9092

Other Dev Services

Mail Server (TestMail)

properties

quarkus.mailer.devservices.enabled=true
quarkus.mailer.port=25

Keycloak (for OAuth2 testing)

properties

quarkus.keycloak.devservices.enabled=true
quarkus.oidc.auth-server-url=http://localhost:8080/auth/realms/quarkus

Custom Dev Services Configuration

properties

# Control Dev Services behavior
quarkus.datasource.devservices.reuse=true  # Reuse containers between runs
quarkus.datasource.devservices.shared=true # Share between multiple apps

# Resource limits
quarkus.datasource.devservices.memory=1G
quarkus.kafka.devservices.service-kafka-node-count=2  # Multiple brokers

Dev Services in Action

When you run ./mvnw quarkus:dev, you'll see output like:

text

Dev Services for PostgreSQL started. 
Other applications can connect using: 
 - jdbc:postgresql://localhost:5432/quarkus

Testing with Dev Services

java

@QuarkusTest
@TestResource(MyTestResource.class)
public class DatabaseTest {

    @Test
    public void testWithDevDatabase() {
        // Tests automatically use the Dev Services database
        given()
          .when().get("/api/users")
          .then()
          .statusCode(200);
    }
}

// Custom test resource
public class MyTestResource implements QuarkusTestResourceLifecycleManager {
    
    @Override
    public Map<String, String> start() {
        // Custom test container setup
        return Collections.singletonMap("quarkus.datasource.jdbc.url", 
            "jdbc:postgresql://localhost:5432/testdb");
    }
    
    @Override
    public void stop() {
        // Cleanup
    }
}

Part 5: Cloud-Native Best Practices

Health Checks

java

@Liveness
@ApplicationScoped
public class CustomLivenessCheck implements HealthCheck {
    @Override
    public HealthCheckResponse call() {
        return HealthCheckResponse.up("Custom live check");
    }
}

@Readiness
@ApplicationScoped
public class CustomReadinessCheck implements HealthCheck {
    @Override
    public HealthCheckResponse call() {
        return HealthCheckResponse.up("Custom ready check");
    }
}

Configuration for Different Environments

properties

# application.properties - Base configuration
quarkus.application.name=my-app
quarkus.http.port=8080

# %dev - Development
%dev.quarkus.log.level=DEBUG
%dev.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/devdb

# %test - Testing  
%test.quarkus.log.level=INFO
%test.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/testdb

# %prod - Production
%prod.quarkus.log.level=WARN
%prod.quarkus.datasource.jdbc.url=${DATABASE_URL:jdbc:postgresql://prod-db:5432/proddb}
%prod.quarkus.datasource.username=${DB_USERNAME}
%prod.quarkus.datasource.password=${DB_PASSWORD}

Deployment Scripts

deploy-to-k8s.sh

bash

#!/bin/bash
# Build and deploy to Kubernetes

echo "Building native image..."
./mvnw clean package -Dnative -Dquarkus.container-image.build=true

echo "Pushing to registry..."
./mvnw package -Dquarkus.container-image.push=true

echo "Deploying to Kubernetes..."
kubectl apply -f target/kubernetes/kubernetes.yml

echo "Rolling update..."
kubectl rollout restart deployment/my-quarkus-app

Key Takeaways

  1. Native First: Always consider native compilation for cloud deployment

  2. Dev Services: Eliminates manual setup for development databases/message brokers

  3. Multi-Platform: Quarkus supports Kubernetes, OpenShift, AWS Lambda, Azure Functions

  4. Optimized Containers: Tiny images with fast startup perfect for microservices

  5. Configuration Profiles: Easy environment-specific configuration

  6. Automated Deployments: Streamlined CI/CD with container-first approach

Quarkus makes cloud deployment incredibly smooth with its container-native approach, fast startup times, and comprehensive cloud integration features.

 

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?