Article
Quarkus Kubernetes extension provides a declarative approach to generating and deploying Kubernetes resources for your Java applications. It automatically generates manifests, handles configuration, and simplifies the entire Kubernetes deployment workflow, making it ideal for building cloud-native Java applications.
What is Quarkus Kubernetes Extension?
The Quarkus Kubernetes extension is a set of tools that automatically generates Kubernetes manifests (YAML files) from your Quarkus application code and configuration. It follows the "compile-time" philosophy of Quarkus, generating optimal Kubernetes resources during build time.
Key Benefits for Java Developers:
- Automatic Manifest Generation: No manual YAML writing required
- Configuration as Code: Kubernetes configuration in application.properties
- Health Checks: Automatic liveness/readiness probe configuration
- Service Discovery: Automatic service and ingress generation
- Security: Built-in security context and RBAC generation
- Multi-Platform Support: Kubernetes, OpenShift, Knative
Setup and Dependencies
1. Maven Configuration
<!-- pom.xml -->
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>quarkus-kubernetes-app</artifactId>
<version>1.0.0</version>
<properties>
<quarkus.platform.version>3.6.0</quarkus.platform.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<!-- Quarkus Core -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<!-- RESTEasy Reactive for HTTP -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<!-- Kubernetes Extension -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes</artifactId>
</dependency>
<!-- Health Checks -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-health</artifactId>
</dependency>
<!-- Metrics -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-micrometer-registry-prometheus</artifactId>
</dependency>
<!-- Configurations -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-config</artifactId>
</dependency>
<!-- Service Binding -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-service-binding</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-bom</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2. Gradle Configuration
// build.gradle
plugins {
id 'java'
id 'io.quarkus'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'io.quarkus:quarkus-arc'
implementation 'io.quarkus:quarkus-resteasy-reactive'
implementation 'io.quarkus:quarkus-kubernetes'
implementation 'io.quarkus:quarkus-smallrye-health'
implementation 'io.quarkus:quarkus-micrometer-registry-prometheus'
implementation 'io.quarkus:quarkus-kubernetes-config'
implementation 'io.quarkus:quarkus-kubernetes-service-binding'
}
quarkus {
setOutputDirectory("$projectDir/build/classes/java/main")
}
Basic Configuration
1. Application Properties Configuration
# application.properties # Application Configuration quarkus.application.name=my-quarkus-app quarkus.application.version=1.0.0 # Kubernetes Configuration quarkus.kubernetes.deployment-target=kubernetes quarkus.kubernetes.namespace=my-namespace # Container Configuration quarkus.kubernetes.image-pull-policy=IfNotPresent quarkus.kubernetes.image-registry=docker.io quarkus.kubernetes.image-group=my-organization quarkus.container-image.build=true # Service Configuration quarkus.kubernetes.service-type=ClusterIP quarkus.kubernetes.ingress.expose=true quarkus.kubernetes.ingress.host=my-app.example.com # Health Checks quarkus.kubernetes.liveness-probe.path=/q/health/live quarkus.kubernetes.readiness-probe.path=/q/health/ready quarkus.kubernetes.liveness-probe.initial-delay=30 quarkus.kubernetes.readiness-probe.initial-delay=5 # Resource Configuration quarkus.kubernetes.resources.requests.memory=256Mi quarkus.kubernetes.resources.requests.cpu=250m quarkus.kubernetes.resources.limits.memory=512Mi quarkus.kubernetes.resources.limits.cpu=500m # JVM Configuration quarkus.kubernetes.env.vars.JAVA_OPTS=-Xmx256m -Xms128m quarkus.kubernetes.env.vars.QUARKUS_PROFILE=production # Replica Configuration quarkus.kubernetes.replicas=3
2. Basic Quarkus Application
package com.example.quarkus;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/api")
public class GreetingResource {
@GET
@Path("/hello")
@Produces(MediaType.APPLICATION_JSON)
public String hello() {
return "{\"message\": \"Hello from Quarkus Kubernetes!\"}";
}
}
3. Health Check Endpoints
package com.example.quarkus.health;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.eclipse.microprofile.health.Liveness;
import org.eclipse.microprofile.health.Readiness;
import jakarta.enterprise.context.ApplicationScoped;
@Liveness
@ApplicationScoped
public class LivenessHealthCheck implements HealthCheck {
@Override
public HealthCheckResponse call() {
return HealthCheckResponse.up("Quarkus Kubernetes App - Liveness");
}
}
@Readiness
@ApplicationScoped
public class ReadinessHealthCheck implements HealthCheck {
@Override
public HealthCheckResponse call() {
return HealthCheckResponse.up("Quarkus Kubernetes App - Readiness");
}
}
Advanced Kubernetes Configuration
1. Complete Kubernetes Configuration
# src/main/resources/application.properties
# ===== BASIC APPLICATION CONFIG =====
quarkus.application.name=order-service
quarkus.application.version=2.1.0
# ===== KUBERNETES DEPLOYMENT CONFIG =====
quarkus.kubernetes.deploy=true
quarkus.kubernetes.deployment-target=kubernetes
quarkus.kubernetes.namespace=production
# ===== CONTAINER IMAGE CONFIG =====
quarkus.container-image.build=true
quarkus.container-image.push=true
quarkus.container-image.registry=ghcr.io
quarkus.container-image.group=my-organization
quarkus.container-image.name=order-service
quarkus.container-image.tag=latest
quarkus.container-image.username=${CONTAINER_REGISTRY_USERNAME}
quarkus.container-image.password=${CONTAINER_REGISTRY_PASSWORD}
# ===== DEPLOYMENT CONFIG =====
quarkus.kubernetes.replicas=3
quarkus.kubernetes.part-of=order-management-system
quarkus.kubernetes.management.port=9000
# ===== SERVICE CONFIG =====
quarkus.kubernetes.service-type=ClusterIP
quarkus.kubernetes.service.ports.http=80
quarkus.kubernetes.service.ports.target-http=8080
# ===== INGRESS CONFIG =====
quarkus.kubernetes.ingress.expose=true
quarkus.kubernetes.ingress.host=orders.mycompany.com
quarkus.kubernetes.ingress.class-name=nginx
quarkus.kubernetes.ingress.annotations.kubernetes\\.io/ingress\\.class=nginx
quarkus.kubernetes.ingress.annotations.nginx\\.ingress\\.kubernetes\\.io/rewrite-target=/
# ===== HEALTH CHECK CONFIG =====
quarkus.kubernetes.liveness-probe.http-action-path=/q/health/live
quarkus.kubernetes.liveness-probe.initial-delay=30
quarkus.kubernetes.liveness-probe.period=10
quarkus.kubernetes.liveness-probe.failure-threshold=3
quarkus.kubernetes.liveness-probe.success-threshold=1
quarkus.kubernetes.readiness-probe.http-action-path=/q/health/ready
quarkus.kubernetes.readiness-probe.initial-delay=5
quarkus.kubernetes.readiness-probe.period=5
quarkus.kubernetes.readiness-probe.failure-threshold=3
quarkus.kubernetes.startup-probe.http-action-path=/q/health/started
quarkus.kubernetes.startup-probe.initial-delay=0
quarkus.kubernetes.startup-probe.period=5
quarkus.kubernetes.startup-probe.failure-threshold=30
# ===== RESOURCE CONFIG =====
quarkus.kubernetes.resources.requests.memory=512Mi
quarkus.kubernetes.resources.requests.cpu=500m
quarkus.kubernetes.resources.limits.memory=1Gi
quarkus.kubernetes.resources.limits.cpu=1000m
# ===== ENVIRONMENT VARIABLES =====
quarkus.kubernetes.env.vars.JAVA_OPTS=-Xmx512m -Xms256m -XX:+UseG1GC
quarkus.kubernetes.env.vars.QUARKUS_PROFILE=production
quarkus.kubernetes.env.vars.LOG_LEVEL=INFO
quarkus.kubernetes.env.vars.DATABASE_URL=postgresql://db-host:5432/orders
# ===== SECURITY CONTEXT =====
quarkus.kubernetes.security-context.run-as-user=1001
quarkus.kubernetes.security-context.run-as-non-root=true
# ===== LABELS AND ANNOTATIONS =====
quarkus.kubernetes.labels.app=order-service
quarkus.kubernetes.labels.version=2.1.0
quarkus.kubernetes.labels.team=backend-team
quarkus.kubernetes.annotations.owner=java-team
quarkus.kubernetes.annotations.description="Order Management Microservice"
# ===== PDB CONFIG =====
quarkus.kubernetes.pdb.min-available=2
# ===== SERVICE ACCOUNT =====
quarkus.kubernetes.service-account-name=order-service-account
2. Multi-Container Pod Configuration
# Multi-container application.properties quarkus.kubernetes.sidecars.logging-agent.image=fluent/fluent-bit:2.1 quarkus.kubernetes.sidecars.logging-agent.env-vars.FLUSH_INTERVAL=1 quarkus.kubernetes.sidecars.logging-agent.ports.http.port=2020 quarkus.kubernetes.init-containers.db-migration.image=postgres:15 quarkus.kubernetes.init-containers.db-migration.commands[0]=/bin/sh quarkus.kubernetes.init-containers.db-migration.commands[1]=-c quarkus.kubernetes.init-containers.db-migration.commands[2]=until pg_isready -h $DB_HOST; do sleep 5; done
3. ConfigMap and Secret Configuration
# ConfigMap and Secrets configuration quarkus.kubernetes.config-maps.app-config.enabled=true quarkus.kubernetes.config-maps.app-config.mount-path=/app/config quarkus.kubernetes.secrets.db-secret.enabled=true quarkus.kubernetes.secrets.db-secret.mount-path=/app/secrets # Environment variables from ConfigMap quarkus.kubernetes.env.configmaps=app-config quarkus.kubernetes.env.secrets=db-secret # Specific fields from ConfigMap quarkus.kubernetes.env.mapping.DB_HOST.from-configmap=app-config quarkus.kubernetes.env.mapping.DB_HOST.with-key=database-host quarkus.kubernetes.env.mapping.DB_PASSWORD.from-secret=db-secret quarkus.kubernetes.env.mapping.DB_PASSWORD.with-key=password
Generated Manifests Examples
1. Generated Deployment Manifest
# Generated kubernetes.yml apiVersion: apps/v1 kind: Deployment metadata: name: order-service namespace: production labels: app.kubernetes.io/name: order-service app.kubernetes.io/version: 2.1.0 app: order-service version: 2.1.0 team: backend-team annotations: owner: java-team description: Order Management Microservice spec: replicas: 3 selector: matchLabels: app.kubernetes.io/name: order-service app.kubernetes.io/version: 2.1.0 template: metadata: labels: app.kubernetes.io/name: order-service app.kubernetes.io/version: 2.1.0 app: order-service version: 2.1.0 spec: serviceAccountName: order-service-account securityContext: runAsUser: 1001 runAsNonRoot: true containers: - name: order-service image: ghcr.io/my-organization/order-service:latest ports: - containerPort: 8080 name: http - containerPort: 9000 name: management env: - name: JAVA_OPTS value: -Xmx512m -Xms256m -XX:+UseG1GC - name: QUARKUS_PROFILE value: production - name: LOG_LEVEL value: INFO - name: DATABASE_URL value: postgresql://db-host:5432/orders resources: requests: memory: 512Mi cpu: 500m limits: memory: 1Gi cpu: 1000m livenessProbe: httpGet: path: /q/health/live port: 8080 initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 3 successThreshold: 1 readinessProbe: httpGet: path: /q/health/ready port: 8080 initialDelaySeconds: 5 periodSeconds: 5 failureThreshold: 3 startupProbe: httpGet: path: /q/health/started port: 8080 initialDelaySeconds: 0 periodSeconds: 5 failureThreshold: 30 imagePullPolicy: IfNotPresent
2. Generated Service Manifest
apiVersion: v1 kind: Service metadata: name: order-service namespace: production labels: app.kubernetes.io/name: order-service app.kubernetes.io/version: 2.1.0 spec: ports: - name: http port: 80 targetPort: 8080 protocol: TCP selector: app.kubernetes.io/name: order-service app.kubernetes.io/version: 2.1.0 type: ClusterIP
3. Generated Ingress Manifest
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: order-service namespace: production annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - host: orders.mycompany.com http: paths: - path: / pathType: Prefix backend: service: name: order-service port: name: http
Advanced Features
1. Custom Resource Definitions
# Custom Resource configuration quarkus.kubernetes.custom-resources.custom-crd.enabled=true quarkus.kubernetes.custom-resources.custom-crd.target-kubernetes=1.25
2. Horizontal Pod Autoscaler
# HPA Configuration quarkus.kubernetes.hpa.enabled=true quarkus.kubernetes.hpa.min-replicas=3 quarkus.kubernetes.hpa.max-replicas=10 quarkus.kubernetes.hpa.metrics.cpu.target-average-utilization=70 quarkus.kubernetes.hpa.metrics.memory.target-average-utilization=80
3. Service Binding
# Service Binding configuration quarkus.kubernetes-service-binding.enabled=true quarkus.kubernetes-service-binding.services.database.api-version=postgresql.cnpg.io/v1 quarkus.kubernetes-service-binding.services.database.kind=Cluster quarkus.kubernetes-service-binding.services.database.name=postgres-cluster
Multi-Environment Configuration
1. Development Profile
# src/main/resources/application-dev.properties quarkus.kubernetes.deploy=false quarkus.kubernetes.replicas=1 quarkus.kubernetes.resources.requests.memory=256Mi quarkus.kubernetes.resources.requests.cpu=100m quarkus.kubernetes.resources.limits.memory=512Mi quarkus.kubernetes.resources.limits.cpu=250m quarkus.kubernetes.env.vars.QUARKUS_PROFILE=dev quarkus.kubernetes.env.vars.LOG_LEVEL=DEBUG quarkus.kubernetes.ingress.expose=false
2. Production Profile
# src/main/resources/application-prod.properties quarkus.kubernetes.deploy=true quarkus.kubernetes.replicas=3 quarkus.kubernetes.resources.requests.memory=512Mi quarkus.kubernetes.resources.requests.cpu=500m quarkus.kubernetes.resources.limits.memory=1Gi quarkus.kubernetes.resources.limits.cpu=1000m quarkus.kubernetes.env.vars.QUARKUS_PROFILE=prod quarkus.kubernetes.env.vars.LOG_LEVEL=INFO quarkus.kubernetes.ingress.expose=true quarkus.kubernetes.ingress.host=api.mycompany.com quarkus.kubernetes.liveness-probe.initial-delay=45 quarkus.kubernetes.security-context.run-as-non-root=true
3. OpenShift Configuration
# OpenShift specific configuration quarkus.kubernetes.deployment-target=openshift quarkus.kubernetes.ingress.expose=true quarkus.openshift.route.host=my-app.openshift.example.com quarkus.openshift.annotations.openshift.io/display-name=My Quarkus App
Build and Deployment
1. Maven Build Commands
# Build application and generate Kubernetes manifests mvn clean package # Build with container image mvn clean package -Dquarkus.container-image.build=true # Build and push container image mvn clean package -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true # Deploy to Kubernetes mvn clean package -Dquarkus.kubernetes.deploy=true # Build for specific profile mvn clean package -Dquarkus.profile=prod # Generate manifests without building mvn quarkus:kubernetes-generate
2. Generated Files Location
target/kubernetes/ ├── kubernetes.yml # Main Kubernetes manifests ├── openshift.yml # OpenShift specific manifests ├── knative.yml # Knative serving manifests └── jib-container # Container build files
3. Custom Build Script
#!/bin/bash
# build-and-deploy.sh
set -e
ENVIRONMENT=${1:-dev}
IMAGE_TAG=${2:-latest}
echo "Building for environment: $ENVIRONMENT"
echo "Using image tag: $IMAGE_TAG"
# Build with specific profile
mvn clean package \
-Dquarkus.profile=$ENVIRONMENT \
-Dquarkus.container-image.build=true \
-Dquarkus.container-image.tag=$IMAGE_TAG
if [ "$ENVIRONMENT" == "prod" ]; then
echo "Pushing image to registry..."
mvn package -Dquarkus.container-image.push=true
fi
echo "Kubernetes manifests generated at: target/kubernetes/"
# Display generated manifests
echo "=== Generated Manifests ==="
cat target/kubernetes/kubernetes.yml
CI/CD Integration
1. GitHub Actions Workflow
# .github/workflows/quarkus-kubernetes.yml
name: Quarkus Kubernetes CI/CD
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Run tests
run: mvn clean test
build:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
steps:
- uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build and generate manifests
run: |
mvn clean package -Dquarkus.container-image.build=true
cat target/kubernetes/kubernetes.yml
- name: Log in to Container Registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push container image
run: mvn package -Dquarkus.container-image.push=true
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Deploy to Kubernetes
uses: steebchen/kubectl@v2
with:
config: ${{ secrets.KUBECONFIG }}
command: apply -f target/kubernetes/kubernetes.yml
- name: Verify deployment
uses: steebchen/kubectl@v2
with:
config: ${{ secrets.KUBECONFIG }}
command: rollout status deployment/order-service
2. GitLab CI Configuration
# .gitlab-ci.yml stages: - test - build - deploy variables: MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository" test: stage: test image: maven:3.9-eclipse-temurin-17 script: - mvn clean test build: stage: build image: maven:3.9-eclipse-temurin-17 script: - mvn clean package -Dquarkus.container-image.build=true - cat target/kubernetes/kubernetes.yml artifacts: paths: - target/kubernetes/ expire_in: 1 week deploy: stage: deploy image: name: bitnami/kubectl:latest entrypoint: [""] script: - kubectl apply -f target/kubernetes/kubernetes.yml - kubectl rollout status deployment/order-service only: - main
Best Practices
1. Security Configuration
# Security best practices quarkus.kubernetes.security-context.run-as-non-root=true quarkus.kubernetes.security-context.run-as-user=1001 quarkus.kubernetes.security-context.allow-privilege-escalation=false quarkus.kubernetes.security-context.capabilities.drop=ALL quarkus.kubernetes.security-context.read-only-root-filesystem=true
2. Monitoring and Observability
# Monitoring configuration quarkus.micrometer.export.prometheus.path=/metrics quarkus.kubernetes.annotations.prometheus\\.io/scrape=true quarkus.kubernetes.annotations.prometheus\\.io/port=8080 quarkus.kubernetes.annotations.prometheus\\.io/path=/metrics
3. Resource Optimization
# Resource optimization quarkus.kubernetes.resources.requests.memory=64Mi quarkus.kubernetes.resources.requests.cpu=50m quarkus.kubernetes.resources.limits.memory=128Mi quarkus.kubernetes.resources.limits.cpu=100m quarkus.kubernetes.env.vars.QUARKUS_JVM_CHECK=false quarkus.kubernetes.env.vars.JAVA_OPTS=-Xmx64m -Xms16m
Conclusion
The Quarkus Kubernetes extension provides Java developers with:
- Zero-Configuration Kubernetes: Automatic manifest generation
- Production-Ready Defaults: Health checks, resource limits, security
- Multi-Environment Support: Easy configuration for dev/staging/prod
- CI/CD Integration: Seamless integration with deployment pipelines
- Cloud-Native Features: Service discovery, config management, scaling
By leveraging the Quarkus Kubernetes extension, Java teams can focus on business logic while Quarkus handles the complexities of Kubernetes deployment, resulting in faster development cycles and more reliable deployments.
Pyroscope Profiling in Java
Explains how to use Pyroscope for continuous profiling in Java applications, helping developers analyze CPU and memory usage patterns to improve performance and identify bottlenecks.
https://macronepal.com/blog/pyroscope-profiling-in-java/
OpenTelemetry Metrics in Java: Comprehensive Guide
Provides a complete guide to collecting and exporting metrics in Java using OpenTelemetry, including counters, histograms, gauges, and integration with monitoring tools. (MACRO NEPAL)
https://macronepal.com/blog/opentelemetry-metrics-in-java-comprehensive-guide/
OTLP Exporter in Java: Complete Guide for OpenTelemetry
Explains how to configure OTLP exporters in Java to send telemetry data such as traces, metrics, and logs to monitoring systems using HTTP or gRPC protocols. (MACRO NEPAL)
https://macronepal.com/blog/otlp-exporter-in-java-complete-guide-for-opentelemetry/
Thanos Integration in Java: Global View of Metrics
Explains how to integrate Thanos with Java monitoring systems to create a scalable global metrics view across multiple Prometheus instances.
https://macronepal.com/blog/thanos-integration-in-java-global-view-of-metrics
Time Series with InfluxDB in Java: Complete Guide (Version 2)
Explains how to manage time-series data using InfluxDB in Java applications, including storing, querying, and analyzing metrics data.
https://macronepal.com/blog/time-series-with-influxdb-in-java-complete-guide-2
Time Series with InfluxDB in Java: Complete Guide
Provides an overview of integrating InfluxDB with Java for time-series data handling, including monitoring applications and managing performance metrics.
https://macronepal.com/blog/time-series-with-influxdb-in-java-complete-guide
Implementing Prometheus Remote Write in Java (Version 2)
Explains how to configure Java applications to send metrics data to Prometheus-compatible systems using the remote write feature for scalable monitoring.
https://macronepal.com/blog/implementing-prometheus-remote-write-in-java-a-complete-guide-2
Implementing Prometheus Remote Write in Java: Complete Guide
Provides instructions for sending metrics from Java services to Prometheus servers, enabling centralized monitoring and real-time analytics.
https://macronepal.com/blog/implementing-prometheus-remote-write-in-java-a-complete-guide
Building a TileServer GL in Java: Vector and Raster Tile Server
Explains how to build a TileServer GL in Java for serving vector and raster map tiles, useful for geographic visualization and mapping applications.
https://macronepal.com/blog/building-a-tileserver-gl-in-java-vector-and-raster-tile-server
Indoor Mapping in Java
Explains how to create indoor mapping systems in Java, including navigation inside buildings, spatial data handling, and visualization techniques.