Kubernetes CPU Alert Not Firing - Complete Troubleshooting Guide | DevOps Duoo
Learn why your Kubernetes CPU alerts might not be firing and how to fix common Prometheus alerting issues in production environments.
The Problem
You've set up CPU alerts in your Kubernetes cluster, but they're not firing even when pods are clearly under heavy load. This is one of the most frustrating monitoring issues because everything looks correct, but the alerts never trigger.
Common Causes and Fixes
1. Metrics Are Not Being Collected
First, verify that CPU metrics are actually being scraped:
container_cpu_usage_seconds_total{namespace="your-namespace"}
up{job="kubelet"}If you see no data, the issue is at the collection layer:
- ServiceMonitor not matching: Check labels match your Prometheus operator config
- Kubelet metrics disabled: Ensure
--read-only-portis enabled or use authenticated scraping - Network policies blocking: Prometheus needs access to kubelet metrics endpoint
2. Alert Expression Is Wrong
The most common mistake is using instantaneous values instead of rates:
expr: container_cpu_usage_seconds_total > 0.8
expr: |
sum(rate(container_cpu_usage_seconds_total{container!=""}[5m])) by (pod, namespace)
/
sum(kube_pod_container_resource_limits{resource="cpu"}) by (pod, namespace)
> 0.83. Alert Is Pending But Not Firing
Alerts have a for duration that must be exceeded:
alert: HighCPUUsage
expr: ...
for: 5m # Alert must be true for 5 minutes continuouslyCheck the Prometheus Alerts page - if your alert shows "Pending" but never "Firing", the condition is flapping (going above and below threshold).
Fix: Either extend the evaluation window or adjust the threshold.
4. Alertmanager Configuration Issues
Even if Prometheus fires alerts, Alertmanager might not route them:
curl -s http://alertmanager:9093/api/v2/alerts | jq .
amtool config show --alertmanager.url=http://alertmanager:9093Common issues:
- Inhibit rules: Another alert might be suppressing yours
- Route mismatch: Labels don't match any route
- Silences active: Check for active silences
Complete Working Example
Here's a production-tested CPU alert that works:
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: cpu-alerts
namespace: monitoring
spec:
groups:
- name: cpu.rules
interval: 30s
rules:
- alert: HighPodCPUUsage
expr: |
(
sum(rate(container_cpu_usage_seconds_total{container!="", container!="POD"}[5m])) by (pod, namespace)
/
sum(kube_pod_container_resource_limits{resource="cpu", unit="core"}) by (pod, namespace)
) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "Pod {{ $labels.pod }} CPU usage is above 80%"
description: "Pod {{ $labels.pod }} in namespace {{ $labels.namespace }} has been using more than 80% of its CPU limit for 5 minutes."
runbook_url: "https://devopsduoo.com/runbooks/high-cpu"Debugging Checklist
Run through this checklist when alerts aren't firing:
/api/v1/rules endpointfor duration to passKey Takeaways
- Always use
rate()with counter metrics like CPU usage - Test alerts with artificially low thresholds first
- Check both Prometheus AND Alertmanager for issues
- Use the Prometheus UI to validate expressions before deploying
- Monitor
prometheus_notifications_failed_totalfor delivery issues
Next Steps
If you're still having issues, consider:
- Setting up recording rules for complex expressions
- Implementing alert testing with
promtool - Adding dead man's switch alerts to catch silent failures
Have questions? Reach out to us at contact@devopsduoo.com or connect on LinkedIn.