The Comprehensive Ceph Guide
فارسیGet started
On this page
Chapter 1

Ceph: A New Era — Architecture, Planning and Your First Cluster

49 min readEdit this page
TL;DR this chapter in a few lines
  • Ceph is software-defined storage: block (RBD), object (RGW) and file (CephFS) interfaces all sit on one layer, RADOS, instead of RAID arrays.
  • MONs hold the cluster maps, the MGR holds statistics and modules, and OSDs hold the data; CRUSH computes where an object lives, so there is no central lookup table.
  • Planning decides success: workload, failure domain, network and MTU, fill ratio, and SSDs with power-loss protection for DB/WAL and MONs.
  • cephadm is the official deployment tool: bootstrap one host, add hosts, and declare the desired services with ceph orch apply.

1-1 Before you start#

1-1-1 What questions does this chapter answer?#

On the surface the first chapter is an "introduction", but in practice it builds the mental map on which the rest of the book rests. Every concept we meet in later chapters, from RBD and RGW to CRUSH, BlueStore and erasure coding, ultimately goes back to a few simple ideas introduced here: software-defined storage, the removal of a "central table of where data lives", and the intelligent distribution of responsibility across thousands of independent daemons. In this guide we try to answer these questions:

  • Why does traditional storage built on RAID and dedicated arrays hit a dead end at today's scale, and exactly which pains does Ceph cure?
  • Which layers and daemons make up the Ceph architecture, and what is each one responsible for?
  • What path does an object take from the moment a client writes it until it is stored on three disks in three racks?
  • Which questions must be answered before you buy hardware or build your first cluster?
  • How do you build a real test cluster with cephadm, grow it and work with it?

1-1-2 Prerequisites and how to read#

This chapter assumes you are familiar with Linux, basic disk concepts (partitions, LVM, file systems) and networking (IP, subnets, MTU). Experience with containers (Podman or Docker) helps, because modern Ceph runs all of its daemons in containers. If you do not have a test cluster, the "Building the lab" section suggests a complete path with four virtual machines.

Many older Ceph tutorials were written against the Jewel and Luminous releases and use tools such as ceph-deploy and ceph-ansible for installation. Both tools have since been retired. In this book all examples are written with cephadm and current Ceph releases. Wherever behaviour differs between releases, we say so explicitly.

Throughout the text you will see several kinds of box:

💡 Tip

A "Tip" box is a practical recommendation or a working shortcut.

⚠ Warning

A "Warning" box marks a place where a mistake leads to data loss or a service outage in production.

▶ Try it

A "Try it" box suggests a small experiment on the test cluster.

◆ Deeper

A "Deeper" box explains the mechanism behind the scenes; if you are in a hurry you can skip it.

✚ Troubleshooting

A "Troubleshooting" box lists the symptoms of common problems in that section and how to investigate them.

✎ Note

A "Note" box is a side remark or a historical comment.

1-1-3 Chapter roadmap#

We move through the chapter in seven stops. First we see what software-defined storage is and where Ceph came from. Then we review the structural weaknesses of RAID. Next we open up the Ceph architecture layer by layer. After that we turn to deployment planning and hardware. Then we build a virtual lab, install Ceph with cephadm and grow the cluster. Finally we do hands-on work with pools, objects and block devices. The "Supplementary and up to date" section summarises the important changes from 2019 to today.

1-2 Ceph: the beginning of a new era#

1-2-1 From storage arrays to software-defined storage#

Until only a decade ago, "enterprise storage" was almost synonymous with an expensive box from one particular vendor: two controllers, a few disk shelves, a closed operating system, and a support contract that grew more expensive every year. These boxes did their job well, but they had three fundamental limitations:

  • Vertical scaling: capacity and performance grew by adding shelves to the same pair of controllers. Sooner or later the controllers became the bottleneck, and there was no way out except buying a bigger box.
  • Vendor lock-in: disks, controllers, software and even cables had to come from the same vendor. Migrating from one generation to the next usually meant a project of several months.
  • Data islands: one product for block, another for files, and a third for backup. Each needed its own management tools and its own team of specialists.

Software-defined storage (SDS) turns this equation around: the intelligence is separated from the hardware and lives in software that runs on ordinary (commodity) servers. Hardware becomes a replaceable commodity, and the software takes over replication, distribution, repair and serving the interfaces. As a result, growing only requires adding servers, and different generations of hardware can work side by side in one cluster.

PropertyTraditional arraySoftware-defined storage (Ceph)
ScalabilityVertical, limited by the controllerHorizontal, by adding nodes
Point of failureThe controller pairNone; every component is replicated
HardwareVendor-specificOrdinary x86 or ARM servers
InterfacesUsually one kind per productBlock, object and file in one cluster
UpgradesMove the data to a new boxGradual replacement, node by node
Licence costHigh and capacity-basedOpen source; commercial support optional

1-2-2 Cloud storage and new requirements#

The rise of public clouds changed expectations. A user who creates a disk or a bucket in AWS with a single API call expects the same from their organisation's private cloud. Cloud storage has several properties that traditional arrays were not designed for:

  • Self-service and API-driven: creating, resizing and deleting resources must happen through an API, without a ticket. Projects such as OpenStack Cinder, Kubernetes CSI and the S3-compatible API all require exactly this.
  • Multi-tenancy: thousands of customers with quotas, access policies and full isolation on one shared infrastructure.
  • Petabyte scale and continuous growth: unstructured data (photos, video, logs, backups, machine-learning datasets) grows at a pace that makes multi-year planning impossible.
  • Failure as the normal state: in a cluster with thousands of disks, several disks fail every day. The system must heal itself without human intervention.

Ceph was designed for exactly this world. Today it is the storage backbone of many OpenStack-based private and public clouds, of many Kubernetes platforms (through Rook), and of S3-compatible object storage services.

1-2-3 A unified next-generation architecture#

Ceph's most important distinction is that it is "unified": a single cluster serves three kinds of storage interface at the same time:

  • Block storage (RBD): virtual disks for virtual machines, containers and physical servers, with snapshots, clones and cross-site replication.
  • Object storage (RGW): an API compatible with Amazon S3 and OpenStack Swift, with multi-tenancy, versioning, lifecycle, object lock and multisite replication.
  • File storage (CephFS): a POSIX-compatible distributed file system, with snapshots, quotas, and export over NFS and SMB.
Figure 1-1: Ceph layers: the three block, object and file interfaces are all built on a common RADOS layer
Figure 1-1: Ceph layers: the three block, object and file interfaces are all built on a common RADOS layer

All three interfaces are built on a common layer called RADOS (Reliable Autonomic Distributed Object Store). This means replication, repair, data distribution and failure handling are implemented only once, in one place, and every interface benefits from them. Operationally, too, one cluster, one set of monitoring tools and one team are enough.

◆ Deeper

The word "Autonomic" in the name RADOS is key. In Ceph no central server decides which data must be copied where. Each OSD monitors the state of its neighbours, reports failures, and when the cluster map changes it pulls the data it needs from its peers. The MONs only hold the "map" and reach consensus on it; they are not in the data path. This design is what lets Ceph scale to thousands of OSDs.

