Production Issue Debugging

Production issue debugging in Spring Boot microservices requires more than checking application logs. A failure can originate from application code, JVM resources, database queries, Kafka consumers, network communication, containers, or Kubernetes infrastructure.

This guide explains how to identify, investigate, and resolve production issues using practical debugging techniques, observability tools, JVM diagnostics, and infrastructure commands.

Observability – Core Signals

Observability helps understand the internal state of an application by analyzing its outputs and behaviour.

The five core observability signals are:

  • Logs – What happened?

    • Application events, exceptions, stack traces, errors, and business transactions.

  • Metrics – How often and how badly is it happening?

    • Request count, error rate, response time, CPU, memory, garbage collection, threads, and database connections.

  • Distributed Tracing – Where did the request spend its time?

    • Follow requests across API Gateway, microservices, databases, Kafka, and external APIs.

  • Profiling – What is consuming application resources?

    • CPU-intensive methods, memory allocation, thread contention, deadlocks, and JVM bottlenecks.

  • Events – What changed in the environment?

    • Application deployments, configuration changes, infrastructure changes, scaling events, and database migrations.

How These Signals Work Together

  • Use metrics to identify abnormal behaviour and performance degradation.

  • Use traces to find the failing or slow service.

  • Use logs to understand the actual exception or failure.

  • Use profiling to investigate resource-level bottlenecks.

  • Use deployment and infrastructure events to identify possible triggers.

Correlation IDs and Distributed Tracing

Distributed tracing helps track a request as it travels across multiple microservices and external dependencies. Correlation IDs and trace IDs make it easier to connect logs and traces from different services.

1. Correlation ID and Trace ID

  • Correlation ID: Identifies a business request across multiple services.

  • Trace ID: Identifies an end-to-end distributed trace.

  • Span ID: Identifies an individual operation within a trace.

A typical request flow looks like this:

Client
  |
API Gateway
  |  Trace ID: abc123
  |
Order Service
  |  Span ID: span-01
  |
Payment Service
  |  Span ID: span-02
  |
Inventory Service
     Span ID: span-03

Use a consistent correlation ID across services when you need to search related application logs.

2. Implementing Distributed Tracing

For Spring Boot 3.x and Java 21, use Micrometer Tracing with an OpenTelemetry bridge.

Common dependencies include:

  • micrometer-tracing-bridge-otel

  • opentelemetry-exporter-otlp

  • spring-boot-starter-actuator

Micrometer Tracing integrates with Spring Boot and can automatically add trace and span information to supported logging contexts.

Example configuration:

management:
  tracing:
    sampling:
      probability: 0.1

  otlp:
    tracing:
      endpoint: http://otel-collector:4318/v1/traces

A sampling probability of 0.1 means approximately 10% of eligible traces are sampled. Adjust this according to traffic volume and troubleshooting requirements.

3. Propagating Correlation IDs

You can configure a custom correlation ID as a baggage field:

management:
  tracing:
    baggage:
      remote-fields: x-correlation-id
      correlation:
        fields: x-correlation-id

The correlation ID can then be propagated between supported instrumented services.

Use the auto-configured HTTP client builders for instrumentation:

  • RestClient.Builder

  • RestTemplateBuilder

  • WebClient.Builder

Creating HTTP clients manually, such as using new RestTemplate(), may bypass Spring Boot's automatic instrumentation.

4. Distributed Tracing with Kafka

For asynchronous communication, tracing context should be propagated through Kafka message headers.

Spring Kafka observation can be enabled using:

spring:
  kafka:
    template:
      observation-enabled: true
    listener:
      observation-enabled: true

This helps connect producer and consumer operations in distributed traces.

For asynchronous execution, Reactor pipelines, and custom executors, use Micrometer Context Propagation and appropriate context propagation configuration.

5. Distributed Tracing Tools

  • OpenTelemetry: Vendor-neutral instrumentation and telemetry collection.

  • Micrometer Tracing: Integrates tracing with Spring Boot applications.

  • Grafana Tempo: Stores and queries distributed traces.

  • Jaeger: Distributed tracing platform.

  • Zipkin: Distributed tracing and visualization.

  • AWS X-Ray: Distributed tracing for AWS applications.

For new instrumentation, OpenTelemetry is a good vendor-neutral starting point.

Application Logging and Centralized Log Management

Application logs are one of the most important sources of information when investigating production failures.

A centralized logging system collects logs from multiple services and provides a single place to search and analyze them.

1. Structured Logging

Prefer structured JSON logging over plain-text messages.

Example:

{
  "timestamp": "2026-11-02T10:30:00Z",
  "level": "ERROR",
  "service": "order-service",
  "traceId": "abc123",
  "spanId": "span001",
  "correlationId": "CORR-12345",
  "message": "Payment processing failed",
  "exception": "PaymentTimeoutException"
}

Spring Boot 3.4 and later support built-in structured logging formats.

Example configuration:

