CephCXIV · Complete Storage Node LossComplete Storage Node Loss
Whether the rebuild can finish at all
What you'll learn
- Determine whether the surviving topology can satisfy the placement rule
- Distinguish a slow rebuild from one that can never complete
- Assess what a second concurrent failure would do right now
- Express the exposure window as a decision input
Prerequisites
None — start here.
Verified against Ceph Tentacle 20.2.x · Ceph Squid 19.2.x (supported previous) · cephadm matches the verified Ceph release · podman 4.x · csi-rbd and csi-cephfs current · RBD / CephFS / RGW current (matches Ceph release) · Linux kernel 5.15+ (5.10 minimum) · Ubuntu 24.04 LTS (Ceph host baseline) · Debian 12 (Bookworm) (Ceph host baseline) · Rocky Linux / RHEL / AlmaLinux 9.x (Ceph host baseline) · Proxmox VE 9.x (cross-course integration) · Kubernetes 1.31+ (cross-course integration) · 2026-08-18
Why this matters in production
After a permanent node loss the cluster either rebuilds to full redundancy or it does not, and the answer is arithmetic you can do in two minutes. Waiting to find out costs days of exposure.
The placement question comes first
ceph osd pool ls detail | grep -E 'replicated|erasure'
ceph osd crush rule dump | python3 -c '
import sys,json
for r in json.load(sys.stdin):
types = [s.get("type") for s in r["steps"] if s.get("op","").startswith("chooseleaf")]
print("%-20s failure domain: %s" % (r["rule_name"], types or "?"))'
# how many hosts still carry up OSDs
ceph osd tree --format json | python3 -c '
import sys,json
d = json.load(sys.stdin)
byid = {n["id"]: n for n in d["nodes"]}
live = {n["name"] for n in d["nodes"] if n.get("type") == "host"
and any(byid.get(c, {}).get("status") == "up" for c in n.get("children", []))}
print(len(live), "hosts with up OSDs:", " ".join(sorted(live)))'
| Surviving hosts | Rule | Result after losing one host |
|---|---|---|
4, size=3, domain host | replicated | rebuilds to clean |
3, size=3, domain host | replicated | permanently undersized, still serving |
2, size=3, domain host | replicated | undersized and one failure from inactive |
| 5, EC 4+2, domain host | erasure | permanently undersized at 5 shards |
| 6, EC 4+2, domain host | erasure | rebuilds to clean |
any, size=3, domain osd | replicated | rebuilds, but copies may share a host |
Reading the answer out of the cluster
ceph pg ls undersized | head -5
ceph health detail | grep -A3 PG_DEGRADED
active+undersized+degraded is serving reads and writes with fewer copies
active+undersized+degraded+remapped+backfilling is repairing
active+undersized+degraded with no backfill and no progress is stuck
# stuck means the rule cannot place the missing copy
ceph pg ls undersized --format json | python3 -c '
import sys,json
d = json.load(sys.stdin)
pgs = d.get("pg_stats", d) if isinstance(d, dict) else d
print(len([p for p in pgs if "backfilling" not in p.get("state","")]), "not backfilling")'
What a second failure would do now
ceph osd pool get rbd-vms min_size
ceph pg ls degraded | wc -l
| Current state | Next OSD failure in the same PG |
|---|---|
size=3, two copies, min_size=2 | drops to one copy — IO blocks on those PGs |
size=3, two copies, min_size=1 | serves from one copy, no redundancy at all |
EC 4+2, five shards, min_size=5 | drops to four — those PGs go inactive |
| rebuilt to three copies | tolerated normally |
min_size=1 is not a safety setting. It converts an availability outage
into a silent single-copy window, and the next failure is data loss.
The exposure window is a decision input
ceph osd ok-to-stop osd.22
ceph -s | grep -E 'degraded|misplaced'
| Activity | During the window |
|---|---|
| Unrelated host reboots | postpone |
| Firmware or kernel updates | postpone |
| Adding unrelated capacity | postpone; it competes for the same backfill |
| Replacement hardware procurement | accelerate |
Quiz
Knowledge check · 4 questions
Q1. A three-host cluster with `size=3` and a host failure domain loses one host. PGs sit `active+undersized+degraded` with no backfill. What is happening?
Q2. Setting `min_size=1` on a degraded pool converts a potential availability outage into a window where the next failure is data loss.
Q3. Assess redundancy after a permanent node loss.
A five-host cluster runs replicated pools at `size=3` and one EC 4+2 pool, both with a host failure domain. One host is permanently lost.
Q4. How do you tell a slow rebuild from one that can never complete?
Passing score: 75%. Answers are checked in this browser.
Production discipline
Count surviving failure domains against every pool’s rule before tuning
anything — a rebuild that cannot place its last copy will not respond to
recovery settings, and the two states look identical in ceph -s. Treat
the exposure window as a freeze on unrelated maintenance, and reach for
min_size=1 only as a deliberate, time-boxed availability trade.
Cross-course references
- Kubernetes: a PodDisruptionBudget that cannot be satisfied blocks rather than degrading quietly
- Linux: an array below its minimum member count refuses to assemble rather than guessing