
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
To successfully run Micronaut on Kubernetes, you must move beyond basic deployments and configure the platform-specific integration that makes this framework unique. Unlike traditional Spring Boot applications, Micronaut’s compile-time dependency injection and low-memory footprint offer distinct advantages in containerized environments, but only if you correctly configure liveness probes, resource requests, and environment variable mapping. This guide provides the exact configuration patterns I use in production to ensure your Kubernetes resource limits and requests align with Micronaut’s actual runtime behavior.
kubernetes feature in your build, define HTTP-based liveness and readiness probes pointing to /health/liveness and /health/readiness, set explicit memory requests matching your JVM heap plus overhead, and prefer GraalVM native images for sub-second startup times and minimal resource consumption.How do you configure Micronaut health checks for Kubernetes probes?
Kubernetes relies on liveness and readiness probes to manage pod lifecycle, and Micronaut exposes dedicated endpoints specifically designed for this purpose. A common mistake is using the generic /health endpoint for both probes, which can cause cascading restarts when a single downstream dependency fails. You should always separate these concerns to maintain cluster stability.
Distinguishing liveness from readiness
Liveness determines if the application process is functional, while readiness determines if it can accept traffic. In Micronaut, enable the management endpoints and expose them on a separate port to prevent external access to internal operational data. Add the following to your application.yml:
endpoints:
health:
enabled: true
sensitive: false
details-visible: ANONYMOUS
all:
port: 8081
micronaut:
application:
name: my-service
server:
port: 8080 This configuration binds management endpoints to port 8081 while your business logic remains on 8080. Your Kubernetes deployment should then reference these specific paths:
- Liveness:
httpGeton/health/livenessport 8081 - Readiness:
httpGeton/health/readinessport 8081 - Startup probe: Use
/health/startedfor native images to avoid premature kills during initialization
If you are integrating with databases or message brokers, consider reading about PostgreSQL administration essentials to understand how connection pool exhaustion can falsely trigger readiness failures. Configure custom health indicators in Micronaut to report degraded status rather than down status for non-critical dependencies.
What are the best practices for setting Kubernetes resource limits with Micronaut?
Micronaut’s predictable memory usage makes right-sizing containers easier than with reflection-heavy frameworks, but you still need to account for JVM overhead, metaspace, and direct buffers. Setting requests too low causes OOMKilled errors; setting them too high wastes cluster capacity and increases cloud bills.
Calculating accurate memory requests
For JVM-based Micronaut applications, a reliable baseline formula is: Heap Size + Metaspace (256MB) + Thread Stacks (1MB × thread count) + Direct Memory (256MB). If your application uses 512MB heap with 200 threads, your minimum request should be approximately 1.2GB. Always set limits equal to or slightly above requests to avoid burstable QoS penalties in production namespaces.
| Deployment Mode | Memory Request | CPU Request | Startup Time | Best For |
|---|---|---|---|---|
| JVM (Standard) | 1Gi – 2Gi | 500m – 1000m | 3s – 8s | Complex apps, dynamic proxies |
| Native Image (GraalVM) | 128Mi – 256Mi | 100m – 250m | 0.05s – 0.3s | Serverless, high-density, scale-to-zero |
| JVM + CDS | 768Mi – 1.5Gi | 400m – 800m | 1.5s – 4s | Balance of compatibility and speed |
Monitor actual usage with Prometheus before finalizing values. My article on Prometheus metrics monitoring fundamentals covers the specific JVM exporters you need to track heap utilization and GC pressure accurately. Adjust requests based on P95 memory usage over a 7-day period, not peak spikes during load tests.
How does Micronaut service discovery work natively in Kubernetes?
You do not need Consul, Eureka, or a service mesh just to discover other services within the same cluster. Micronaut includes a native Kubernetes service discovery module that queries the Kubernetes API directly, eliminating the operational overhead of maintaining additional infrastructure. This approach reduces latency and simplifies compliance audits by removing extra network hops.
Enabling Kubernetes-native discovery
Add the micronaut-kubernetes-discovery-client dependency to your project. Micronaut will automatically resolve service names like http://payment-service to the corresponding Kubernetes Service DNS entry. No annotation changes are required in your declarative HTTP clients:
@Client("payment-service")
public interface PaymentClient {
@Get("/api/v1/payments/{id}")
Payment getPayment(String id);
} Ensure your service account has RBAC permissions to list services and endpoints in the namespace. Without this, discovery fails silently and falls back to DNS-only resolution, losing load-balancing awareness. For cross-namespace communication, specify the fully qualified domain name (service.namespace.svc.cluster.local) or configure namespace watching in your Micronaut configuration.
Should you use GraalVM native images when you run Micronaut on Kubernetes?
Native images transform your Micronaut application into a standalone executable with near-instant startup and minimal memory footprint. This is particularly valuable in Kubernetes environments where node density, scaling responsiveness, and cost efficiency directly impact operational budgets. However, native compilation introduces build-time complexity and restricts certain dynamic features.
When native images deliver measurable ROI
Choose native images when your workload scales frequently, runs in serverless-like patterns (Knative, KEDA), or operates under strict memory constraints. The reduction from 1.5GB to 150MB per pod allows 10x higher density on the same nodes. Startup times drop from seconds to milliseconds, making horizontal pod autoscaling genuinely responsive to traffic spikes rather than lagging behind demand.
When to stay on the JVM
Stick with standard JVM deployments if your application relies heavily on reflection-based libraries incompatible with GraalVM, requires dynamic class loading, or has long-lived processes where JIT optimization outperforms AOT compilation after warmup. Debugging native images in production is also significantly harder; stack traces lack line numbers and tooling support is limited compared to mature JVM profilers.
For teams managing secrets across both deployment modes, review Kubernetes secrets management done right to ensure environment variable injection works identically whether you run JVM or native binaries. Native images read environment variables at runtime, but some Micronaut configuration binding behaves differently during AOT compilation.
How do you optimize Micronaut startup performance in Kubernetes clusters?
Even on the JVM, Micronaut starts faster than most Java frameworks because it avoids runtime reflection scanning. You can push this advantage further with Class Data Sharing (CDS), parallel bean initialization, and lazy loading of non-critical components. These optimizations reduce readiness probe failures during rolling updates and improve deployment velocity.
- Enable AppCDS: Generate a shared archive during your Docker build using
-XX:ArchiveClassesAtExit, then reference it at runtime with-XX:SharedArchiveFile. This cuts classloading time by 30–40%. - Parallel initialization: Set
micronaut.bean-creation.parallel=trueto initialize independent beans concurrently. Measure the impact; some applications see no benefit if beans have sequential dependencies. - Lazy beans: Annotate expensive, infrequently-used beans with
@Contextscope removed or use@Factorywith lazy providers. Defer database migration runners to post-startup hooks if they block readiness unnecessarily. - Tune GC for containers: Use G1GC with
-XX:MaxRAMPercentage=75.0instead of fixed heap sizes. This respects container memory limits dynamically and avoids OOMKilled events when Kubernetes adjusts resources.
Production checklist for running Micronaut on Kubernetes
Deploying Micronaut successfully requires attention to details that generic Kubernetes tutorials overlook. Verify each item before promoting to production:
- Management endpoints isolated on a separate port with network policies restricting access
- Liveness and readiness probes targeting correct paths with appropriate initial delays
- Resource requests derived from observed P95 memory usage, not guesses
- Service account RBAC scoped to minimum required permissions for discovery
- Configuration externalized via ConfigMaps with immutable flags for cache safety
- Graceful shutdown enabled with preStop hook delay matching termination grace period
- Structured logging configured for container log aggregation (JSON format preferred)
If you are building observability into your Micronaut services from day one, start with instrumenting an app with OpenTelemetry to capture traces, metrics, and logs through a unified pipeline. Micronaut has first-class OpenTelemetry support that auto-instruments HTTP clients, database calls, and messaging without manual span creation.
Next steps for your Micronaut Kubernetes deployment
Running Micronaut on Kubernetes gives you a compelling combination of developer productivity and operational efficiency when configured correctly. Start with JVM deployments to validate functionality, profile resource usage under realistic load, then evaluate native images for workloads where density and startup latency justify the build complexity. Every configuration decision should be backed by measurement, not assumptions borrowed from other frameworks.
If your team needs help designing production-grade Micronaut deployments, optimizing existing clusters, or establishing compliance-ready infrastructure patterns, reach out to discuss your specific requirements. I work with engineering teams across Nepal and globally to build systems that scale safely and pass audits confidently.