Repository navigation
Alert on what actually breaks, and fire the alerts to prove it - #18
Merged
Merged
Conversation
Prometheus scraping every node individually, rules for the ways a consensus cluster fails, an Alertmanager routing them, and a Grafana dashboard provisioned from a file in this repository rather than clicked together in a UI. The rules are written against what the cluster believes, not against pod health, because those are different questions. Five pods can be Running and perfectly healthy while a partition leaves none of them able to reach a majority — every pod fine, the cluster down. Kubernetes cannot see that; "no node can name a leader" can. It waits fifteen seconds, roughly ten election timeouts, because every election has a leaderless instant and an alert that fires on routine failover is one people learn to ignore. Quorum is computed from the voter count the cluster reports rather than from a hardcoded five, so it stays correct across membership changes. One node down is a warning rather than a page, since a five-node cluster survives it by construction. A failing scrape alerts on the monitoring rather than on the cluster, because treating a broken exporter as a broken cluster is how a healthy node gets restarted during an incident. An alert rule that has never fired is an assertion: the expression may not match the metric names, the threshold may be unreachable, the routing may drop it, and none of that surfaces until an incident. So monitoring.sh demo removes quorum on purpose. Both critical alerts fired thirty seconds after quorum was lost and cleared ten seconds after it returned, with no intervention. That demo also makes a point worth keeping: scaling the StatefulSet down does not remove anything from the Raft configuration, which lives in the replicated log and moves only through joint consensus. The cluster still believed it had five voters, so two survivors correctly refused to serve. Also stops the leader publishing its replication lag to itself. The leader tracks its own progress because its own log counts toward the majority that commits an entry, but a node's lag behind itself is zero by definition, and publishing it puts a line on the dashboard that reads as a perfectly healthy follower while not being a follower at all — the exact confusion the metric's own documentation says it avoids.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Prometheus scraping every node individually, alert rules for the ways a consensus cluster actually fails, an Alertmanager routing them, and a Grafana dashboard provisioned from a file in this repository.
The alerts were fired on purpose
An alert rule that has never fired is an assertion, not a safeguard — the expression may not match the metric names, the threshold may be unreachable, the routing may silently drop it, and none of that surfaces until an incident. So
make monitoring-demoremoves quorum deliberately and checks the alert arrives at Alertmanager. Against the live five-node cluster:Both critical alerts fired within 30s of quorum loss and cleared within 10s of recovery, without intervention. All eight rules load; the dashboard is provisioned and its panel queries return data.
There is a detail in that demo worth keeping. Scaling the StatefulSet from five to two does not remove anything from the Raft configuration — membership lives in the replicated log and moves only through joint consensus. The cluster still believed it had five voters, so the two survivors could not assemble a majority and correctly refused to serve. The alert measures a majority of the configuration, not a count of pods.
Why the rules are written against consensus state, not pod health
RaftKVNoLeaderis expressed as "no node can name a leader" rather than as a count of running pods, because those are different questions: five pods can beRunningand healthy while a partition leaves none of them able to reach a majority. Every pod fine, the cluster down — Kubernetes cannot observe that difference.It waits 15s, not 0s. Every election has a leaderless instant, so a zero threshold pages on routine failover and trains people to ignore it; 15s is about ten election timeouts, which separates "failing to elect" from "in the middle of electing".
RaftKVBelowQuorumreads the voter count from the cluster rather than hardcoding five, so it survives membership changes.RaftKVNodeDownis a warning rather than a page, because one node down on five is survivable by construction — it matters only when a second follows, which the quorum alert covers.RaftKVScrapeFailingalerts on the monitoring, not the cluster: if the exporter cannot read a node's state the node may be perfectly healthy, and treating a broken exporter as a broken cluster is how a healthy node gets restarted mid-incident.RaftKVStuckInJointConfigurationcatches a membership change that never completed, a state strictly more fragile than either configuration alone and one nothing else would notice.Alertmanager inhibits
RaftKVNodeDownunderRaftKVBelowQuorum, and groups by alert name rather than by pod — during a rolling upgrade every pod goes down in turn, and per-pod grouping would send five notifications for one expected event.Scraping and the dashboard
Pod discovery, not the Service. The client Service load-balances, so scraping it would return an arbitrary node per scrape with nothing to distinguish the series. Consensus metrics are only meaningful per node. The scrape interval is 5s because failover takes 1–2s; at a conventional 60s most elections would be invisible.
The dashboard is a reviewable JSON file mounted into Grafana, not a row in Grafana's database that disappears with the pod.
One fix found by looking at the dashboard
The leader was publishing its replication lag to itself. It tracks its own progress legitimately — its own log counts toward the majority that commits an entry — but a node's lag behind itself is zero by definition, and publishing it puts a line on the dashboard that reads as a perfectly healthy follower while not being a follower at all. That is the exact confusion the metric's own comment claims to avoid. Verified after the fix: the leader emits four peer series on a five-node cluster, not five.
Commands
Verification
make checkpasses: vet, determinism guards,-racesuite, 22/22 mutations caught. The stack was installed against the live kind cluster and the quorum demo run end to end.