logging.structured.format.console=ecs

Other supported formats include Logstash and GELF.

2. Centralized Logging Platforms

ELK Stack

  • Elasticsearch: Stores and indexes application logs.

  • Logstash: Processes and transforms log data.

  • Kibana: Provides log searching, dashboards, and visualization.

Grafana Loki

  • Stores and queries application logs.

  • Integrates with Grafana dashboards.

  • Commonly uses Grafana Alloy for log collection.

OpenSearch

  • Open-source search and analytics platform.

  • Can be used for centralized log storage and investigation.

Splunk

  • Enterprise platform for log analysis, monitoring, and security investigations.

AWS CloudWatch Logs

  • Collects and monitors logs from AWS workloads.

  • Integrates with EC2, Lambda, ECS, EKS, and other AWS services.

3. Log Collection Architecture

A typical centralized logging architecture:

Spring Boot Microservices
          |
          v
    Log Files / Console
          |
          v
     Log Collector
          |
          v
 Centralized Log Platform
          |
          v
    Search and Dashboard

For Loki, avoid using high-cardinality values such as trace IDs and correlation IDs as labels. Search for these values in the log content instead.

Example LogQL query:

{service_name="order-service"} |= "CORR-12345"

4. Logging Best Practices

  • Include timestamp, log level, service name, and trace information.

  • Use appropriate log levels: DEBUG, INFO, WARN, and ERROR.

  • Log exceptions with stack traces when useful.

  • Avoid logging passwords, tokens, personal information, and sensitive payloads.

  • Use consistent formats across services.

  • Avoid excessive logging inside high-volume loops.

  • Configure log rotation and retention policies.

Metrics and Application Monitoring

Metrics help identify abnormal application behaviour before it becomes a major production incident.

Spring Boot Actuator and Micrometer provide application metrics that can be exported to monitoring platforms.

1. Spring Boot Actuator and Micrometer

Add the following dependencies:

  • spring-boot-starter-actuator

  • micrometer-registry-prometheus

Example configuration:

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus

  endpoint:
    health:
      show-details: when_authorized

Secure management endpoints and expose only the endpoints required by your monitoring environment.

2. Prometheus and Grafana

  • Prometheus: Collects and stores time-series metrics.

  • Grafana: Creates dashboards and visualizes metrics.

  • Alertmanager: Handles and routes Prometheus alerts.

Typical monitoring architecture:

Spring Boot Applications
          |
      Micrometer
          |
      Prometheus
          |
        Grafana
          |
     Alertmanager

3. JVM Metrics

Monitor JVM metrics to identify memory, garbage collection, and thread-related problems.

Important metrics include:

MetricPurpose
jvm_memory_used_bytesJVM memory utilization
jvm_gc_pause_secondsGarbage collection pause duration
jvm_threads_states_threadsThread states
process_cpu_usageApplication process CPU usage

Investigate increasing heap usage, frequent garbage collection, long GC pauses, and growing thread counts.

4. API Performance Metrics

Monitor the following HTTP metrics:

  • Request count.

  • Error rate.

  • Average response time.

  • P95 and P99 response time.

  • Requests per second.

  • HTTP 4xx and 5xx responses.

For example, a Prometheus query for the 99th percentile HTTP request duration:

histogram_quantile(
  0.99,
  sum(rate(http_server_requests_seconds_bucket[5m])) by (le)
)

Use histogram metrics to understand latency distribution rather than relying only on average response time.

5. Database Connection Pool Monitoring

For applications using HikariCP, monitor:

  • Active connections.

  • Idle connections.

  • Pending connection requests.

  • Connection acquisition time.

  • Connection timeouts.

A continuously increasing pending connection count may indicate connection pool exhaustion, slow queries, or connections being held for too long.

6. PostgreSQL Monitoring

Useful PostgreSQL monitoring sources include:

  • pg_stat_activity: Shows active database sessions and queries.

  • pg_stat_statements: Provides query execution statistics.

  • pg_blocking_pids: Helps identify blocking sessions.

  • EXPLAIN ANALYZE: Examines query execution plans and actual execution performance.

Example:

SELECT
    pid,
    usename,
    state,
    wait_event_type,
    wait_event,
    query
FROM pg_stat_activity;

Identify blocked queries using:

SELECT
    pid,
    pg_blocking_pids(pid) AS blocking_pids,
    query
FROM pg_stat_activity
WHERE cardinality(pg_blocking_pids(pid)) > 0;

Be careful when using EXPLAIN ANALYZE: it executes the query.

7. MySQL Monitoring

Useful MySQL diagnostic commands:

SHOW FULL PROCESSLIST;
SHOW ENGINE INNODB STATUS;

Monitor:

  • Threads_connected

  • Threads_running

  • Max_used_connections

For deeper query analysis, use Performance Schema, the Slow Query Log, and EXPLAIN ANALYZE (MySQL 8.0.18 and later).

8. Kafka Monitoring

