* feat: introduce partition/region/ceph-cluster model across the stack
Formalize partition -> region -> {one k8s cluster, many ceph clusters} and
thread it through every layer plus a new yuctl ops CLI.
- tf: deployment/<partition>/<region>/<stack> layout; terragrunt path-parse +
state key yucca/<partition>/<region>/<stack>; per-region region.hcl (role,
site_id, datacenter, provider_code, domain); env->partition / site->region
renames (NetBird object names byte-identical); standardized per-stack
`discovery` output contract (secrets as op:// refs).
- k8s: clusters/<partition>/<region>/ (staging/austin, prod/htz-fsn1, dev/local);
role-based kustomize components (primary/secondary); hybrid cluster-settings
(TF-rendered identity + human fragment); dev-mirror folded into dev/local;
charts regrouped into charts/{apps,platform,lib,dev}.
- ci: infra.yml partition/region discovery matrix; partition-keyed path filters;
<partition>-<region> environment gates; image-versions path moves.
- ansible: inventories under <partition>-<region>/<cluster>.
- yuctl: Go/cobra CLI reading the discovery contract from TF state.
- Retire the sietch-talos libvirt VM cluster (dev@local is the k3d cluster);
ceph inventory_dirname -> <partition>-<region>/<cluster>.
Verified: mise k8s:validate green (3 clusters); yuctl go build/vet; tofu
validate pre-merge (all 9 stacks). Live-staging state migration NOT run.
* fix typo
* commit
3.3 KiB
Runbook: Replace a Host (Hardware Swap, Preserving Name)
When: chassis failure, motherboard swap, or preventative hardware refresh. You want the new box to assume the old host's identity — same hostname, same IP, same Ceph OSD identities.
Time estimate: 1-2 hours (bare-metal) / 30 min (Hetzner).
Preserving name = preserving trust
Keeping the old hostname avoids:
- Re-issuing the ansible-iac SSH key to a new hostname
- Rotating the host's Ceph auth keys
- Updating monitoring dashboards / alert rules with new labels
- Updating any external systems that refer to the hostname
The TF inventory declaration stays unchanged — cluster name, host name, bond IP all match. Only the physical box changes.
Steps
1. Mark OSDs out, wait for backfill
# SSH to bootstrap node
sudo ceph osd out $(sudo ceph osd ls-tree <hostname-being-replaced>)
sudo ceph -w # watch for HEALTH_OK or acceptable degraded state
Depending on cluster size, full backfill can take hours. For time-critical replacements, skip this step and accept degraded state during rebuild — but confirm you have headroom.
2. Power down old host, rack new one in same slot
Preserve the physical network cabling and IPMI address. The new box gets the same bond IP via the same DHCP reservation / static config.
3. Re-run provisioning against the new host
Bare-metal (sietch):
# Boot the new box from the Debian 12 live image (same procedure as first
# provision — see docs/runbooks/add-node.md for iDRAC steps).
CEPH_ENV=inventories/staging-austin/sietch/inventory-provision.ini \
scripts/ansible-play.sh provision.yml \
-e confirm_wipe=true \
--limit sietch-ceph-<name>
Hetzner (NVMe-RAID host): reboot into rescue, run installimage +
post-install scripts from the cluster's inventories/<cluster>/installimage/.
4. Clear the old host's Ceph state
The cluster still has the old host's OSDs, CRUSH entries, and cephadm host record. Clean those up BEFORE the new box rejoins:
# On bootstrap node:
for osd in $(sudo ceph osd ls-tree <hostname>); do
sudo ceph osd purge $osd --yes-i-really-mean-it
done
sudo ceph osd crush remove <hostname>
sudo ceph orch host rm <hostname> --force
5. Re-run baseline + deploy for that host
scripts/ansible-play.sh baseline.yml --limit <hostname>
scripts/ansible-play.sh deploy-ceph.yml \
--limit <hostname>,<bootstrap-hostname>
Note bootstrap host must be in --limit — join/placement/OSD activation
all run from bootstrap.
6. Verify
# All OSDs for the replaced host are up+in
sudo ceph osd tree | grep <hostname>
# Cluster is rebalancing or healthy
sudo ceph -s
Gotchas
- Hardware topology changed: new chassis may have different PCI paths
for SAS controllers / NVMe. Update
host_vars/<hostname>.yml(sas_path_prefix,ceph_hdd_osds) before step 5. - Different serial numbers: acceptable —
by-pathis used for OSD slot identity, notby-id. - Backfill thundering herd: if you skipped step 1, the new OSDs enter
the cluster and backfill aggressively. Throttle with
ceph_osd_recovery_max_activein vars.yml if you see client-IO impact.
References
docs/runbooks/add-node.md— related but for net-new hostsdocs/runbooks/replace-disk.md— single-disk replacement within a host