☁️ Cloud & DevOps

Kubernetes Alert Diagnostics: A Pragmatic Pipeline Guide

Marcus Cole
Marcus Cole
Cloud & DevOps Lead

Platform engineer who's been through every infrastructure era — bare metal, VMs, containers, serverless. Has strong opinions about YAML files and even stronger opinions about over-engineering.

incident response runbooksCNCF toolsobservability stackmanaged workflows

I have racked physical servers in data centers where the ambient noise required ear protection. Now, we deploy to virtual clusters in regions we have never visited. The hardware changed, but the 3 AM pager anxiety hasn't. Today, we are going to look at Kubernetes alert diagnostics, and we are going to do it without the hype.

The Reality Check: 3 AM and the Sea of Dashboards

Let's be honest about what happens when a production alert fires in a modern cloud-native environment.

We adopted microservices to decouple our deployments. We added service meshes to handle the network complexity. We deployed the full CNCF observability stack—Prometheus for metrics, Loki for logs, Tempo for traces. We built a system so observable that it generates terabytes of telemetry a day.

Yet, when the PagerDuty alarm goes off at 3:14 AM because a checkout service pod is crash-looping, what do you actually do? You sit up in bed, open your laptop, and manually copy the pod name from Slack. You paste it into a Grafana dashboard. You query Loki. You run kubectl describe pod.

The horrible complexity of trendy architectures is that they give us infinite data but zero context. We have built world-class libraries, but we forgot to build the index card system. The operator is still expected to manually walk every aisle, correlating timestamps across five different browser tabs while the business loses money.

The Core Problem: The Missing Link in the Observability Stack

The real bottleneck in our infrastructure isn't a lack of metrics or poorly configured dashboards. The bottleneck is the manual correlation of disparate data sources.

We rely on tired human beings to act as the "glue" between Prometheus, Loki, and the Kubernetes API during an incident. The data is there, but the pipeline connecting the alert to the actual investigation is broken. Recent shifts in the DevOps community, as seen at DevOps Experience 2026, highlight that the industry is finally trying to fix this plumbing by introducing managed workflows that handle the initial triage. But before we rely on external managed execution layers, we need to understand how the underlying mechanics work.

Under the Hood: The ReAct Pattern and Harbor Logistics

Before we build anything, let's strip away the magic and look at how a diagnostic engine actually works under the hood.

Think of your Kubernetes cluster like a massive commercial shipping harbor.

An alert fires: "Cargo Ship 404 is delayed."

In the old days, the port manager (you) would have to manually call the weather station (Prometheus), check the crane maintenance logs (Loki), and call customs (Kubernetes API) to figure out why the ship is stuck.

Modern diagnostic engines use something called the ReAct pattern (Reasoning and Acting). Instead of the port manager doing the legwork, a dispatcher (the engine) receives the alert. The dispatcher doesn't just blindly guess; they pull out a strictly defined Standard Operating Procedure—the runbook.

The dispatcher reads the alert, looks at the runbook, and decides on the first tool to use. They check the weather. Based on that result, they decide the next step. If the weather is clear, they check the cranes. They gather all this context, package it into a neat dossier, and hand it to the port manager.

The dispatcher doesn't fix the ship. They just do the tedious correlation so the manager can make an informed decision immediately.

Alertmanager Diagnostic Engine Markdown Runbook Prometheus Loki Kube API Slack Thread

The Pragmatic Solution: Building the Pipeline

We are going to build a mechanized diagnostic pipeline. When an alert fires, it will trigger a managed workflow that reads a markdown runbook, executes read-only queries against our CNCF tools, and drops the context into a Slack thread.

We are not replacing the engineer. We are replacing the first 15 minutes of tedious copy-pasting.

Step-by-Step Tutorial: Mechanizing Your Runbooks

Prerequisites

Before we start plumbing, you need your tools laid out on the workbench:
  • A running Kubernetes cluster (EKS, GKE, or local kind cluster).
  • Prometheus and Alertmanager configured and capturing metrics.
  • A diagnostic engine deployed in your cluster (e.g., HolmesGPT or a similar CNCF sandbox tool that supports ReAct workflows).
  • A Slack workspace with an incoming webhook configured.

Step 1: Writing the Metadata-Driven Runbook

The Why:
The engine is only as smart as the instructions you give it. If you just point an engine at a cluster without boundaries, it will hallucinate or waste time querying irrelevant logs. We use markdown because it is human-readable, easily stored in Git, and simple for a reasoning engine to parse. The metadata header acts as a strict boundary, telling the engine exactly which tools it is allowed to use for this specific namespace.

Create a file named checkout-service-runbook.md and store it in your repository:

## Meta
scope: namespace=checkout-prod
tools: kubectl, prometheus, loki
caution: payment-gateway containers are excluded from centralized logging due to PCI compliance -> use kubectl logs directly.

Investigation Steps

1. If a pod is in CrashLoopBackOff, first check the previous container exit code using kubectl. 2. Query Prometheus for container_memory_usage_bytes over the last 30 minutes to check for OOM spikes. 3. Pull the last 50 lines of logs from Loki for the affected pod, filtering for "ERROR" or "FATAL". 4. Summarize the findings and highlight any immediate memory pressure or database connection timeouts.