Kafka monitoring should cover both broker health and consumer performance.

Broker and JVM metrics

  • CPU and memory utilization.

  • Request handler idle percentage.

  • Network processor idle percentage.

  • Under-replicated partitions.

  • Offline partitions.

Use Kafka JMX metrics with Prometheus JMX Exporter.

Consumer metrics

  • Consumer lag.

  • Records consumed.

  • Processing rate.

  • Failed message count.

  • Rebalance frequency.

Useful tools include Kafka Exporter and Burrow for consumer lag monitoring.

Example commands:

kafka-consumer-groups.sh \
  --bootstrap-server localhost:9092 \
  --describe \
  --group order-service-group
kafka-topics.sh \
  --bootstrap-server localhost:9092 \
  --list

9. Redis Monitoring

Useful Redis commands:

redis-cli INFO
redis-cli SLOWLOG GET 10
redis-cli --latency

Monitor memory usage, connected clients, command latency, cache hit ratio, and rejected connections.

Avoid expensive production diagnostics such as KEYS * and continuous MONITOR usage on busy Redis instances.

10. Kubernetes Monitoring

Monitor the health and resource utilization of Kubernetes workloads.

Common tools:

  • Prometheus: Collects cluster and application metrics.

  • Grafana: Provides Kubernetes dashboards.

  • kube-state-metrics: Exposes Kubernetes object state.

  • Metrics Server: Provides resource metrics for pods and nodes.

  • Node Exporter: Collects node-level metrics.

  • cAdvisor: Provides container resource metrics.

Application Performance Monitoring (APM)

APM platforms combine application performance metrics, distributed tracing, error tracking, and transaction analysis.

They help identify slow endpoints, database bottlenecks, external API delays, and service-level performance degradation.

1. Popular APM Platforms

  • Dynatrace: Application performance monitoring, distributed tracing, and infrastructure visibility.

  • Datadog APM: Application tracing, service maps, metrics, and log correlation.

  • New Relic: Application monitoring, transaction analysis, and distributed tracing.

  • AppDynamics: Application performance and business transaction monitoring.

  • Elastic APM: Application monitoring integrated with the Elastic ecosystem.

2. When to Use APM

Use APM when you need to:

  • Identify slow API endpoints.

  • Trace requests across multiple microservices.

  • Find database and external API bottlenecks.

  • Investigate high error rates.

  • Compare application performance before and after deployments.

  • Correlate logs, traces, and metrics.

JVM Profiling and Troubleshooting

JVM-level debugging helps identify memory leaks, high CPU utilization, garbage collection problems, thread contention, and deadlocks.

1. JVM Diagnostic Tools

Java Flight Recorder (JFR)

  • Captures JVM runtime events.

  • Helps investigate CPU usage, memory allocation, garbage collection, and thread activity.

  • Can be used in production with appropriate recording settings.

Java Mission Control (JMC)

  • Analyzes Java Flight Recorder recordings.

  • Helps identify performance bottlenecks.

Eclipse Memory Analyzer (MAT)

  • Analyzes heap dumps.

  • Identifies memory leaks and objects retaining large amounts of memory.

VisualVM

  • Monitors JVM CPU, memory, threads, and garbage collection.

  • Supports profiling and heap dump analysis.

async-profiler

  • Low-overhead CPU and allocation profiling.

  • Useful for identifying expensive methods.

Grafana Pyroscope

  • Continuous profiling platform.

  • Helps analyze CPU and memory allocation over time.

2. Capture a Thread Dump

Use jcmd to capture a thread dump:

jcmd <pid> Thread.print

For Java 21, a JSON-format thread dump can also be generated:

jcmd <pid> Thread.dump_to_file \
  -format=json /tmp/threads.json

Inspect thread states to identify:

  • BLOCKED threads.

  • WAITING threads.

  • Deadlocks.

  • Thread pool exhaustion.

  • Long-running operations.

For applications using Java virtual threads, use suitable JFR events and JSON thread dumps. Traditional thread dumps may not show virtual-thread activity in the same way as platform threads.

3. Investigate High CPU Usage

First identify the Java process:

top

Then inspect individual threads:

top -H -p <pid>

Convert the thread ID from decimal to hexadecimal:

printf '%x\n' <tid>

Find the corresponding nid in the thread dump.

This helps identify the Java thread consuming excessive CPU.

4. Capture Heap Information

Check JVM heap information:

jcmd <pid> GC.heap_info

Generate a class histogram:

jcmd <pid> GC.class_histogram

Capture a heap dump:

jcmd <pid> GC.heap_dump /tmp/heapdump.hprof

Analyze the dump using Eclipse MAT or another compatible tool.

Heap dumps can cause pauses, consume significant disk space, and contain sensitive application data. Capture them only after considering production impact and access controls.

5. Start a Java Flight Recorder Session

Start a recording:

jcmd <pid> JFR.start \
  name=ProductionDebug \
  duration=120s \
  filename=/tmp/production-debug.jfr