1-2-4 Where did Ceph come from?#

Ceph grew out of Sage Weil's doctoral research at the University of California, Santa Cruz (UCSC). Its foundational papers were published in 2006: the Ceph paper at the OSDI conference and the paper on the CRUSH algorithm at the SC conference. The RADOS paper followed in 2007. The name Ceph comes from "cephalopod" (the octopus family), which is why releases are also named after animals of that family: from Argonaut and Bobtail to Reef, Squid, Tentacle and Umbrella.

YearEvent
2006–2007The Ceph, CRUSH and RADOS papers are published
2010The CephFS client enters the Linux kernel (version 2.6.34)
2012Inktank is founded for commercial support; the first stable release, Argonaut
2014Red Hat acquires Inktank
2017Luminous: BlueStore becomes stable and the default, and ceph-mgr (introduced in Kraken) becomes mandatory
2018The Ceph Foundation is founded under the Linux Foundation
2020Octopus: cephadm and the container-based orchestrator are introduced
2023Red Hat's storage team (including Ceph) moves to IBM
2024–2026Squid, Tentacle and Umbrella; FastEC, the NVMe-oF gateway, the SMB module and the Crimson preview
✎ Note

Until a few years ago Jewel and Luminous were common, FileStore was the default storage engine, and installation was done with ceph-deploy. If you have read older sources, much of the difference between them and this book lies in exactly these points.

1-3 The end of the RAID era#

1-3-1 What problem did RAID solve?#

RAID was designed in the 1980s to solve a specific problem: building a disk that is bigger, faster and more reliable out of several small, cheap disks. RAID 1 with mirroring, RAID 5 with one parity and RAID 6 with two parities made it possible to survive the failure of one or two disks. At a time when disks held a few tens of gigabytes and each server had a few disks, this was an excellent solution. But over three decades disk capacity grew thousands of times while transfer speed grew only tens of times. This simple mismatch is what makes RAID inefficient at today's scale.

1-3-2 RAID rebuilds are painful#

When a disk fails in a RAID 5 or 6 array, the controller must read its contents from all remaining disks, recompute them and write them to the spare disk. The speed of this process is limited by the write speed of one disk (the spare). A 20 TB disk with a sustained rate of about 200 MB/s needs about 28 hours to fill in the best case. In practice, because the array is serving users at the same time, a rebuild usually takes several days. During all that time:

  • The array runs in a degraded state, and its performance has dropped sharply.
  • Fault tolerance is reduced. In RAID 5, the failure of a second disk means losing the whole array.
  • All the remaining disks are under heavy read load. This is exactly the moment when disks of the same age and batch are more likely to fail.
Figure 1-2: Many-to-one rebuild in RAID versus many-to-many recovery in Ceph: in Ceph every healthy OSD takes part in the repair
Figure 1-2: Many-to-one rebuild in RAID versus many-to-many recovery in Ceph: in Ceph every healthy OSD takes part in the repair

In Ceph the data of a failed OSD is spread, in the form of hundreds of placement groups, over tens or hundreds of other OSDs. When an OSD fails, each PG is rebuilt independently on a new OSD. That means tens of disks read in parallel and tens of other disks write in parallel. This declustered recovery cuts repair time from days to minutes or a few hours, and the larger the cluster, the faster it gets.

1-3-3 Spare disks raise the cost#

To react quickly to failures, RAID needs a hot spare: a disk that has been bought, draws power, takes up space and holds no data. In a data centre with hundreds of arrays, that means hundreds of idle disks. Ceph has no concept of a spare disk. The "free capacity" of the whole cluster plays the role of the spare. You only need to plan the cluster so that after the loss of one failure domain (for example one host) it still stays below the fullness threshold. That capacity is also used for normal service in the meantime and is not wasted.

1-3-4 RAID is expensive and hardware-bound#

Hardware RAID needs a dedicated controller, a cache backed by a battery or capacitor, and often "certified" disks at a higher price. When the controller fails, often only a controller of the same model (and sometimes the same firmware version) can recognise the array again. Ceph, by contrast, sees the disks directly, without a RAID layer (JBOD or HBA mode). The intelligence is in the software, and any ordinary server with a simple HBA card is enough.

⚠ Warning

Never build Ceph OSDs on RAID 5 or RAID 6 volumes. Doing so stacks two layers of redundancy, wastes capacity, increases write latency and, most importantly, hides single-disk failure information from Ceph. If your controller has no HBA or passthrough mode, the next best option is a single-disk RAID 0 for each physical disk; in that case configure the controller's write cache carefully (and only with a healthy BBU).

1-3-5 Growing a RAID group is hard#

Adding a disk to an existing RAID group is either impossible or a long, risky operation that rewrites the whole array. In practice, organisations create a new RAID group and spread the data between groups by hand. In Ceph, adding a disk means adding an OSD. CRUSH automatically gives the new OSD a proportional share of the PGs, moving only the minimum amount of data. You can add one disk, one server or ten racks in the same way.

1-3-6 RAID's reliability model is no longer convincing#

RAID's most important weakness is statistical. Hard disks have an unrecoverable read error rate (URE) specification, usually stated as one error per 101410^{14} bits for consumer-class disks and one error per 101510^{15} bits for enterprise disks. 101410^{14} bits is about 12.5 TB. Rebuilding a RAID 5 array whose healthy disks total a few tens of terabytes means reading several times that amount. The probability of hitting at least one URE during the rebuild is no longer negligible, and in RAID 5 such an error can lead to a lost block or to a complete rebuild failure.

◆ Deeper

A simple calculation of this probability is instructive. If we take the URE rate as p=10−14p = 10^{-14} per bit and the rebuild must read NN bits, the probability of finishing without an error is approximately (1−p)N≈e−pN(1-p)^N \approx e^{-pN}. For reading 40 TB (about 3.2×10143.2 \times 10^{14} bits), pNpN is about 3.2 and the probability of finishing without an error is only about 4 percent. This figure is pessimistic, because the real rate of disks is usually better than the number on the datasheet, but it shows the direction of the trend well.

Ceph contains this problem in several ways. First, each PG is independent, so a read error affects only one object, not the whole disk. Second, with a checksum on all data (crc32c by default in BlueStore), Ceph detects silent corruption and reads the healthy copy from another peer. Third, scrub and deep scrub periodically compare all copies with each other, so hidden corruption is discovered before we need the data. Fourth, by choosing three-way replication or erasure coding with a larger m, you can pick the protection level for each pool separately.

AspectRAID 6Ceph with 3-way replicationCeph with EC 8+3
Simultaneous failures tolerated2 disks per group2 failure domains (e.g. 2 hosts)3 failure domains
Capacity overhead2 disks out of n200%about 38%
Rebuild bottleneckOne spare diskThe whole clusterThe whole cluster
Silent corruption detectionUsually limitedchecksum and deep scrubchecksum and deep scrub
Failure domainOne server or shelfConfigurable: disk, host, rack, roomConfigurable

1-4 The Ceph architecture at a glance#

1-4-1 RADOS: the heart of the system#

