Rook-Ceph Cluster Guidance
This document summarizes operational guidance for the Rook-Ceph cluster in this repo. It is based on recent troubleshooting and expansion planning.
Current Topology Assumptions
- OSDs run on worker nodes only.
- Failure domain is
host(replicas spread across nodes). - Replication size is 3.
Nearfull Diagnostics (Read-Only)
Use these commands to identify nearfull OSDs and pools:
ceph osd df
ceph health detail
ceph osd tree
ceph osd dump | egrep 'nearfull|backfillfull|full'Interpretation tips:
nearfull_ratiois the warning threshold.- A single nearfull OSD can flag multiple pools as nearfull.
- With mixed-size OSDs, smaller disks fill first even if total free space exists.
Rebalancing Guidance
If the built-in balancer reports no optimization but one OSD is hotter than others:
- Confirm balancer status:
ceph balancer status- If needed, enable balancer (safe, standard):
ceph balancer on
ceph balancer mode upmap- If balancer still shows no plan, use manual reweighting:
ceph osd reweight osd.<id> 0.95Monitor and step down in small increments (0.02 to 0.05) if necessary:
ceph -s
ceph osd dfAlternative automatic reweight-by-utilization:
ceph osd reweight-by-utilization 110Rebalancing does not create capacity. If you are nearfull, add capacity or delete data.
Capacity Expansion Strategy
Recommended order (safest to most risky):
- Add larger disks to worker nodes, keep old disks temporarily, rebalance, then retire old OSDs.
- Replace disks on workers one node at a time (swap-in-place).
- Add OSDs to control-plane nodes (not preferred).
Reasons to avoid control-plane OSDs:
- Control-plane services are latency-sensitive.
- Lower memory (16 GiB) increases contention risk.
- Operational complexity and failure impact are higher.
Mixing sizes is supported, but large skews increase nearfull risk on smaller drives.
Mapping OSDs to Nodes/Devices
Use these to identify which OSD is on which node/device:
ceph osd tree
ceph osd find <id>
ceph device ls-by-osd osd.<id>Swap-In-Place (No Extra Ports)
If you cannot keep the old disk connected while adding a new one, use this workflow. This is riskier because the cluster is degraded during each swap. Do this one node at a time and keep the window short.
- Confirm the cluster is stable:
ceph -s- Mark the target OSD out (start data migration while it is still online):
ceph osd out osd.<id>- Wait until recovery/backfill completes:
ceph -sLook for these signals before proceeding:
pgsshows onlyactive+clean(noremapped,recovering,backfilling).objects misplacedis 0.
[!NOTE] If an OSD is still
outand you only have 3 OSDs with size=3 replication, recovery cannot finish. In that case, continue the swap and bring the new OSDinso the cluster has a third placement target.
- Power down the node, swap the disk, and boot it back up.
sudo systemctl stop k3s
sudo systemctl disable k3s- Clear the disk to prepare it for rook-ceph
# clear disk
export DISK_ID='/dev/disk/by-id/ata-SATA_SSD_...'
sudo rm -rf /dev/ceph-*
sudo rm -rf /dev/mapper/ceph-*
sudo sgdisk --zap-all "${DISK_ID}"
sudo dd if=/dev/zero of="${DISK_ID}" bs=1M count=100 oflag=direct,dsync
sudo blkdiscard "${DISK_ID}"
sudo partprobe "${DISK_ID}"
# start k3s
sudo systemctl enable k3s
sudo systemctl start k3s- Update the Rook-Ceph HelmRelease (and Ansible vars) with the new disk by-id for that node:
kubernetes/apps/rook-ceph/rook-ceph-cluster/app/helmrelease.yaml
- Verify the new OSD comes up:
ceph osd tree
ceph osd df- Confirm health returns to OK/WARN only for recovery:
ceph -s[!CAUTION] Do not remove a second OSD until the first swap is fully recovered! With size=3 and only 3 OSDs, one OSD out reduces redundancy to 2.
- Remove old OSD from CRUSH and OSD map.
[!CAUTION] Do not remove the old OSD until the swap is fully recovered!
ceph osd out osd.X
ceph osd purge osd.X --yes-i-really-mean-itSlow/Stalled recovery
If ceph -s reports PG’s stuck in active+clean+remapped for a prolonged period of time, it may be possible to force the recovery.
# in ceph toolbox
cd /tmp
ceph osd getcrushmap -o crush.map
crushtool -d crush.map -o crush.txtEdit crush.txt: vi crush.text; set “tunable choose_total_tries 100”
crushtool -c crush.txt -o crush.map2
ceph osd setcrushmap -i crush.map2