Skip to main content
RunBook Academy

CephCXV · Cluster-Wide Capacity IncidentCluster-Wide Capacity Incident

Finding where the cluster is actually full

Intermediate⏱ ~18 minceph

What you'll learn

  • Read the fullness health checks and distinguish ratio-driven from quota-driven ones
  • Identify the specific OSDs carrying the problem
  • Interpret MAX AVAIL against raw free space
  • Narrow the incident to a device class or CRUSH subtree

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

Ceph blocks writes on the fullest OSD, not on the average one. A cluster reporting 68% used can be refusing writes, and every minute spent reasoning about the average is a minute not spent on the device.

The health checks name two different problems

ceph health detail
HEALTH_ERR 1 full osd(s); 3 nearfull osd(s); 2 pool(s) full
[ERR] OSD_FULL: 1 full osd(s)
    osd.37 is full
[WRN] OSD_NEARFULL: 3 nearfull osd(s)
    osd.11 is near full
[ERR] POOL_FULL: 2 pool(s) full
    pool 'cephfs.data' is full (reached quota's max_bytes)
CheckDriven byFixed by
OSD_NEARFULLthe OSD’s own utilisationspace or distribution
OSD_BACKFILLFULLthe OSD’s own utilisationspace or distribution
OSD_FULLthe OSD’s own utilisationspace or distribution
POOL_NEAR_FULLa pool quota you setraising or removing the quota
POOL_FULLa pool quota you setraising or removing the quota

A quota-driven POOL_FULL on an otherwise healthy cluster is a configuration event, not a capacity incident. Read which check fired before deciding what kind of night this is.

Fullness is a property of an OSD

ceph osd df --format json | python3 -c '
import sys,json
n = sorted(json.load(sys.stdin)["nodes"], key=lambda o: -o.get("utilization",0))
for o in n[:8]:
    print("osd.%-4d %-6s %6.2f%%  var %.2f  pgs %4d  avail %6.1f GiB"
          % (o["id"], o.get("device_class",""), o.get("utilization",0),
             o.get("var",0), o.get("pgs",0), o.get("kb_avail",0)/1024**2))'
ceph osd utilization
ceph osd df tree | tail -20
ColumnWhat it tells you
%USEthe number the thresholds are compared against
VARthis OSD’s utilisation divided by the cluster average
PGSwhether the OSD is holding more PGs than its peers
AVAILhow much room is left before the next threshold
STDDEV in the summarywhether this is a distribution problem

MAX AVAIL is not free space

ceph df detail
--- POOLS ---
POOL          ID  PGS   STORED  OBJECTS  USED  %USED  MAX AVAIL
rbd-vms        3  2048   31 TiB   8.12M   93 TiB  81.4     7.1 TiB
cephfs.data    6  1024   14 TiB   4.40M   42 TiB  74.2     7.1 TiB
MAX AVAIL is what the pool can still absorb given its replication and
the fullest OSD in its CRUSH tree. Raw free space across the cluster is
almost always larger, and almost always irrelevant.

Narrowing to a class or subtree

ceph osd crush class ls
ceph osd df tree --format json | python3 -c '
import sys,json
for n in json.load(sys.stdin)["nodes"]:
    if n.get("type") in ("host","rack"):
        print("%-8s %-14s %6.2f%%" % (n["type"], n["name"], n.get("utilization",0)))'
ceph osd pool ls detail | grep -E 'crush_rule|pool '
ceph osd crush rule dump | grep -E 'rule_name|item_name|class'

Quiz

Knowledge check · 4 questions

  1. Q1. `ceph df` reports 68% raw used and clients are getting blocked writes. Where do you look first?

  2. Q2. A `POOL_FULL` health check means the cluster has run out of space.

  3. Q3. Triage a fullness alert.

    Alerting fires at 03:10. `ceph -s` shows HEALTH_ERR with one full OSD and three nearfull. `ceph df` reports 71% raw used and 6 TiB MAX AVAIL on the pool that matters.

  4. Q4. Why is a pool's MAX AVAIL usually far smaller than the cluster's raw free space?

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

Production discipline

Begin every capacity incident by sorting OSDs by utilisation, not by reading the cluster percentage — the thresholds are per-OSD and the average has never blocked anything. Record STDDEV and VAR in the first five minutes: whether this is a volume problem or a distribution problem determines which of the remedies can help at all.

Cross-course references

  • Kubernetes: a node under DiskPressure evicts pods while cluster capacity looks fine
  • Linux: a full filesystem on one mount does not show in aggregate storage reporting