Step 2: Scoping the Execution Sandbox (RBAC)

The Why:
Security in Kubernetes fundamentally relies on the principle of least privilege. You should never give a diagnostic engine cluster-admin rights. If the engine's logic fails, or if a bad actor manages to inject a prompt via an alert label, the engine should only have the ability to read telemetry, not alter state. We isolate the engine's runtime concerns using a strict Role-Based Access Control (RBAC) policy.

Apply this ClusterRole and ClusterRoleBinding to sandbox your engine:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: diagnostic-engine-readonly
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log", "events", "services", "endpoints"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets", "daemonsets"]
  verbs: ["get", "list", "watch"]

apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: diagnostic-engine-binding subjects: - kind: ServiceAccount name: diagnostic-engine-sa namespace: observability roleRef: kind: ClusterRole name: diagnostic-engine-readonly apiGroup: rbac.authorization.k8s.io

Step 3: Routing the Alert

The Why:
Alertmanager is the central nervous system of our observability stack. By default, it routes alerts directly to Slack or PagerDuty. We need to intercept that flow. We configure Alertmanager to send a webhook to our diagnostic engine first. The engine will process the alert, run the runbook, and then forward the enriched payload to Slack.

Update your alertmanager.yml configuration:

route:
  group_by: ['alertname', 'namespace']
  group_wait: 10s
  group_interval: 5m
  repeat_interval: 3h
  receiver: 'diagnostic-pipeline'

receivers:
- name: 'diagnostic-pipeline'
  webhook_configs:
  - url: 'http://diagnostic-engine.observability.svc.cluster.local:8080/api/v1/alerts'
    send_resolved: true

Verification: Testing the Plumbing

To confirm this works, we shouldn't wait for a real 3 AM failure. We will force a controlled failure.

1. Deploy a dummy pod configured to consume memory until it crashes (an intentional OOMKilled scenario) in the checkout-prod namespace.
2. Watch your Prometheus targets to ensure the alert fires.
3. Check your Slack channel.

If the pipeline is functioning, you won't just see a generic "High Memory Usage" alert. You will see a threaded message containing:

  • The alert details.

  • A note that the engine fetched checkout-service-runbook.md.

  • The exit code of the pod (137 for OOMKilled).

  • A snippet of the Prometheus memory graph data.

  • The last few lines of the pod's logs.


Troubleshooting Common Pitfalls

The engine returns "Unauthorized" or "Forbidden" when fetching logs.
This is almost always an RBAC issue. Ensure the ServiceAccount attached to the diagnostic engine's deployment matches the one specified in your ClusterRoleBinding. Remember that pods/log is a separate resource from pods in Kubernetes RBAC.

The engine ignores the runbook and checks the wrong tools.
Check your metadata scope. If the alert fires for a namespace that doesn't match namespace=checkout-prod, the engine will fall back to its default, unguided behavior. Ensure your Alertmanager routing labels perfectly match the scope defined in your markdown files.

Slack messages are delayed by several minutes.
Diagnostic workflows take time to execute multiple queries. If your engine takes too long, Alertmanager might time out the webhook. Check the engine's logs to see if it is hanging on a slow Loki query. You may need to optimize your Loki log retention or restrict the time window the engine is allowed to query (e.g., limit to the last 5 minutes instead of 30).

What You Built

You just built a systematized incident response pipeline. You took the tribal knowledge trapped in your senior engineers' heads, codified it into a markdown runbook, and wired it to an execution engine that gathers context while you are still making your coffee. You haven't replaced the need for engineering judgment; you've just automated the busywork.

There is no perfect system. There are only recoverable systems.

Frequently Asked Questions

Why use markdown for incident response runbooks instead of YAML or code? Markdown is universally readable by both humans and parsing engines. Code rots and requires maintenance, while YAML can be difficult to read during a high-stress incident. Markdown strikes the perfect balance between structured metadata (headers) and flexible, human-centric instructions.
Can this pipeline automatically restart pods or scale deployments? Technically yes, but pragmatically, no. You should strictly limit the execution sandbox to read-only operations (GET, LIST, WATCH). The goal of this pipeline is diagnostics and context-gathering, not blind remediation. State changes should remain in the hands of the operator or dedicated controllers like HPA.
What happens if the diagnostic engine itself goes down? Your Alertmanager configuration should have a fallback receiver. If the webhook to the diagnostic engine fails or times out, Alertmanager should be configured to route the raw, unenriched alert directly to your paging system (e.g., PagerDuty) to ensure you never miss a critical alert.
Does this replace my existing CNCF tools like Grafana? Absolutely not. This pipeline relies entirely on your existing observability stack. The engine acts as a client querying Prometheus and Loki on your behalf. Grafana remains essential for deep-dive visual exploration once you review the initial diagnostic dossier.

📚 Sources

Related Posts

☁️ Cloud & DevOps
AWS Sustainability API: Pragmatic Carbon Metrics Tutorial
Apr 13, 2026
☁️ Cloud & DevOps
Pragmatic Observability: Surviving Modern DevOps Sprawl
Apr 23, 2026
☁️ Cloud & DevOps
Automated Incident Investigation: A Pragmatic Look
Apr 19, 2026