Analyze the generated recording using Java Mission Control.

6. Configure Automatic Heap Dumps and GC Logs

For applications running in production, consider configuring automatic heap dumps:

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/dumps

Enable garbage collection logging:

-Xlog:gc*:file=/var/log/app/gc.log:time,uptime:filecount=5,filesize=20m

Ensure the configured dump and log directories have sufficient disk space and appropriate permissions.

Step-by-Step Production Debugging

Follow a systematic process instead of randomly restarting services or changing configurations.

Step 1. Understand the Production Impact

First identify the scope and severity of the issue.

  • Is the issue affecting all users or specific users?

  • Is one microservice failing or multiple services?

  • Are requests failing, timing out, or responding slowly?

  • Is the issue intermittent or continuously reproducible?

  • Is there a business-critical transaction affected?

Check dashboards, alerts, and service health before making changes.

Step 2. Check Recent Changes

Investigate recent changes that may have introduced the issue.

  • Application deployments.

  • Configuration changes.

  • Database migrations.

  • Infrastructure changes.

  • Dependency upgrades.

  • Kubernetes scaling or scheduling events.

Compare the current deployment with the previous stable version.

Step 3. Identify the Request

Use the correlation ID, trace ID, or relevant business identifier to identify the affected request.

For example:

correlationId = CORR-12345

Search for this identifier in centralized logs and distributed traces.

Step 4. Analyze Application Logs

Look for:

  • Exceptions and stack traces.

  • Repeated error messages.

  • Timeout exceptions.

  • Authentication and authorization failures.

  • Validation errors.

  • Unexpected application behaviour.

Identify the first meaningful failure rather than focusing only on downstream exceptions.

Step 5. Analyze Distributed Traces

Follow the request across the service boundaries.

Identify:

  • Which service is taking the most time?

  • Which service is returning an error?

  • Is the database operation slow?

  • Is an external API timing out?

  • Is Kafka message processing delayed?

This helps isolate the failing component.

Step 6. Investigate JVM and Application Resources

Check CPU, memory, garbage collection, and thread utilization.

Use:

  • top and htop for CPU.

  • free -m for memory.

  • jcmd for JVM diagnostics.

  • JFR and JMC for profiling.

  • Heap dumps for memory investigations.

  • Thread dumps for thread-related problems.

Step 7. Check External Dependencies

Investigate the health of dependent services and infrastructure.

  • Database availability and query performance.

  • HikariCP connection pool utilization.

  • Kafka broker health and consumer lag.

  • Redis latency and memory.

  • External API response times.

  • DNS and network connectivity.

Step 8. Investigate Infrastructure

Check whether the issue originates outside the application.

  • CPU and memory pressure.

  • Container restarts.

  • OOMKilled events.

  • Kubernetes pod scheduling issues.

  • Network failures.

  • Disk utilization and inode exhaustion.

  • Deployment and scaling events.

Step 9. Identify Root Cause and Apply a Fix

Once the failing component is identified:

  • Reproduce the issue safely where possible.

  • Identify the underlying cause.

  • Apply the smallest appropriate fix.

  • Validate the change in a controlled environment.

  • Follow the organization's production change and rollback procedures.

Avoid applying speculative fixes without understanding their impact.

Step 10. Validate and Prevent Recurrence

After applying the fix:

  • Verify application health.

  • Check error rates and response times.

  • Confirm that dependent services are healthy.

  • Monitor logs, traces, and metrics.

  • Add alerts for the identified failure condition.

  • Document the root cause and preventive actions.

Debugging Linux VM and Containerized Applications

Production Spring Boot applications commonly run on Linux virtual machines, Docker containers, and Kubernetes clusters. Understanding the underlying environment is essential for effective debugging.

1. Linux VM Debugging

Useful Linux commands:

Process and CPU

ps -ef | grep java
pgrep -af java
top
htop

Memory and Disk

free -m
df -h
df -i

System Load and Performance

uptime
vmstat 1

System Logs

journalctl -u <service-name>
dmesg | grep -i -E 'oom|killed process'

Network Diagnostics

ss -tulnp
curl -v http://localhost:8080/actuator/health
nslookup example.com
dig example.com

For deeper network investigation, tcpdump can capture network packets. Use it carefully because packet captures may contain sensitive information.

2. AWS Production Debugging

For applications hosted on AWS, use the following services:

  • Amazon CloudWatch: Collects application and infrastructure logs and metrics.

  • CloudWatch Agent: Collects operating system metrics and logs from EC2.

  • AWS Systems Manager Session Manager: Provides secure access to managed instances without requiring SSH access.

  • AWS CloudTrail: Tracks AWS API activity and account-level changes.

  • AWS X-Ray: Provides distributed tracing and service dependency visualization.

For new instrumentation, consider OpenTelemetry or AWS Distro for OpenTelemetry.

3. Docker Container Debugging

Useful Docker commands:

List running containers

docker ps

Check container resource utilization

docker stats

Inspect container configuration and state

docker inspect <container-id>

View container logs

docker logs -f <container-id>

Inspect Docker events

docker events

Check the container's exit code and OOMKilled status when investigating unexpected restarts.

Exit code 137 commonly indicates that a process received SIGKILL. It may be caused by an out-of-memory kill, but confirm the container state and system events before concluding.

4. Kubernetes Debugging

Useful Kubernetes commands:

Check pods and deployments

kubectl get pods -n <namespace>
kubectl get deployments -n <namespace>
kubectl get services -n <namespace>
kubectl get nodes

Inspect a pod

kubectl describe pod <pod-name> -n <namespace>

Check pod logs

kubectl logs <pod-name> -n <namespace>

For a previously restarted container:

kubectl logs <pod-name> \
  -n <namespace> \
  --previous

Check resource utilization

kubectl top pods -n <namespace>
kubectl top nodes

Check deployment status

kubectl rollout status deployment/<deployment-name> \
  -n <namespace>

Inspect deployment history

kubectl rollout history deployment/<deployment-name> \
  -n <namespace>

Rollback a deployment

kubectl rollout undo deployment/<deployment-name> \
  -n <namespace>

Access a running container

kubectl exec -it <pod-name> \
  -n <namespace> \
  -- /bin/sh

For minimal or distroless containers, use an ephemeral debug container when appropriate:

kubectl debug -it <pod-name> \
  -n <namespace> \
  --target=<container-name> \
  --image=busybox

5. Kubernetes Memory and CPU Issues

Investigate the following conditions:

  • OOMKilled: Container terminated because it exceeded its memory limit.

  • CrashLoopBackOff: Container repeatedly fails to start or stay running.

  • Pending: Pod cannot be scheduled.

  • CPU throttling: Container is being restricted by CPU limits.

  • Node pressure: Node has insufficient memory, disk, or other resources.

A Java application needs memory beyond its configured heap, including metaspace, thread stacks, direct buffers, and other native allocations.

Do not allocate the entire container memory limit to the JVM heap.

Resilience and Fault Tolerance

Production microservices must handle temporary failures in dependent services without causing cascading failures.

Resilience patterns help maintain application stability when databases, external APIs, or other microservices become unavailable.

1. Circuit Breaker

Prevents repeated calls to a failing service.

Common states:

  • CLOSED: Requests are allowed.

  • OPEN: Requests are rejected temporarily.

  • HALF_OPEN: A limited number of requests are allowed to test recovery.

Use Resilience4j Circuit Breaker to implement this pattern.

2. Retry

Retries transient failures.

Best practices:

  • Retry only appropriate transient failures.

  • Use bounded retry attempts.

  • Apply exponential backoff and jitter.

  • Retry only idempotent operations, or use appropriate idempotency protection.

  • Avoid retry storms.

3. Bulkhead

Isolates resources so that failures in one dependency do not exhaust resources across the entire application.

For example, use separate thread pools or concurrency limits for different external service calls.

4. Timeout and TimeLimiter

Set appropriate timeouts for HTTP requests, database operations, and external service calls.

Avoid allowing requests to wait indefinitely for an unavailable dependency.

5. Rate Limiter

Controls the number of requests accepted within a configured time window.

This helps protect services from excessive traffic.

6. Fallback

Provides an alternative response when a dependent operation fails.

Fallbacks should preserve business correctness. Avoid returning misleading success responses when a critical operation has actually failed.

7. Kafka Dead Letter Topics

Use Dead Letter Topics (DLTs) to isolate messages that cannot be processed successfully after configured retries.

Investigate failed messages, fix the underlying issue, and implement a controlled replay process.

Production Best Practices

1. Health Checks

Implement Spring Boot Actuator health endpoints.

Use Kubernetes probes appropriately:

  • Liveness Probe: Determines whether the application needs to be restarted.

  • Readiness Probe: Determines whether the application can receive traffic.

  • Startup Probe: Allows sufficient time for slow application startup.

Avoid making liveness checks dependent on every external service because temporary dependency failures can cause unnecessary restarts.

2. Monitoring and Alerting

Define Service Level Indicators (SLIs) and Service Level Objectives (SLOs) for important application behaviour.

Monitor:

  • Availability.

  • Request latency.

  • Error rates.

  • Resource utilization.

  • Dependency health.

  • Message processing delays.

Configure alerts around meaningful service-level symptoms rather than every individual metric.

3. Secure Production Diagnostics

  • Secure Spring Boot Actuator endpoints.

  • Restrict access to heap dumps and thread dumps.

  • Do not expose sensitive configuration.

  • Avoid logging credentials, access tokens, or personal information.

  • Apply appropriate log retention and access policies.

4. Graceful Shutdown

Configure applications to stop accepting new requests and complete in-flight work where possible.