Everything in Ceph is ultimately an object: an RBD disk is split into thousands of 4 MB objects, a CephFS file into data and metadata objects, and an S3 object into a head object plus its parts. RADOS is the layer that stores, replicates, distributes and repairs these objects. Every object in RADOS has a name, binary data, a number of xattrs (small key-value attributes) and an omap (a larger, sorted key-value space). The omap is where, for example, RGW keeps the list of objects in each bucket.

1-4-2 The main daemons#

Figure 1-3: Daemon roles: the client gets the maps from the MONs and then works directly with the OSDs
Figure 1-3: Daemon roles: the client gets the maps from the MONs and then works directly with the OSDs
DaemonRoleTypical count in productionOperational note
MON (ceph-mon)Holds the cluster maps and reaches consensus with Paxos; cephx authentication3 or 5 (odd)On a low-latency SSD; a majority must stay alive
MGR (ceph-mgr)Statistics, modules (dashboard, prometheus, orchestrator, balancer, pg_autoscaler)2 (one active, one standby)Without an active MGR, statistics and many commands do not work
OSD (ceph-osd)Data storage, replication, recovery, scrubOne per disk (or several for a large NVMe)Default memory target of 4 GB per OSD
MDS (ceph-mds)CephFS file system metadataAt least one active and one standby per file systemNeeded only for CephFS
RGW (radosgw)HTTP gateway for S3 and SwiftSeveral instances behind a load balancerStateless; simple horizontal scaling

Monitor (MON)#

The MONs are the cluster's "official memory". They hold a set of maps: the MON map, OSD map, PG map (in recent releases much of the PG statistics lives in the MGR), CRUSH map, MDS map (FSMap) and others. Every change to these maps is agreed among the MONs with the Paxos consensus algorithm and gets a new epoch. For the cluster to make decisions, a majority of the MONs (a quorum) must be available, which is why the number of MONs is chosen to be odd. Three MONs tolerate the failure of one, and five MONs tolerate the failure of two.

Manager (MGR)#

Since Luminous the MGR is a mandatory part of the cluster. It collects statistics about PGs, space usage and performance, and runs a set of Python modules. The web dashboard, the Prometheus exporter, the cephadm orchestrator, the balancer and the PG autoscaler are all MGR modules. At any moment only one MGR is active, and the others stay in standby.

Object Storage Daemon (OSD)#

Each OSD is usually responsible for one storage device. OSDs store data, take part in replication and recovery, exchange heartbeats with their peers and report peer failures to the MON. Since Luminous the default storage engine is BlueStore, which works directly on the raw device (chapter 12). OSDs are intelligent: they work out for themselves which PGs belong to them, and they drive peering and recovery themselves.

MDS and RGW#

The MDS is needed only for CephFS and manages the file system metadata (the directory tree, permissions, locks), while the file data itself moves directly between the client and the OSDs. RGW is an HTTP server that translates S3 and Swift requests into RADOS operations. Both are examined in detail in their own chapters (4, 5 and 6).

1-4-3 CRUSH: computation instead of lookup#

Traditional distributed storage systems rely on a central lookup table (a metadata server or name node) to find where each piece of data lives. At large scale this table is both a performance bottleneck and a point of failure. Ceph removes this table. The location of each object is computed with the deterministic CRUSH algorithm (Controlled Replication Under Scalable Hashing). Any client that has the cluster map can work out which OSDs hold the object it wants without asking any server.

Figure 1-4: The placement path: the object name maps to a PG, and CRUSH takes that PG to a set of OSDs in different failure domains
Figure 1-4: The placement path: the object name maps to a PG, and CRUSH takes that PG to a set of OSDs in different failure domains

This mapping happens in two steps:

  1. 1. Object to PG: the object name is hashed, and its remainder modulo the number of PGs in the pool (computed stably, with a method called stable mod) determines the PG number. A PG id combines the pool number and the PG number, for example 3.1a.
  2. 2. PG to OSDs: given the PG id, the hierarchical cluster map (racks, hosts, disks and their weights) and the pool's rule, CRUSH returns an ordered list of OSDs. The first OSD is the primary, and writes are coordinated through it.
◆ Deeper

Why is the PG layer needed? If we ran CRUSH directly on every object, each OSD would have to coordinate the state of billions of objects with its peers one by one. The PG is an aggregation layer: billions of objects are grouped into a few thousand PGs, and peering, recovery and scrub happen at the PG level. The number of PGs is a trade-off between even distribution (more PGs) and memory and CPU overhead (fewer PGs). Since Nautilus the pg_autoscaler module tunes this number automatically.

1-4-4 Pool: the unit of policy#

A pool is a logical namespace that sets the storage policy: the kind of protection (replication or erasure coding), the number of copies (size) and the minimum number of copies needed to accept I/O (min_size), the CRUSH rule (which disks and which failure domain), the number of PGs, compression and quota. Every pool also has an application tag (rbd, rgw or cephfs) that says which interface uses it.

💡 Tip

For replicated pools, size=3 and min_size=2 are the default and the standard recommendation. Never set min_size=1 in production: the cluster may then accept writes with only one copy, and if that OSD is lost too, data the client was told was written is gone.

1-4-5 The write path of an object#

When a client writes an object to a replicated pool with size=3:

  1. 1. The client gets the latest OSD map from one of the MONs (if it does not already have a fresh one).
  2. 2. Using the hash and CRUSH, it computes the PG and the primary OSD, and sends the request directly to the primary OSD.
  3. 3. The primary OSD applies the write in its local transaction and, at the same time, sends it to the two secondary OSDs.
  4. 4. Each secondary OSD replies to the primary after it has stored the data durably.
  5. 5. When every copy in the acting set has made the write durable, the primary OSD sends an acknowledgement (ack) to the client.

This means Ceph has strong consistency: once a write is acknowledged, every read from any client sees the latest data. Reads are served by the primary OSD by default (although RBD and CephFS can also read from the nearest copy in certain conditions).

1-5 Planning a Ceph deployment#

1-5-1 From requirements to architecture#

Most of the costly mistakes in Ceph happen not while running it but when buying the hardware. Before anything else, these questions must be answered:

  • Which interfaces? Only RBD for OpenStack or Kubernetes, only S3 for archive and backup, or a combination of all three?
  • Workload pattern: small random I/O (databases, virtual machines) or large sequential I/O (video, backup, analytics data)? What is the read-to-write ratio?
  • Usable capacity today and in three years, and the monthly growth rate.
  • Performance targets: the required IOPS and throughput, and the acceptable 99th-percentile latency.
  • Failure domain: the failure of what must be tolerated without an outage? A disk, a server, a rack, or a whole hall?
  • Geographic availability: is replication to a second site needed? Synchronous or asynchronous?
Figure 1-5: The planning decision path: workload type, failure domain, network and capacity
Figure 1-5: The planning decision path: workload type, failure domain, network and capacity

1-5-2 Hardware: what does each daemon need?#

The hardware recommendations in the official Ceph documentation are a good starting point. The table below is a practical summary of them, together with common production experience:

ComponentCPUMemoryDiskNote
MON2 to 4 coresAt least 4 to 8 GB; more in large clustersSSD with about 100 GB for /var/lib/cephSensitive to fsync latency; avoid sharing a disk with an OSD
MGR2 to 4 cores4 GB or moreNegligibleUsually co-located with a MON
OSD on HDDAbout 1 core per OSD4 GB (osd_memory_target) plus headroomHDD with WAL and DB on NVMeA typical ratio is 4 to 10 HDDs per NVMe for the DB
OSD on NVMe4 to 8 cores or more per OSD4 to 8 GBEnterprise NVMe with PLPThe CPU is usually the main bottleneck
MDSA fast core (single-thread speed matters)Depends on the cache; 8 to 64 GBNegligibleTune mds_cache_memory_limit
RGW4 to 8 cores8 to 16 GBNegligibleSeveral instances behind a load balancer
⚠ Warning

Consumer SSDs without Power Loss Protection (PLP) are not suitable for Ceph. Ceph uses a flush for every durable write, and in this pattern SSDs without PLP both become very slow and may lose acknowledged data on a sudden power loss. For OSDs, DB/WAL and MONs, use only enterprise SSDs or NVMe drives with PLP.

1-5-3 Network#

Ceph is a network-centric system, and the network affects performance and stability more than any other component. There are two logical networks:

  • Public network: traffic between clients and the MONs, OSDs, MDSs and RGWs. It is mandatory.
  • Cluster network: replication, recovery and heartbeat traffic between OSDs. It is optional.

Recent Ceph documentation stresses that a separate cluster network is not always needed, and that in many designs a single network with enough bandwidth (for example two bonded 25 or 100 Gb links) is simpler and more reliable. If you do build a separate cluster network, it must be just as reliable as the public network. A partial failure of the cluster network can make OSDs report each other down while the MON sees them as alive, and the result is the unpleasant phenomenon known as flapping.

💡 Tip

Keep the MTU the same along the whole path. If you enable jumbo frames (MTU 9000), they must be enabled on every NIC, bond, VLAN and switch. A single switch with a different MTU can let small packets (heartbeats) through while large packets (replication) are lost, which is one of the most confusing problems in Ceph. Test between all nodes with ping -M do -s 8972.

1-5-4 Capacity and fill ratios#

The usable capacity of a cluster must not be computed as "the sum of the disks divided by the replication factor". Three other factors must be taken into account:

  • Fill ratios: by default the nearfull warning fires at 85%, backfill stops at 90% (backfillfull), and all writes stop at 95% (full).
  • Capacity needed for recovery: after the failure of the largest failure domain (for example one host), its data must fit on the rest and still stay below nearfull.
  • Imbalance: even with the balancer, OSDs do not fill up exactly evenly, and the fullest OSD is what counts.
▶ Try it

A back-of-the-envelope calculation: 6 hosts, each with 12 disks of 16 TB, three-way replication. The raw capacity is 1152 TB. If one host is lost, 960 TB remain. To stay below 80% after the failure, the raw data must not exceed 768 TB, which is about 256 TB of usable data. The same cluster with EC 4+2 (overhead 1.5) accepts about 512 TB of usable data, provided we have at least 6 hosts for a host failure domain (and preferably 7, so that recovery is possible after one host fails).

1-5-5 Failure domains and node count#

The minimum number of hosts depends on the protection policy. Three-way replication with a host failure domain needs at least three hosts, but four hosts are recommended so that, after one fails, Ceph can rebuild the third copy elsewhere. Erasure coding with a k+m profile needs at least k+m hosts, and k+m+1 is recommended for automatic repair. The more hosts there are, the smaller each one's share of the data and the smaller the impact of any single failure.

✎ Note

In small clusters (three or four hosts), the failure of one host means losing 25 to 33 percent of the raw capacity and a heavy recovery load on the rest. Planning the fill ratio matters twice as much in these clusters.

1-6 Building a virtual lab#

1-6-1 Lab design#

The common old approach was to use VirtualBox and Vagrant to build several virtual machines. That approach still works, but today there are lighter options too: KVM/libvirt on Linux, LXD or Incus with virtual machines, Multipass, or even a cloud server with several VMs. It does not matter which you choose; the structure we suggest is:

Figure 1-6: Lab topology: three nodes to start with, a fourth node for expansion, and a client machine
Figure 1-6: Lab topology: three nodes to start with, a fourth node for expansion, and a client machine
MachinevCPUMemoryDisksRole
ceph-node124 GB20 GB system + 3 disks of 20 GBbootstrap, _admin, MON, MGR, OSD
ceph-node224 GBSystem + 3 disksMON, MGR, OSD
ceph-node324 GBSystem + 3 disksMON, OSD
ceph-node424 GBSystem + 3 disksAdded in the "Growing the cluster" section
client-node112 GBSystem onlyRBD, S3 and CephFS client

1-6-2 Preparing the machines#

Install a supported distribution on each node (for example Rocky Linux 9, CentOS Stream 9 or Ubuntu 24.04). According to the official documentation, the prerequisites of cephadm are: Python 3 (at least 3.9 in Umbrella), systemd, Podman or Docker, time synchronisation (chrony) and LVM2.

bash
# On every node (example for Rocky/Alma 9)
sudo dnf install -y podman lvm2 chrony python3
sudo systemctl enable --now chronyd
# Names must be resolvable from every node
cat <<'H' | sudo tee -a /etc/hosts
192.168.56.11 ceph-node1
192.168.56.12 ceph-node2
192.168.56.13 ceph-node3
192.168.56.14 ceph-node4
192.168.56.20 client-node1
H
# Look at the empty disks (they must have no partitions or file systems)
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT
⚠ Warning

Ceph Umbrella is built on Rocky Linux 10 images, which need a CPU at the x86-64-v3 microarchitecture level. If your lab runs on virtual machines with an old or emulated CPU model (for example qemu64), the daemons will not start. In libvirt use host-passthrough, or choose the Tentacle release for the lab.

✚ Troubleshooting

If cephadm later does not show a disk as "available", it is usually for one of these reasons: the disk has a partition or an old file-system signature, it is smaller than 5 GB, it is mounted, or it carries LVM. Use ceph orch device ls --wide to see why it was rejected (the REJECT REASONS column), and in the lab wipe it with ceph orch device zap <host> <path> --force.

1-7 Installing and configuring Ceph with cephadm#

1-7-1 Why cephadm?#

Since Octopus, cephadm has been the official tool for deploying Ceph and managing its life cycle. Three properties set it apart from the older tools:

  • Containerised: each daemon runs in a Podman or Docker container with the official Ceph image. The Ceph version is independent of the operating system's package versions, and an upgrade means swapping the image.
  • Built-in orchestrator: cephadm runs as an MGR module and works with the hosts over SSH. You declare the "desired state" (for example "three MONs on these hosts") and the module keeps it in place, much like Kubernetes controllers.
  • No external dependencies: it needs no Ansible, Salt or other configuration-management tool. Just SSH, Python and a container engine.
Figure 1-7: The steps of bootstrapping and adding hosts with cephadm
Figure 1-7: The steps of bootstrapping and adding hosts with cephadm

1-7-2 Installing cephadm and bootstrapping#

