11# simple-volume
22
3- ` simple-volume ` is a Kubernetes-native async replicated local-volume prototype .
3+ ` simple-volume ` is a Kubernetes-native async replicated local-volume system .
44Applications use normal PVCs backed by the ` simple-volume.shipstuff.io ` CSI
55driver. The controller and node agents handle the local replica lifecycle,
66freshness policy, and promotion state.
@@ -26,9 +26,10 @@ acceptable fit for many single-writer workloads.
2626See [ docs/why-simple-volume.md] ( docs/why-simple-volume.md ) for the full design
2727rationale, replication model, and storage options we evaluated.
2828
29- ## V0 Scope
29+ ## Initial Release Scope
3030
31- The V0 scope is intentionally narrow and complete enough for initial release:
31+ The ` v0.2.0 ` release is intentionally narrow and ready for initial real
32+ workload use with understood async-replication tradeoffs:
3233
3334- dynamic PVC provisioning into logical SimpleVolumes
3435- chart-configured local storage pools
@@ -40,38 +41,56 @@ The V0 scope is intentionally narrow and complete enough for initial release:
4041
4142Replication logic does not run inside CSI. CSI is the Kubernetes mount boundary;
4243the controller owns policy and the node agent owns local filesystem operations.
43- Like ` local-path ` , v0 does not enforce PV capacity at the filesystem layer. The
44- PVC request is used for Kubernetes API shape, placement decisions, and operator
45- visibility; workloads can still consume available space in the backing local
46- pool unless the host filesystem enforces its own limits.
44+ Like ` local-path ` , ` simple-volume ` does not enforce PV capacity at the
45+ filesystem layer. The PVC request is used for Kubernetes API shape, placement
46+ decisions, and operator visibility; workloads can still consume available space
47+ in the backing local pool unless the host filesystem enforces its own limits.
4748
4849## Replication Model
4950
50- The intended V0 replication path is watch-driven:
51+ The intended replication path is watch-driven and, by default, shadow-backed :
5152
5253- the active node-agent watches configured durable paths inside the active
5354 volume
5455- file events are debounced into batches
55- - replica agents receive batch sync requests
56- - replica agents pull changed files from the active agent's read-only rclone
57- WebDAV endpoint
56+ - in ` shadow ` consistency mode, the source agent first stages those changes into
57+ a local shadow tree
58+ - replica agents receive batch sync requests and pull from the completed shadow
59+ tree through the active agent's read-only rclone WebDAV endpoint
5860- the WebDAV server uses a short directory cache so newly written files are
5961 visible to watch-triggered pulls
62+ - a generation is considered successfully delivered only after the configured
63+ number of replicas confirms it
6064- an off-hours full resync schedule, such as ` 0 4 * * * ` , provides a safety net
6165 for missed events or agent restarts
6266
6367Volumes can replicate only selected folders/files. For game servers, this keeps
6468large reconstructable game downloads out of the hot replication path while still
6569protecting save/config state.
6670
71+ The default chart resources are sized for a low-memory steady state. The node
72+ agent uses conservative rclone settings for replication work: single-transfer
73+ copying, one checker, no explicit transfer buffer, and no multi-threaded stream
74+ copying. That keeps memory predictable on small clusters, including Pi-class
75+ nodes, but it also means large initial seeds can be slow. Operators that want
76+ faster whole-volume seeding should raise the agent memory limit and the rclone
77+ concurrency/buffer settings together once those knobs are exposed. Raising
78+ memory alone only increases headroom; it does not make a single-transfer sync
79+ faster.
80+
81+ Treat 1:1 full-volume seeding as an operational bootstrap path, not the normal
82+ replication profile. It walks many more files, includes reconstructable game
83+ runtime data, and can consume noticeably more accounted memory from kernel page
84+ cache and rclone directory/check state than scoped steady-state replication.
85+
6786The operator chooses the storage-capable node set when installing the chart by
6887scheduling the node-agent DaemonSet with normal Kubernetes selectors, affinity,
6988and tolerations. Workloads that consume ` simple-volume ` storage should also
7089declare matching scheduling intent in their own manifests. ` simple-volume ` owns
7190the per-volume active/fresh labels, but it should not depend on a mutating
7291admission webhook to make unrelated workload charts schedulable.
7392
74- The node agent exposes the V0 watch control surface used by the controller and
93+ The node agent exposes the watch control surface used by the controller and
7594manual E2E validation:
7695
7796- ` POST /replication/watch/start ` starts or replaces an active watch for a
@@ -104,7 +123,7 @@ Example start request:
104123}
105124```
106125
107- The controller reconciles this same behavior for annotated PVCs. For V0 it
126+ The controller reconciles this same behavior for annotated PVCs. It
108127discovers the active/source node from the running pod that mounts the claim,
109128uses all other ready node-agent pods as replicas, starts the source watch, and
110129optionally runs a scoped full sync against each replica.
@@ -115,15 +134,33 @@ metadata:
115134 simple-volume.shipstuff.io/replication-enabled : " true"
116135 simple-volume.shipstuff.io/replication-include-paths : " writes.log,saves/**"
117136 simple-volume.shipstuff.io/replication-exclude-paths : " downloads/**"
137+ simple-volume.shipstuff.io/replication-prune-excluded : " false"
118138 simple-volume.shipstuff.io/replication-debounce : " 2s"
139+ simple-volume.shipstuff.io/replication-consistency-mode : " shadow"
140+ simple-volume.shipstuff.io/replication-confirmed-replicas : " 1"
119141 simple-volume.shipstuff.io/replication-full-sync-on-start : " true"
120142 simple-volume.shipstuff.io/replication-full-sync-schedule : " 0 4 * * *"
121143` ` `
122144
145+ ` shadow` is the safe default for DB-like file trees because replicas pull from a
146+ source-side staged copy instead of the live directory while the app is mutating
147+ it. Workloads that do not need this can opt out with
148+ `replication-consistency-mode : " live" ` . Shadow mode writes an additional local
149+ copy of the included paths on the active node, so narrow include paths are the
150+ main mitigation for disk growth and SSD wear.
151+
152+ Excluded paths are preserved on replicas by default. This is important for
153+ large reconstructable caches such as Steam game installs: they can be excluded
154+ from replication without being deleted during a full sync. Set
155+ ` simple-volume.shipstuff.io/replication-prune-excluded: "true"` only when the
156+ replica must be an exact filtered mirror and deleting excluded files is
157+ acceptable.
158+
123159Replication uses rclone metadata preservation and the controller infers replica
124160file ownership from the active pod's `runAsUser`, `runAsGroup`, or `fsGroup`
125161when available. PVC annotations can override this for workloads without a pod
126- security context :
162+ security context. File-mode overrides preserve existing executable bits so
163+ launch scripts and runtimes are not made non-executable by normalization :
127164
128165` ` ` yaml
129166metadata:
@@ -138,7 +175,7 @@ The current schedule parser intentionally supports exact minute/hour cron
138175windows such as `0 4 * * *`; ranges and step expressions are left for the
139176controller-runtime implementation.
140177
141- Opt-in V0 failover is PVC annotation driven :
178+ Opt-in automatic failover is PVC annotation driven :
142179
143180` ` ` yaml
144181metadata:
0 commit comments