For Kubernetes deployments, configure appropriate termination grace periods and ensure application shutdown behaviour is compatible with the deployment lifecycle.

5. Resource Management

  • Configure JVM heap based on container memory limits.

  • Monitor garbage collection.

  • Tune HikariCP connection pools according to database capacity.

  • Configure appropriate thread pool sizes.

  • Monitor Kafka consumer lag.

  • Review CPU throttling and memory pressure.

Recommended Modern Observability Stack

The following stack provides a practical starting point for Java 21 and Spring Boot microservices.

AreaRecommended ToolPurpose
Application FrameworkJava 21, Spring Boot 3.xMicroservice development
LoggingSLF4J, LogbackApplication logging
Log CorrelationMDC, Micrometer TracingTrace and correlation context
InstrumentationOpenTelemetryTelemetry collection and propagation
Log ManagementGrafana Loki, AlloyCentralized log collection and querying
MetricsPrometheus, MicrometerMetrics collection
DashboardsGrafanaMonitoring and visualization
Distributed TracingGrafana TempoTrace storage and querying
ProfilingJFR, JMC, async-profilerJVM performance analysis
Memory AnalysisEclipse MATHeap dump investigation
Database MonitoringHikariCP metrics, DB statisticsConnection and query monitoring
Kafka MonitoringJMX Exporter, Kafka ExporterBroker metrics and consumer lag
ResilienceResilience4jFault tolerance
InfrastructureLinux, Docker, KubernetesRuntime diagnostics
AlertingPrometheus AlertmanagerAlert routing

Key Takeaway

Production debugging is a systematic process of identifying symptoms, narrowing down the failing component, investigating the root cause, and validating the fix.

For Spring Boot microservices, combine logs, metrics, distributed tracing, JVM profiling, and infrastructure diagnostics to understand what is happening across the entire system.

A well-designed observability setup does more than report failures. It helps engineering teams detect issues early, reduce troubleshooting time, improve application reliability, and prevent recurring production incidents.

OpenShift


OpenShift is a Kubernetes-based enterprise container platform developed by Red Hat.

It provides everything you need to build, deploy, manage, and scale applications using containers.

Think of OpenShift as:

  • Kubernetes + more automation + built-in security + developer tools + enterprise support.


Key Components of OpenShift

1. Kubernetes (Core Orchestrator)

OpenShift is built on top of Kubernetes and includes:

  • Pod & container orchestration

  • Service discovery

  • Auto-scaling

  • Load balancing

2. OpenShift API Server

  • Central control point

  • Manages all cluster operations

3. OpenShift Container Registry (OCR)

  • Built-in Docker-compatible registry

  • Stores images internally in a secure manner

4. OpenShift Router

  • Based on HAProxy

  • Handles external traffic

  • Supports routes, TLS, sticky sessions, etc.

5. Operators

  • Automate lifecycle of apps & infrastructure (install → upgrade → manage)

  • OpenShift uses OperatorHub to provide many certified operators

6. Developer Tools

  • Source-to-Image (S2I): build apps from source code

  • Dev Spaces (formerly CodeReady Workspaces)

  • Pipelines (Tekton-based CI/CD)

  • GitOps (ArgoCD)


Types of OpenShift Platforms

1. OpenShift Container Platform (OCP)

  • Self-managed version

  • Install on your own infrastructure (on-prem, private cloud, bare-metal)

2. OpenShift Online

  • Fully managed SaaS offering by Red Hat

3. OpenShift Dedicated

  • Customer-specific cluster

  • Managed by Red Hat on AWS or GCP

4. ROSA (Red Hat OpenShift on AWS)

  • Joint Red Hat–AWS managed service

5. ARO (Azure Red Hat OpenShift)

  • Joint Red Hat–Microsoft managed platform


Architecture Overview

OpenShift has 3 major layers:

1. Master/Control Plane

  • API Server

  • etcd

  • Scheduler

  • Controller Manager

  • Machine API

2. Worker Nodes

  • Run containers/pods

  • Include:

    • CRI-O or Docker runtime

    • Kubelet

    • Node services

3. Services Layer

  • Monitoring (Prometheus)

  • Logging / EFK stack

  • Image registry

  • Networking (OpenShift SDN / OVN-Kubernetes)


Key Features of OpenShift

Enterprise Security

  • Role-Based Access Control (RBAC)

  • Image scanning (Clair)

  • Network policies

  • Security Context Constraints (SCC)

Built-in CI/CD

  • Tekton pipelines

  • ArgoCD for GitOps

Developer-Friendly

  • Web console + dashboard

  • S2I build system

  • UI-based deployment

  • Integrated logging & monitoring

Autoscaling

  • Horizontal Pod Autoscaler

  • Cluster autoscaler

  • Machine autoscaler

Multi-Cloud + Hybrid Support

  • Deploy anywhere

  • Consistent experience across environments