The official documentation suggests two ways of getting cephadm: the distribution package (for example apt install cephadm on Ubuntu, or the centos-release-ceph-* repository on CentOS Stream), or downloading the executable with curl. Do not mix the two methods.

bashReef+
# On ceph-node1 as root
CEPH_RELEASE=tentacle   # or umbrella; see the releases page for the list of active releases
curl --silent --remote-name --location \
  https://download.ceph.com/rpm-${CEPH_RELEASE}/el9/noarch/cephadm
chmod +x cephadm
./cephadm add-repo --release ${CEPH_RELEASE}
./cephadm install
which cephadm            # /usr/sbin/cephadm

Now we create the first MON and MGR. The --mon-ip address must be on the public network and reachable from every node and client:

bashReef+
cephadm bootstrap \
  --mon-ip 192.168.56.11 \
  --cluster-network 10.10.10.0/24 \
  --initial-dashboard-user admin \
  --allow-fqdn-hostname

When it finishes, bootstrap has done the following: created one MON and one MGR on the local host, generated a new SSH key and placed it in root's authorized_keys, written the public key to /etc/ceph/ceph.pub, put a minimal ceph.conf and the admin keyring (ceph.client.admin.keyring) in /etc/ceph, and given the bootstrap host the _admin label. The dashboard address and a temporary password are also printed in the output.

⚠ Warning

The file /etc/ceph/ceph.client.admin.keyring is the cluster's full administrative key. Anyone who has it can read or delete all data. Keep this file only on administrative hosts (those with the _admin label), never put it in a Git repository or a public backup, and create a separate user with limited access for applications (chapter 8).

1-7-3 Accessing the Ceph command line#

cephadm does not need Ceph packages installed on the host. You have two ways to run commands:

bashReef+
# Option 1: a shell in a container with all the tools
cephadm shell
cephadm shell -- ceph -s
# Option 2: install the command-line tools on the host
cephadm install ceph-common
ceph -v
ceph status

At this stage the output of ceph status looks something like this. The warning about the OSD count is normal, because we have not added any disks yet:

text
  cluster:
    id:     3f6c1d2e-....-....
    health: HEALTH_WARN
            OSD count 0 < osd_pool_default_size 3
  services:
    mon: 1 daemons, quorum ceph-node1 (age 2m)
    mgr: ceph-node1.xkqzpa(active, since 1m)
    osd: 0 osds: 0 up, 0 in

1-7-4 Adding hosts#

For the orchestrator to create daemons on other hosts, the cluster's public key must be in their authorized_keys:

bashReef+
ssh-copy-id -f -i /etc/ceph/ceph.pub root@ceph-node2
ssh-copy-id -f -i /etc/ceph/ceph.pub root@ceph-node3
ceph orch host add ceph-node2 192.168.56.12 --labels _admin
ceph orch host add ceph-node3 192.168.56.13
ceph orch host ls

After the hosts are added, cephadm by default spreads up to five MONs and up to two MGRs over the available hosts. In production it is better to set their placement explicitly:

bashReef+
ceph orch apply mon --placement="ceph-node1,ceph-node2,ceph-node3"
ceph orch apply mgr --placement="ceph-node1,ceph-node2"
ceph orch ls
ceph orch ps
💡 Tip

Use labels instead of a list of host names. For example, give three hosts the mon label and run ceph orch apply mon --placement="label:mon". Later, moving a MON is just a matter of moving the label, with no need to edit the spec.

1-7-5 Adding OSDs#

The simplest way is to say that every free, suitable disk in the cluster should become an OSD:

bashReef+
ceph orch device ls
ceph orch apply osd --all-available-devices
# or disk by disk:
ceph orch daemon add osd ceph-node1:/dev/sdb
⚠ Warning

--all-available-devices creates a persistent service: any free disk added to any host later also becomes an OSD automatically. That is convenient in a lab, but in production it may swallow a disk you attached for something else. After the initial deployment you can stop this behaviour with ceph orch apply osd --all-available-devices --unmanaged=true, or use an OSD service spec with precise filters from the start (chapter 11).

After a few minutes the cluster should reach HEALTH_OK:

bashReef+
ceph -s
ceph osd tree
ceph df
✚ Troubleshooting

If the OSDs were not created, look at ceph orch ps --daemon-type osd and ceph log last cephadm. On the target host, cephadm ls and journalctl -u ceph-<fsid>@osd.<id> give more information. Most of the time the problem is one of these: the SSH key was not added, the container image cannot be pulled (for example because of restricted internet access or no internal mirror), or the nodes' clocks are not synchronised.

✎ Note

In environments without direct access to quay.io, you must build an internal registry and mirror the image there, then start with cephadm --image <registry>/ceph/ceph:<tag> bootstrap .... The "Deployment in an Isolated Environment" documentation has the details.

1-7-6 Centralised configuration#

Since Mimic, Ceph configuration is kept in the MONs' configuration database instead of in ceph.conf files on each host. The ceph.conf file on the hosts holds little more than the MON addresses.

bashReef+
ceph config dump                          # all non-default settings
ceph config get osd osd_memory_target     # the value for one daemon type
ceph config set osd osd_max_backfills 2   # change it for all OSDs
ceph config show osd.0 | head             # the effective value on a running daemon
ceph config help osd_memory_target        # description, type and default value

During bootstrap cephadm enables automatic tuning of OSD memory (osd_memory_target_autotune), which by default divides 0.7 of the host's memory among the OSDs. On hosts that also do other work (for example in a hyperconverged setup), lower this ratio.

1-8 Growing the cluster#

1-8-1 Adding a fourth node#

One of the beauties of Ceph is that growing the cluster is a "normal operation", not a project. Prepare ceph-node4 like the others and add it:

bashReef+
ssh-copy-id -f -i /etc/ceph/ceph.pub root@ceph-node4
ceph orch host add ceph-node4 192.168.56.14
ceph orch host label add ceph-node4 rgw
# If the all-available-devices service is active, the disks become OSDs automatically
ceph orch device ls ceph-node4
watch -n 5 ceph -s

In the output of ceph -s you will see some PGs go into the remapped and backfilling states. CRUSH has given the new OSDs a proportional share of the PGs, and the data is being moved. The cluster stays fully available during this time.

💡 Tip

In a production cluster holding a lot of data, adding many OSDs at once can cause a heavy wave of backfill. Since Quincy the mClock scheduler manages the recovery share automatically. If you want more control, set the norebalance flag before adding the OSDs, add them all, and then remove the flag, so that data moves only once and straight to its final destination. Tools such as upmap-remapped are also used to add weight gradually (chapter 7).

1-8-2 Adding MONs and other services#

bashReef+
ceph orch host label add ceph-node4 mon
# By label, but with an explicit cap of 3 instances (a YAML spec)
cat > mon.yaml <<'Y'
service_type: mon
placement:
  count: 3
  label: mon
Y
ceph orch apply -i mon.yaml
⚠ Warning

Do not run an even number of MONs. Four MONs, like three, tolerate the failure of only one (a majority is 3 of 4), but they have one more voting member and one more point of failure. Either stay at 3 MONs or go straight to 5.

At this stage we can also deploy the interface services so that we can use them in later chapters:

bashReef+
ceph orch apply rgw demo --placement="label:rgw" --port=8080
ceph fs volume create cephfs01        # the MDSs are deployed automatically
ceph orch ls

1-9 Hands-on work with the cluster#

1-9-1 Pools, objects and rados#

Let us start at the lowest layer, RADOS. We create a test pool, write a few objects to it and see where they are stored:

bashReef+
ceph osd pool create lab-pool
ceph osd pool application enable lab-pool rados-test
echo "salam ceph" > /tmp/hello.txt
rados -p lab-pool put hello /tmp/hello.txt
rados -p lab-pool ls
rados -p lab-pool stat hello
ceph osd map lab-pool hello

The output of ceph osd map looks something like this and shows the whole mapping path we saw in the CRUSH section: the pool and PG numbers, and the lists of up and acting OSDs, the first of which is the primary.

text
osdmap e87 pool 'lab-pool' (5) object 'hello' -> pg 5.4a3e9f1b (5.1b) -> up ([4,9,1], p4) acting ([4,9,1], p4)
▶ Try it

Temporarily stop one OSD of this set (ceph orch daemon stop osd.9), run ceph osd map again and look at ceph -s. The PG goes into the degraded state, but reading the object (rados -p lab-pool get hello -) still works. After about ten minutes (the default value of mon_osd_down_out_interval), the stopped OSD is marked out and recovery begins. At the end, start the OSD again: ceph orch daemon start osd.9.

1-9-2 A look at PGs and space#

bashReef+
ceph osd pool ls detail
ceph pg ls-by-pool lab-pool | head
ceph osd df tree
ceph df detail
ceph osd pool autoscale-status

There are two important columns in the output of ceph df: STORED (user data) and USED (the real space consumed, including replication). The MAX AVAIL column shows the writable space, taking the fullest OSD and the full ratio into account; this is the number capacity planning should be based on, not the raw sum.

1-9-3 A quick block device#

bashReef+
ceph osd pool create rbd
rbd pool init rbd
rbd create rbd/disk01 --size 10G
rbd info rbd/disk01
# On client-node1 (after copying ceph.conf and a suitable keyring; chapter 2)
sudo rbd map rbd/disk01
sudo mkfs.xfs /dev/rbd0 && sudo mount /dev/rbd0 /mnt

1-9-4 Cleaning up#

Deleting a pool in Ceph is deliberately hard, so that it does not happen by accident:

bashReef+
ceph config set mon mon_allow_pool_delete true
ceph osd pool rm lab-pool lab-pool --yes-i-really-really-mean-it
ceph config set mon mon_allow_pool_delete false
⚠ Warning

Never leave mon_allow_pool_delete permanently enabled in production. A typo in a clean-up script can delete a real pool forever. There is no "recycle bin" for pools.

1-10 From the code: from object name to bytes on disk#

1-10-1 Three layers of mapping#

Every RADOS request passes through three layers of mapping. None of them has a central "where is this object" table; everything is computed from the object name and the OSDMap. This is Ceph's most important design decision, and the rest of the chapters build on it.

