From 459dad954bdeac383a9caaf5bec82f268e25a547 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Tue, 23 Jun 2026 16:25:14 +0200 Subject: [PATCH] =?UTF-8?q?v0.40.0:=20third=20CT=20volume=20=E2=80=94=20SS?= =?UTF-8?q?D=20user-data=20(/mnt/sys=5Fdrive,=20mp1)=20baked=20+=20-sysdat?= =?UTF-8?q?a-grow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the OS/Docker-data split to a three-volume layout: rootfs + Docker-data (mp0) + SSD user-data (mp1 @ /mnt/sys_drive, backup=1) = the controller's system_data_path. Clears the controller's "not a separate drive" warning with zero controller change (it already auto-discovers /felhom-data and warns via system.IsMountPoint; the mp reaches the container via the existing -v /mnt:/mnt:rslave bind). - build-golden.sh: --mp1 ...,mp=/mnt/sys_drive,backup=1 (env GOLDEN_SYSDATA_GB=8); findmnt /mnt/sys_drive separate-mount guard + vzdump aborts if mp0 OR mp1 excluded. - bringup.go: DefaultSysDataMount=mp1; BringUpSpec.{SysDataGrowGB,SysDataMount}; new "4c" online grow-only block mirroring the "4b" Docker-data grow. - main.go: -sysdata-grow / -sysdata-mount flags wired into all three call sites. - Tests: SysDataGrow (asserts ResizeLXC mp1 +42G) + SysDataGrowZeroNoResize. - RUNBOOK extended to the three-volume layout (32 rootfs + 200 docker + 50 user-data). Static CT volume, NOT an enrolled drive — never enrolls/ejects/decommissions. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW --- CHANGELOG.md | 31 ++++++++++++ RUNBOOK-provisioning-storage.md | 78 ++++++++++++++++++++---------- cmd/felhom-agent/main.go | 18 +++++-- configs/build-golden.sh | 28 +++++++++-- internal/reconcile/bringup.go | 32 ++++++++++++ internal/reconcile/bringup_test.go | 58 ++++++++++++++++++++++ 6 files changed, 210 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62f98af..8da8126 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,37 @@ All notable changes to **felhom-agent** are recorded here. Update on every code change that gets pushed. +## v0.40.0 — third CT volume: SSD user-data (`/mnt/sys_drive`, mp1) baked + `-sysdata-grow` (2026-06-23) + +**The third golden volume.** Extends the OS/Docker-data split (v0.29.x) to a **three-volume layout**: +rootfs + Docker-data (`mp0`) + **SSD user-data (`mp1` @ `/mnt/sys_drive`, `backup=1`)** — the +controller's `system_data_path`. Until now `/mnt/sys_drive` was a plain directory on the 32 GB OS +rootfs, so the controller correctly warned that SSD app data (`/felhom-data`) lands on the +OS drive. Baking it as its own thin volume clears that warning with **zero controller change** (the +controller already auto-discovers `/felhom-data` and warns via `system.IsMountPoint`); the +`mp` under the guest's `/mnt` reaches the controller container through the existing +`-v /mnt:/mnt:rslave` bind. + +- **`configs/build-golden.sh`** — `pct create` gains + `--mp1 ${ROOTFS_STORAGE}:${GOLDEN_SYSDATA_GB},mp=/mnt/sys_drive,backup=1` (new env + `GOLDEN_SYSDATA_GB=8`, near-empty; provision grows it). The resilience guards are mirrored for `mp1`: + a `findmnt /mnt/sys_drive` separate-mount assertion, and the vzdump-inclusion guard now aborts if + **either** `mp0` **or** `mp1` is EXCLUDED (the B3 trap — extra mountpoints default `backup=0`). The + golden does NOT pre-create `felhom-data`; the controller does once it's a real mountpoint. +- **`internal/reconcile/bringup.go`** — `const DefaultSysDataMount = "mp1"`; `BringUpSpec` gains + `SysDataGrowGB int` + `SysDataMount string`; a new **"4c"** grow block (online, grow-only `ResizeLXC`, + its own task) mirrors the "4b" Docker-data grow. `0 = skip` (separateness comes from the golden, not + the grow — the warning clears regardless of size). +- **`cmd/felhom-agent/main.go`** — `-sysdata-grow` / `-sysdata-mount` flags (mirror + `-datavol-grow`/`-datavol-mount`); `bringUpSizing` carries them into all three bring-up/provision call + sites; `--selftest=provision` help text updated. +- **Static volume, NOT an enrolled drive.** `/mnt/sys_drive` is part of the baked golden layout; it + never enrolls/ejects/decommissions and is deliberately kept off the drive-intent machinery. + `freeMountSlot` auto-skips the baked `mp0`/`mp1` so enrolled drives never collide. +- Tests: `TestRunBringUp_StorageSplit_SysDataGrow` (asserts `ResizeLXC(vmid,"mp1","+42G")`) + + `…_SysDataGrowZeroNoResize` (0 → no mp1 resize). RUNBOOK-provisioning-storage.md extended to the + three-volume layout (default ~512 GB SSD: 32 rootfs + 200 docker-data + 50 user-data). + ## v0.39.0 — DR recipe completion: live PBS coord + drop the two unfillable drive fields (2026-06-16) **DR-recipe agent-half completion.** A live eyeball of the demo recipe (v0.38.0) found three host-half diff --git a/RUNBOOK-provisioning-storage.md b/RUNBOOK-provisioning-storage.md index e339d4b..4ce3b02 100644 --- a/RUNBOOK-provisioning-storage.md +++ b/RUNBOOK-provisioning-storage.md @@ -1,23 +1,38 @@ -# RUNBOOK — provisioning the OS / Docker-data storage split +# RUNBOOK — provisioning the OS / Docker-data / user-data storage split -How the controller guest's **OS rootfs** and **Docker data** are carved onto separate `local-lvm` -volumes, and how to size them per node/customer. Grounded by the storage-split spike -(`REPORT-storage-split-spike.md`). Defaults target a ~512 GB SSD: **32 GB OS rootfs + 256 GB -Docker-data**, rest of the thin pool free for other guests. +How the controller guest's **OS rootfs**, **Docker data**, and **SSD user-data** are carved onto three +separate `local-lvm` volumes, and how to size them per node/customer. Grounded by the storage-split spike +(`REPORT-storage-split-spike.md`). Defaults target a ~512 GB SSD: **32 GB OS rootfs + 200 GB Docker-data ++ 50 GB user-data**, rest of the thin pool free for other guests. ## The design (locked) +Three thin volumes are baked into the golden and grown at provision: + +| mp slot | Mount | Holds | Golden default | Provision grow knob | +|---------|-------|-------|----------------|---------------------| +| rootfs | `/` | OS only | `OS_SIZE_GB=32` | `-rootfs-grow` | +| `mp0` | `/var/lib/docker` | ALL Docker images + overlay + named volumes | `GOLDEN_DOCKER_GB=16` | `-datavol-grow` | +| `mp1` | `/mnt/sys_drive` | SSD user-data (the controller's `system_data_path`; `/felhom-data` = SSD-only app data + DBs) | `GOLDEN_SYSDATA_GB=8` | `-sysdata-grow` | + - **Split for resilience, not backup size.** An isolated OS rootfs stays bootable + agent-recoverable - if the Docker volume fills. Both volumes ride into PBS regardless (so the backup size is unchanged) — - the win is independent sizing/growth and a smaller, faster-to-restore OS rootfs. + if the Docker volume fills. All three volumes ride into PBS regardless (so the backup size is + unchanged) — the win is independent sizing/growth and a smaller, faster-to-restore OS rootfs. - **One Docker daemon, one data-root, one volume** at `/var/lib/docker` for ALL images + overlay (controller, traefik, cloudflared, filebrowser, and customer apps). Infra is NOT relocated to the OS partition — infra/user separation under one daemon isn't cleanly possible and isn't needed. Infra is protected by the controller's **prevention layer** (reserved buffer + deploy gate + disk alerts + baked log rotation), not by placement. -- **`backup=1` on the Docker-data volume is non-negotiable.** Extra LXC mountpoints default to - `backup=0` = EXCLUDED from vzdump/PBS (spike B3). Without it, named-volume DBs fall out of the - snapshot AND the volume (with baked images) is excluded from the golden archive. +- **`/mnt/sys_drive` is a static CT volume, NOT an enrolled drive.** It never enrolls, ejects, or + decommissions — it is part of the golden's baked layout. The controller auto-discovers + `/felhom-data` and, via `system.IsMountPoint`, **warns when `/mnt/sys_drive` is not its own + mount** (`selftest.go`). Making `mp1` a real mount clears that warning with **zero controller change**; + the controller is untouched by this slice. The `mp` mounted under the guest's `/mnt` propagates into + the controller container through the existing `-v /mnt:/mnt:rslave` bind (the same path enrolled drives + use). +- **`backup=1` on the Docker-data AND user-data volumes is non-negotiable.** Extra LXC mountpoints + default to `backup=0` = EXCLUDED from vzdump/PBS (spike B3). Without it, named-volume DBs / SSD app + data fall out of the snapshot AND (for mp0) the baked images are excluded from the golden archive. ## Golden build (per controller-image baseline) @@ -25,15 +40,20 @@ Docker-data**, rest of the thin pool free for other guests. ``` # defaults shown; override via env -OS_SIZE_GB=32 GOLDEN_DOCKER_GB=16 \ +OS_SIZE_GB=32 GOLDEN_DOCKER_GB=16 GOLDEN_SYSDATA_GB=8 \ ./build-golden.sh