Skip to main content
RunBook Academy

CephCXII · OSD Host LossOSD Host Loss

How much more you can afford to lose

Advanced⏱ ~18 minceph

What you'll learn

  • Derive remaining tolerance from the pool and rule
  • Count PGs sitting at exactly min_size
  • Interpret ok-to-stop correctly
  • Communicate tolerance without overstating it

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

Not yet marked complete on this device.

Why this matters in production

Every action taken during a host outage — a reboot, a firmware update, a scrub — is a bet on how much redundancy is left, and the number is knowable rather than guessable.

Where tolerance comes from

ceph osd pool ls detail | grep -E 'replicated|erasure'
ceph osd crush rule dump replicated_hdd | python3 -c '
import sys,json
d = json.load(sys.stdin)
for s in d["steps"]:
    print(s)'
{"op": "take", "item": -1, "item_name": "default"}
{"op": "chooseleaf_firstn", "num": 0, "type": "host"}
{"op": "emit"}
Rule elementWhat it fixes
type host in chooseleafone replica per host
pool sizehow many domains a PG occupies
pool min_sizehow few it can occupy and still serve
size - min_sizeguaranteed domain failures before I/O stops

Counting what is left

ceph pg dump pgs --format json 2>/dev/null | python3 -c '
import sys,json,collections
d = json.load(sys.stdin)
rows = d.get("pg_stats", d) if isinstance(d, dict) else d
c = collections.Counter(len(p.get("acting", [])) for p in rows)
for n in sorted(c):
    print("acting set of %d: %6d PGs" % (n, c[n]))'
acting set of 2:    376 PGs      <- one more loss takes these below min_size
acting set of 3:   3721 PGs
ceph pg ls undersized | head
ceph pg dump_stuck degraded | head

The exposed PGs are not spread evenly. Find which hosts hold their surviving replicas, because those are the machines that must not be touched until recovery completes.

ceph pg dump pgs --format json 2>/dev/null | python3 -c '
import sys,json,collections,subprocess
d = json.load(sys.stdin)
rows = d.get("pg_stats", d) if isinstance(d, dict) else d
tree = json.loads(subprocess.check_output(["ceph","osd","tree","--format","json"]))
host = {}
for n in tree["nodes"]:
    if n["type"] == "host":
        for c in n.get("children", []):
            host[c] = n["name"]
c = collections.Counter()
for pg in rows:
    a = pg.get("acting", [])
    if len(a) == 2:
        for o in a: c[host.get(o, "?")] += 1
for h, n in c.most_common(10):
    print("%-24s %5d exposed PGs" % (h, n))'

Asking before acting

ceph osd ok-to-stop 44
ceph osd ok-to-stop 44 45 46 --max 3
ceph orch host ok-to-stop ceph-osd-09
ceph osd safe-to-destroy 18 19 20
CommandQuestion it answers
ceph osd ok-to-stopwould stopping these make PGs unavailable
ceph orch host ok-to-stopthe same question for every OSD on a host
ceph osd safe-to-destroydo these OSDs still hold copies nothing else has

Saying it accurately

Wrong: "we can lose two more hosts, we have 40."
Right: "376 PGs are at two copies; any host holding one of those is a
service outage for that PG. Everything else tolerates one more host."

Quiz

Knowledge check · 4 questions

  1. Q1. What does `ceph osd ok-to-stop` actually evaluate?

  2. Q2. A forty-host cluster with size 3 and min_size 2 tolerates more host failures than a four-host cluster with the same settings.

  3. Q3. Assess whether a second maintenance action is safe.

    One host is down and recovery is in progress. A firmware update is scheduled for another host tonight. 376 PGs currently show an acting set of two.

  4. Q4. Where does guaranteed failure domain tolerance come from?

Passing score: 75%. Answers are checked in this browser.

Production discipline

Express remaining tolerance as a count of PGs at their minimum acting set, not as a count of spare hosts — the two diverge badly in large clusters. Confirm min_size on the affected pools before trusting ok-to-stop, since it is an availability check and not a durability one.

Cross-course references

  • Kubernetes: PodDisruptionBudget answers availability and says nothing about data redundancy
  • Linux: quorum arithmetic does not improve because you added more machines