Figure 1-8: The three layers of an object's path. In the logical layer, the object name is turned into a 32-bit number by the hash function called rjenkins (hobject_t keeps this hash together with the namespace and snap), and ceph_stable_mod maps it to a PG of the pool. In the mapping layer, CRUSH builds the list of OSDs from the placement seed (pps) and that pool's rule; then the exceptions recorded in the OSDMap, namely upmap and pg_temp/primary_temp, are applied to it, giving the up set and the acting set. The first member of acting is the primary. In the physical layer, each PG on each OSD is a collection in BlueStore (for example 3.1a_head). The metadata of each object is an onode in RocksDB, and the data points to raw ranges on the block device through the chain of extent, blob and pextent
Figure 1-8: The three layers of an object's path. In the logical layer, the object name is turned into a 32-bit number by the hash function called rjenkins (hobject_t keeps this hash together with the namespace and snap), and ceph_stable_mod maps it to a PG of the pool. In the mapping layer, CRUSH builds the list of OSDs from the placement seed (pps) and that pool's rule; then the exceptions recorded in the OSDMap, namely upmap and pg_temp/primary_temp, are applied to it, giving the up set and the acting set. The first member of acting is the primary. In the physical layer, each PG on each OSD is a collection in BlueStore (for example 3.1a_head). The metadata of each object is an onode in RocksDB, and the data points to raw ranges on the block device through the chain of extent, blob and pextent
text
pseudocode: object → OSD (this book's summary of Objecter::_calc_target and OSDMap)
  ps      = ceph_str_hash_rjenkins(name)          # or the pool's other hash
  pg      = (pool_id, ceph_stable_mod(ps, pg_num, pg_num_mask))
  pps     = crush_hash32_2(pg.ps, pool_id)        # placement seed (different for each pool)
  raw     = crush_do_rule(rule, pps, size, weights)
  up      = apply_upmap(raw) ; drop down/out OSDs
  acting  = pg_temp.get(pg, up) ; primary = primary_temp.get(pg, acting[0])
✎ Note

Run this computation yourself: ceph osd map rbd myobject follows the same path with the current OSDMap and prints the pg, up and acting. To run it offline on a copy of the map: ceph osd getmap -o om && osdmaptool om --test-map-object myobject --pool 3.

1-10-2 On-disk structures#

bluestore_onode_t in src/os/bluestore/bluestore_types.h has the fields nid (a unique numeric id within the OSD), size, attrs (xattrs), extent_map_shards, and the hints expected_object_size, expected_write_size and alloc_hint_flags. bluestore_blob_t is the unit of checksumming and compression, and bluestore_pextent_t is a physical range (offset and length). Blobs can be shared between clones as a bluestore_shared_blob_t.

Figure 1-9: Key prefixes in the RocksDB inside BlueStore, defined in BlueStore.cc. S is for the superblock, T for statistics, C for collections, O for onodes, M for omap, L for deferred transactions, B for the freelist and X for shared blobs. The bottom row shows the main fields of pg_log_entry_t, which is stored in the omap of each PG's special pgmeta object. These fields are the operation, the object id, the version and the previous version, the reqid used to detect a duplicate request after a client reconnects, and mod_desc, which allows rollback in EC
Figure 1-9: Key prefixes in the RocksDB inside BlueStore, defined in BlueStore.cc. S is for the superblock, T for statistics, C for collections, O for onodes, M for omap, L for deferred transactions, B for the freelist and X for shared blobs. The bottom row shows the main fields of pg_log_entry_t, which is stored in the omap of each PG's special pgmeta object. These fields are the operation, the object id, the version and the previous version, the reqid used to detect a duplicate request after a client reconnects, and mod_desc, which allows rollback in EC
Constant/optionValue (main)Why it matters
bluestore_min_alloc_size_hdd / _ssd4_K / 4_KThe smallest allocation unit; fixed when the OSD is created
bluestore_prefer_deferred_size_hdd / _ssd64_K / 0Smaller writes on HDD are first recorded in the WAL (deferred)
bluestore_max_blob_size_hdd / _ssd64_K / 64_KThe maximum blob size
bluestore_allocatorhybridThe default allocator
osd_min_pg_log_entries / osd_max_pg_log_entries250 / 10000The pg log length; longer means log-based recovery instead of backfill
osd_target_pg_log_entries_per_osd300000The total log budget of each OSD
⚠ Warning

The value of bluestore_min_alloc_size is recorded on the OSD at mkfs time, and changing the option on an existing OSD has no effect. Old HDD OSDs created with 64K (before Pacific) waste a lot of space for small objects such as RGW objects, and the only fix is to rebuild the OSD.

✚ Troubleshooting

Seeing these structures in practice (stop the OSD first):

bashReef+
ceph osd map rbd rbd_data.5e2a.0000000000000001
ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-4 --op list --pgid 3.1a | head
ceph-objectstore-tool --data-path ... --pgid 3.1a '<obj-json>' dump | jq '.onode'
ceph-objectstore-tool --data-path ... --op log --pgid 3.1a | jq '.pg_log_t.log[-1]'
ceph-bluestore-tool show-label --dev /dev/sdb
ceph daemon osd.4 bluestore allocator score block

1-11 Planning by the numbers: PG count, the probability of data loss, and rebuild time#

The numbers in this section come from real CRUSH mappings, not random placement. With crushtool --build --num_osds 120 … host straw2 12 root straw2 0 we built a map of 10 hosts × 12 OSDs whose default rule is chooseleaf firstn 0 type host. For each pg_num we created an osdmap with osdmaptool --createsimple 128 --pg-bits b --pgp-bits b and imported the map into it. The eight extra OSDs are not in CRUSH and receive no data. We then mapped every PG with osdmaptool --mark-up-in --test-map-pgs-dump. The tools were from Ceph 18.2.7 (Reef). The straw2 selection function (bucket_straw2_choose in src/crush/mapper.c) is the same in the main branch, so the result also holds for newer releases. The only assumption in this section is the per-disk rebuild rate, which is marked explicitly.

1-11-1 PG count and "copysets"#

∑ Algorithm: Probability of losing a PG when three OSDs fail at the same time

Source in code: Exact computation on the CRUSH mapping with osdmaptool; default mon_target_pg_per_osd = 200 from src/common/options/mgr.yaml.in

Complexity: O(pg_num) for mapping and counting

text
pseudocode
for each ps in [0, pg_num): up(ps) = CRUSH(rjenkins(ps, pool), rule)   # osdmaptool --test-map-pgs-dump
S = the set of distinct (unordered) triples in up
P(loss | three random OSDs fail at the same time) = |S| / C(120, 3)          # exact, not sampled
E[fraction of PGs lost] = Σ_PG 1/C(120,3) / pg_num = 1 / C(120,3)     # independent of pg_num

Result (120 OSDs, size = 3). There are C(120, 3) = 280840 possible triples.

pg_numDistinct triplesProbability of losing at least one PG
102410210.36%
8192 (about 200 PGs per OSD)80372.86%
655365624620.0%

At large pg_num values, the number of distinct triples falls below pg_num because of collisions. The expected fraction of data lost in such an event is exactly 1/280840 and does not depend on pg_num. Each PG is exactly one triple, and the probability that the failed triple is that one is 1/C(120,3).

The real choice is between "rarely, but a lot" and "more often, but a little". The same mappings show that with 8192 PGs the number of PGs per OSD ranges from 172 to 234. This unevenness is why the balancer and upmap exist (chapter 8).

Recovery fan-out. The same mappings show how many other OSDs each OSD shares PGs with on average. With 1024 PGs this number is about 40, and from 8192 onwards it reaches the ceiling of 108 (that is, 120 minus the 12 OSDs on the same host). So fast recovery (a short window in which three failures must coincide) matters much more than pg_num itself.

Figure 1-10: Result of the exact computation on the real CRUSH mapping for 120 OSDs on 10 hosts and a three-replica pool (crushtool and osdmaptool, Ceph 18.2.7). Left: the probability that three simultaneous failures completely destroy at least one PG, as a function of pg_num, together with the upper bound pg_num/C(120,3). Right: the number of OSDs that share a PG with one OSD (mean and range), and the number of PGs that land on the busiest target OSD after osd.0 is marked out
Figure 1-10: Result of the exact computation on the real CRUSH mapping for 120 OSDs on 10 hosts and a three-replica pool (crushtool and osdmaptool, Ceph 18.2.7). Left: the probability that three simultaneous failures completely destroy at least one PG, as a function of pg_num, together with the upper bound pg_num/C(120,3). Right: the number of OSDs that share a PG with one OSD (mean and range), and the number of PGs that land on the busiest target OSD after osd.0 is marked out

1-11-2 Declustered rebuild versus RAID#

∑ Algorithm: Time to restore redundancy, bottlenecked by the busiest target

Source in code: Mapping before and after osdmaptool --mark-out 0; real limits: osd_max_backfills, the mClock profile (chapter 21) and the network

Complexity: O(pg_num)

text
pseudocode
A = up before the failure ; B = up after osd.0 is marked out
moved = {pg : 0 ∈ A[pg]} ; for each pg: dst(pg) = B[pg] − A[pg]      # exactly one OSD in every case
data per PG = disk capacity / |moved|
t ≈ max_d |{pg : dst(pg) = d}| × data per PG / r                     # r = write rate of one disk (assumed)
RAID with one spare disk: t = capacity / r

Numeric example (a full 16 TB disk, assumed rate r = 0.15 TB/h). RAID takes about 107 hours. The real mapping gives these results for Ceph:

pg_numPGs on osd.0Busiest targetTime
25691 PG11.9 hours
1024252 PGs8.5 hours
81921908 PGs4.5 hours
65536159837 PGs2.5 hours

In these mappings there was no collateral movement: no PG other than those of osd.0 moved. With 8192 PGs, 38 of the 190 targets (20%) were on the same host as osd.0. The reason is that "out" does not change the host's weight in CRUSH, and the retry sometimes picks the same host again.

r is an assumption, and in practice the network, osd_max_backfills or the mClock profile impose a ceiling sooner. But the structure of the result is real: the busiest target, not the average, determines the time, and a larger pg_num spreads the load more evenly. This is the main reason for dropping RAID underneath Ceph.

Figure 1-11: Time to restore redundancy after the failure of a full 16 TB disk. Red is RAID with one spare disk and green is Ceph, where the number of PGs on the failed disk and on the busiest target come from the real CRUSH mapping (osdmaptool --mark-out 0). The vertical axis is logarithmic, and only the rate of 0.15 TB/h per disk is assumed
Figure 1-11: Time to restore redundancy after the failure of a full 16 TB disk. Red is RAID with one spare disk and green is Ceph, where the number of PGs on the failed disk and on the busiest target come from the real CRUSH mapping (osdmaptool --mark-out 0). The vertical axis is logarithmic, and only the rate of 0.15 TB/h per disk is assumed

1-12 Supplementary and up to date#

1-12-1 From 2019 to today: what has changed?#

In 2019 the Jewel (10.2) and Luminous (12.2) releases were still common. Since then eight more major releases have come out, and several fundamental changes have happened that anyone familiar with older sources should know about:

TopicAt the time of the bookToday
Deployment toolceph-deploy and ceph-ansiblecephadm (since Octopus) and Rook on Kubernetes; ceph-deploy is no longer maintained
Storage engineFileStore by default, BlueStore newBlueStore is the only supported option; FileStore was removed in Reef
Configurationceph.conf on every hostA centralised configuration database in the MONs (ceph config)
PG countManual calculationpg_autoscaler by default (since Octopus)
I/O schedulingWPQ with a manually tuned recovery sharemClock by default (since Quincy), with profiles
Network protocolmsgr v1msgr2 with optional encryption on port 3300 (since Nautilus)
Cache tieringAn active featureDeprecated since Reef
Graphical managementCalamari, VSMThe Ceph Dashboard inside the MGR
New interfaces—NVMe-oF/TCP gateway for RBD, SMB module for CephFS, IAM user accounts in RGW
Next-generation OSD—Crimson and SeaStore (technical preview)

1-12-2 Active releases at the time of writing#

According to the official releases page (visited November 2026), three stable releases are actively maintained: Umbrella (21.2, first released on 28 October 2026), Tentacle (20.2, first released on 18 November 2025; the latest version at the time of writing is 20.2.5) and Squid (19.2, with an estimated end of life on 2 December 2026). Reef is now archived. Ceph publishes one major release a year, and X.2.Z versions are the stable releases meant for production (X.1.Z are release candidates and X.0.Z are development points).

💡 Tip

A common production policy is to stay on the previous major release until several point releases of the new one have been published. For example, at the time of writing, Tentacle with five point releases is a more conservative choice than Umbrella, which was released only a few weeks ago. Read the release notes in full before upgrading, especially the sections that change defaults.

⚠ Warning

Umbrella changes several defaults that can alter the cluster's behaviour after an upgrade: the default mon_target_pg_per_osd has gone from 100 to 200 and mon_max_pg_per_osd from 250 to 500, so existing pools may autoscale to more PGs after the upgrade. For clusters whose OSD memory target is below 4 GB, or whose SSDs are split into more than two OSDs, the release notes suggest pinning the old values explicitly before upgrading.

1-12-3 Rook: Ceph on Kubernetes#

If your infrastructure is Kubernetes, Rook is the official CNCF operator (a graduated project) for running Ceph on Kubernetes. Rook runs the same Ceph daemons as Pods and exposes resources such as CephCluster, CephBlockPool, CephObjectStore and CephFilesystem as CRDs. At the time of writing, the latest Rook release is 1.21.2. cephadm and Rook both build on the shared concepts of the Ceph orchestrator, but choose only one of them for a given cluster.

1-12-4 When is Ceph not the right choice?#

Ceph is a powerful tool, but it is not right for every problem:

  • Very small clusters: below three or four hosts, Ceph's operational overhead and wasted capacity are usually not justified. A simple NAS or ZFS is better.
  • Very low latency for a single application: every write in Ceph needs at least one network round trip to the primary OSD and one to the secondaries. For a database that needs latency below 100 microseconds, local NVMe with application-level replication is a better option.
  • A team without operational experience: Ceph behaves well under failures, provided someone knows what to do in unusual situations. Investing in training and monitoring is part of Ceph's real cost.

1-13 Summary and review#

1-13-1 Chapter summary#

Key points
  • Software-defined storage separates intelligence from hardware and makes horizontal scaling, vendor independence and unified interfaces possible.
  • At the scale of multi-terabyte disks, RAID hits a dead end with many-to-one rebuilds, spare disks and URE risk; Ceph solves these problems with many-to-many recovery, checksums and scrubbing.
  • All Ceph interfaces (RBD, RGW, CephFS) are built on RADOS. The MONs hold the map, the MGR holds statistics and modules, and the OSDs hold the data.
  • CRUSH computes where data lives; there is no central table. An object maps to a PG, and a PG maps to a set of OSDs in different failure domains.
  • Correct planning (workload type, failure domain, network, fill ratio, SSDs with PLP) is the most important factor in Ceph's success.
  • cephadm is today's official deployment tool: bootstrap, add hosts, and declare the desired state with ceph orch apply.

1-13-2 Common mistakes#

  • Building OSDs on RAID 5/6, or on virtual disks that sit on one shared physical disk.
  • Using consumer SSDs without PLP for DB/WAL or MONs.
  • Setting min_size=1 to "stay up" during a failure.
  • Inconsistent MTU along the network path.
  • An even number of MONs, or putting all MONs in one rack.
  • Planning capacity from the raw capacity without accounting for nearfull and the loss of the largest domain.
  • Leaving the all-available-devices service running in production.

1-13-3 Self-assessment checklist#

  • I can explain Ceph's three interfaces and their common layer.
  • I know what the MON, MGR, OSD, MDS and RGW each do, and how many of each are needed.
  • I can show the object → PG → OSD path with ceph osd map.
  • I can build a three-node cluster with cephadm and add a fourth node.
  • I can estimate the usable capacity of a design, taking replication, failures and nearfull into account.

1-13-4 Hands-on exercise#

  1. 1. Build this chapter's four-node lab and bootstrap the cluster with three nodes. Save the output of ceph -s and ceph orch ps.
  2. 2. Create a replicated pool, write 100 small objects to it with a bash loop (for i in $(seq 1 100); do rados -p lab-pool put obj$i /etc/hosts; done) and look at their distribution across PGs with ceph pg ls-by-pool.
  3. 3. Add the fourth node and follow the backfill with ceph -s. What percentage of the PGs moved? Why did not all of them move?
  4. 4. Stop one OSD and measure the time until it is marked out and recovery finishes. Then lower mon_osd_down_out_interval to 60 seconds in the lab and repeat the test.
  5. 5. Compute the usable capacity of your own design for two scenarios, three-way replication and EC 4+2, with the condition of staying below 80% after the loss of one host.

1-13-5 Review questions#

  1. 1. What are the three fundamental limitations of traditional storage arrays that software-defined storage removes?
  2. 2. Why does RAID rebuild time get worse as disks get bigger, while Ceph recovery time gets better as the cluster gets bigger?
  3. 3. Compare the roles of the MON and the OSD in the write path of an object. Does data pass through the MON?
  4. 4. What problem does the PG layer solve, and what would happen if it did not exist?
  5. 5. Why is the number of MONs chosen to be odd? How many failures do four MONs tolerate?
  6. 6. What is the difference between size and min_size, and why is min_size=1 dangerous?
  7. 7. When is a separate cluster network useful, and what risk does it carry?
  8. 8. Why is an SSD without PLP unsuitable for Ceph?
  9. 9. Which files does cephadm create in /etc/ceph during bootstrap, and which one is the most sensitive?
  10. 10. Which two Umbrella default changes can alter the cluster's behaviour after an upgrade?

Answers to these questions are in Appendix E: Answers to Review Questions. Answers to this chapter's questions →

1-13-6 Sources for this chapter#

The Comprehensive Ceph Guide · 1.6 · November 2026
© 2026 Ramin Najarbashi · CC BY-NC-SA 4.0

Privacy: this site sets no cookies. Visits are counted with Cloudflare Web Analytics, which is cookie-less and does not track individuals.