How Deployment Works in OpenShift

  1. Developer pushes code to Git repo

  2. OpenShift pipeline triggers build

  3. Build creates Docker image / S2I image

  4. Image is stored in internal registry

  5. DeploymentConfig or Deployment creates pods

  6. Router exposes app through a public route


Command Line Tools

1. oc CLI (OpenShift Client)

Used to interact with OpenShift, similar to kubectl but with extra features:

oc login oc new-project oc new-app oc get pods oc logs oc expose service/myapp

2. kubectl

Also works because OpenShift is Kubernetes under the hood.


OpenShift vs Kubernetes

Feature

Kubernetes

OpenShift

Installation

Complex

Automated installer

Security

Basic

Strict, enterprise-grade

UI Dashboard

Basic

Advanced web console

Built-in CI/CD

No

Yes (Tekton + ArgoCD)

Image registry

External

Built-in

Multi-tenancy

Limited

Strong security & isolation

Developer tools

Minimal

Strong developer experience


Security Enhancements in OpenShift

  • SCCs (Security Context Constraints)

  • Enforces non-root containers

  • Audit logs

  • TLS everywhere

  • Vulnerability scanning


Use Cases of OpenShift

  • Microservices architecture

  • Modernizing legacy applications

  • Hybrid cloud deployments

  • Banking & FinTech applications

  • Telecom workloads

  • Enterprise CI/CD pipelines


Advantages

  • Enterprise-ready

  • Highly secure

  • Great for large teams

  • Rich developer ecosystem


Disadvantages

  • Cost is high

  • Complex for small projects

  • Steeper learning curve than basic Kubernetes



What Is OpenShift Local?

OpenShift Local is a single-node OpenShift cluster (1 master + 1 worker inside one VM).
It is used for:

  • Local learning

  • Testing

  • Small development

  • Proof-of-concept






Setup OpenShift


Enable Hyper-V on Windows 10/11 Home Edition

Option 1: Using PowerShell (Admin Mode)
Run this in PowerShell (as Administrator):

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All

Restart your PC.

Option 2: Enable using reference script

Reference: https://mylemans.online/posts/EnableHyperv-Windows11-Home/

Cross-check: Go to → Control Panel → Programs → Turn Windows features on or off → Ensure Hyper-V is checked.


Step 1 : Create Red Hat Developer Account

Go to: https://developers.redhat.com/register
Sign up (free) or log in with an existing Red Hat account.

You’ll need this account to download OpenShift Local and your Pull Secret.


Step 2 : Download and Install OpenShift Local (CRC)

Visit: https://developers.redhat.com/products/openshift-local/overview

Download: crc-windows-amd64.msi and install it.

Verify installation:

crc version

You should see version output.

Download Pull Secret

Go to: https://cloud.redhat.com/openshift/install/pull-secret
Save it somewhere: D:\Software\crc\pull-secret.txt


Step 3 : Setup the OpenShift Cluster

Run in CMD:

crc setup

This step:

  • Prepares virtualization & networking

  • Validates system

  • Downloads required drivers

  • Sets up image cache


Step 4 : Start the OpenShift Cluster

Run:

crc start --pull-secret-file D:\Software\crc\pull-secret.txt

You’ll see output like:

👉 Save these credentials safely.

This step will:

  • Start a VM in Hyper-V

  • Create the OpenShift cluster

  • Configure kubeadmin login

  • Set up networking

Time required: 10–20 minutes.


Step 5 : Login to OpenShift Cluster

CLI Login

Run:

crc oc-env

👉 Copy the output and run it (It will sets up the oc CLI path).

Login:

oc login -u kubeadmin -p <password>

(Password was shown during crc start.)


Web Console Login

Open browser →
https://console-openshift-console.apps-crc.testing/

Login:

  • Username: kubeadmin

  • Password: shown during crc start

You now have a running local OpenShift cluster.



OpenShift Local Is Now Ready!

You can:

  • Create projects

  • Deploy apps

  • Use S2I

  • Test routes

  • Try pipelines

  • Explore Operators


How to fully reset our CRC/OpenShift Local cluster

1. Stop the CRC VM: crc stop

2. Delete the CRC VM Completely: crc delete 
👉This clears the entire OpenShift cluster

3. Delete the CRC Cache + Configuration (Optional but recommended): Delete following folders manually,

  • C:\Users\<your-username>\.crc\
  • C:\Users\<your-username>\.kube\
4. Start CRC fresh: crc start --pull-secret-file D:\Software\crc\pull-secret.txt 
👉This will create a brand-new OpenShift cluster.

5. Login Again (fresh credentials):
Get credentials: crc console --credentials
Than login: oc login -u kubeadmin -p <password>

6. Verify API Server: oc whoami
You should now see something kubeadmin






Deploy a Spring Boot Application 

(Podman Containerized Application)

on OpenShift


Step 1 : Prepare Your App & Build Podman Image

  1. Build Spring Boot JAR:

        mvn clean install
  1. Update your application.properties or application.yml:

spring.data.mongodb.uri=mongodb://10.107.6.110:27017/truck_lease_service_db

(Use your system IP from ipconfig.)

  1. Build Podman image inside project folder (where your Containerfile is):

        podman build -t springboot-mongodb-example .
  1. Verify image:

        podman images


Step 2 : Login Podman to OpenShift Internal Registry

Make sure you set CRC environment variable PATH value: C:\Users\siraj\.crc\bin\oc

On OpenShell: Get OpenShift token 

$TOKEN = oc whoami -t

Login Podman:

podman login --tls-verify=false -u kubeadmin -p $TOKEN default-route-openshift-image-registry.apps-crc.testing


Step 3 : Tag and Push Your Image to OpenShift

Create project:

oc new-project springboot-demo

Tag your image:

podman tag springboot-mongodb-example:latest default-route-openshift-image-registry.apps-crc.testing:443/springboot-demo/springboot-mongodb-example:latest

👉 Note: Due to firewall restrictions on my local system, I was unable to push the image to the local OpenShift cluster’s image registry using the following step. As an alternative, the Podman image can also be pushed to Docker Hub and then deployed and run in the local OpenShift cluster.

Push the image:

podman push --tls-verify=false default-route-openshift-image-registry.apps-crc.testing:443/springboot-demo/springboot-mongodb-example:latest

Step 4 : Deploy Application in OpenShift

Deploy:

oc new-app springboot-mongodb-example --image-stream=springboot-mongodb-example:latest
oc expose svc/springboot-mongodb-example

Check the route:

oc get routes

Output example:

springboot-mongodb-example springboot-mongodb-example-springboot-demo.apps-crc.testing

Open:

http://springboot-mongodb-example-springboot-demo.apps-crc.testing/api/trucks

Your Spring Boot app is now deployed and accessible!


Step 5 : Verify Logs & Connectivity

Logs:

oc logs -f deployment/springboot-mongodb-example

Verify MongoDB connectivity:

oc rsh deployment/springboot-mongodb-example
nc -zv 10.107.6.110 27017

If you see Connection succeeded! → MongoDB is reachable.


Step 6 : Access Application Locally

Browser or CLI:

curl http://springboot-mongodb-example-springboot-demo.apps-crc.testing/api/trucks

You should receive your API output.


Summary

StepActionCommand/URL
1Register Red Hat Accounthttps://developers.redhat.com/register
2Download and install CRChttps://developers.redhat.com/products/openshift-local/overview
5Pull Secrethttps://cloud.redhat.com/openshift/install/pull-secret
6Setup CRCcrc setup
7Start CRCcrc start --pull-secret-file D:\Software\crc\pull-secret.txt
8Login to Consolehttps://console-openshift-console.apps-crc.testing
9Login CLIoc login -u kubeadmin -p <password>
10Build Image (Podman)podman build -t springboot-mongodb-example .
11Push to OpenShiftpodman push default-route-openshift-image-registry.apps-crc.testing/springboot-demo/springboot-mongodb-example
12Deployoc new-app & oc expose svc/...






Deploy a Spring Boot Application

(without containerized)

on Openshift using S2I

  ðŸ‘‰ No containerization needed — no Podman or Docker required

This approach allows OpenShift to automatically build your app from your GitHub repository using Source-to-Image (S2I).

Step 1: Build Your Spring Boot Project

mvn clean package

Push your project code to GitHub or GitLab.

👉 you can skip this Step-1. It is NOT required for OpenShift S2I deployment. This is only for local testing.

Step 2: Login to OpenShift

Login using the OpenShift CLI:

oc login -u kubeadmin -p <password>

Note: You can get credentials with command crc console --credentials

Create a new OpenShift project:

oc new-project springboot-helloworld-project

Step 3: Deploy the Application Using S2I

Deploy your application using the Red Hat UBI 8 OpenJDK 21 S2I builder image:

oc new-app --strategy=source registry.access.redhat.com/ubi8/openjdk-21~https://github.com/SirajChaudhary/springboot-helloworld-service.git --name=springboot-helloworld-app

OpenShift S2I will automatically:
  • Clone your Git repository

  • Build the Spring Boot JAR using Maven (inside OpenShift)

  • Create an image via S2I

  • Deploy the application pod

After completing this step, wait for 5–10 minutes to allow the build to finish within the OpenShift cluster.

Step 4: Monitor Build and Deployment

Track the build logs (Note: Track the build with following command and make sure build complete before hitting next commands):

oc logs -f buildconfig/springboot-helloworld-app

Check pod status:
oc get pods

Step 5: Expose the Service (Create a Route)

Expose your application so it can be accessed externally:

oc expose service/springboot-helloworld-app

Retrieve the route URL:

oc get route

Open the route URL in a browser. your Spring Boot Hello World Application will now be running on OpenShift!


Step 6: Access OpenShift deployed microservice API

curl http://springboot-helloworld-app-springboot-helloworld-project.apps-crc.testing/hello