architecture

Architecture

Documentation home · Replication · Lifecycle

The driver combines Kubernetes lifecycle management with a direct replicated filesystem protocol. Existing file operations go between a FUSE mount owner and replica workers; neither Kubernetes objects nor the manager are a per-write log.

Components

The following describes the 4.1.0 shared runtime, awaiting staging observations; no deployment is included in the release. Release 4.0.1 still uses generated node-controller and replica Pods.

Logical component Image and process Responsibility
Manager and API reconciliation manager, /manager --role=manager CSI create/delete, allocation, backing PVCs, credentials, transition, replacement and cleanup. The former node-controller work runs here.
NODE replica host node, /node --role=replica-host Own local CSI consumer publications and supervise multiple independent workers as goroutines.
Replica worker Objects inside the NODE replica host Own one backing journal, Raft member, filesystem state, authenticated endpoints and checkpoint/rebuild lifecycle.
CSI frontend node, /node --mount-service=unix:///… Serve kubelet node RPCs and forward mount lifecycle calls to the mount owner.
FUSE mount owner node, /node without --mount-service Own kernel FUSE connections, clients, handles, retries and RWO sessions.
Legacy replica worker replica, /replica --config=… Continue serving pre-transition volumes in their existing Pods.

The replica host is an additional container/process in the existing NODE DaemonSet Pod, with separate health/metrics and its own API client. It needs no additional per-node Pod. The standalone replica image remains for legacy volumes. CSI provisioner/registrar sidecars retain their usual lifecycle roles.

Pod footprint and resource bounds

For N storage nodes and replica counts R(v), release 4.0.1 generates N + sum(R(v)) controller/worker Pods. The 4.1.0 manager generates neither kind for new shared volumes; worker count increases in-process state instead. Individual local-CSI backing PVCs remain sum(R(v)). RF1 follows the same implementation and has no redundant copy. Legacy volumes keep their workers until an explicit transition, so deploying new code alone does not remove them.

The manager normally provisions new generations with --replica-runtime=shared; pod remains an explicit legacy option. Shared placement requires a ready replica-host container on an eligible local-storage node. The manager retires owned old API-only controller Pods and performs allocation itself.

The default node limit is 128 workers, four concurrent starts, 32 shared HTTP operations, two checkpoint captures and two outbound rebuilds. Outbound rebuilds share 32 MiB/s. Per-worker request/retry limits still apply. Exceeding admission returns an explicit pending/unavailable condition, not a smaller replica count. These are resource bounds, not storage quotas or measured capacity guarantees. The source NODE patch starts at 100m CPU / 128 MiB requested and 2 CPU / 768 MiB limited per replica host; operators must size that shared budget for the working set.

Storage and routing contract

The manager owns PVC allocation, selected-node binding and lifecycle intent. The NODE host owns local publication and worker-specific EndpointSlices. Each replica keeps its PVC, journal, generation and original Service DNS identity. Selectorless Services route to independent listener ports on the NODE Pod, so TLS roots, SANs and bearer credentials stay per-volume. There is no shared CA. Endpoints stay reachable for Raft before volume quorum readiness; health is a separate bounded runtime observation and the worker still verifies authority.

Local CSI must enable --consumer-mount-root and expose the same host directory with bidirectional propagation. The NODE host consumes it with HostToContainer propagation. Publication beneath that root is exclusive, recorded durably by local CSI before mounting, and blocks ordinary publication and deletion until normal unpublication completes. The host waits for the bind to appear in its own mount namespace before reading authority or initializing a worker. Dedicated publication locks also exclude an overlapping supervisor given a different private state root. No synthetic kubelet Pod paths or direct disk provisioning are used. Ordinary Pod volume lists cannot be extended in place; see Kubernetes Pod updates.

The host retains PVC/PV/node identity and initialization history on persistent host storage, takes process/publication locks, and protects active claims with a backing-use finalizer. Workers close before unpublication; the manager waits for an identity-bound release acknowledgement before removing that finalizer and requesting normal reclamation. API uncertainty leaves storage preserved.

Transition and failure policy

A generation-guarded shared-runtime request requires quiesced consumers and normal unpublish/unstage. The manager normally deletes legacy workers and waits for their absence on the original Ready node. Local CSI then affirmatively rejects acquisition while any other mount survives. The runtime selection is one-way; bindings, original trust, Raft identities and backing data remain intact. See the transition procedure.

The operator accepts shared process failures and explicit recovery to reduce footprint on 4–16 GB / 4–16 vCPU VM nodes; see the operating scope. A whole NODE Pod replacement also loses FUSE connections even with separate containers. Quotas and enterprise isolation remain outside this consolidation.

Worker failures stay local where possible; OOM/panic can still stop the shared process. A recorded replica is never freshly initialized when retained authority is missing. Missing/truncated retained journal or identity state is reported as ReplicaStateLost with application-data extent explicitly unknown. This is a known loss of replica authority, not a claim that every application byte is lost. Node/API absence reports unavailability or uncertainty, not confirmed data loss.

Data and control paths

flowchart LR
    K[Kubernetes API] --> M[Manager]
    M --> H[NODE replica host]
    H --> W[Independent replica workers]
    A[Application / kernel] --> F[FUSE mount owner]
    N[Kubelet / CSI frontend] --> F
    F --> W
    W <--> P[Raft peers]
    W --> V[Ordinary local-CSI PVC]

The manager supplies lifecycle and trust information. Workers establish actual quorum authority for reads, mutations, membership transitions and fences. Authenticated clients may discover a new coordinator without waiting for the manager to rewrite an application mount. Credentials are refreshed through a background API-dependent path; sufficiently long API outages can eventually prevent refresh and deny service.

Identity and authority

Identity Purpose
CSI create name Retry-safe creation key; not permission to reuse unrelated storage.
Application PVC namespace/name/UID Original source identity; a recreated name has a different UID.
Volume ID Stable rv-… handle used by CSI, Services and worker configuration.
Generation ReplicatedVolume UID, bound into protocol requests, trust and journal/checkpoint identity.
Replica ID and Node UID Original member and physical-placement identity; Node name reuse cannot replace it.
Backing PVC/PV identities Ownership and reclamation authority, preserved across retries and normal restart.
Request, file-object, handle and RWO epoch IDs Ordered operation/retry and access identities inside the data plane; not Kubernetes per-write objects.

Kubernetes records desired lifecycle intent. The journal/checkpoint chain and current quorum determine authoritative file state. A Running Pod, largest file, newest timestamp or absent PV is not a substitute for those authorities.

Provisioning flow

The provisioner supplies the original PVC metadata. The manager records immutable access mode, count, requested capacity and backing class, chooses distinct eligible local-storage nodes, and creates trust/configuration, backing claims and owned workers. A successful creation exposes one filesystem volume, not separate application-visible copies. A backing replica count of one follows the same implementation and has no redundant copy.

File operation flow

The application kernel sends a FUSE request to the mount owner. The client keeps one serialized operation/retry identity across endpoint changes. The elected worker coordinator establishes current quorum, orders mutations in Raft, and applies committed state to ordinary backing files. Reads wait for authority and applied state. Other members catch up from ordered journal entries or a verified checkpoint and tail. An unsuccessful call can still have committed; see uncertain results.

Failure boundaries

A surviving replica majority may elect a coordinator and continue I/O. Losing quorum returns errors rather than silently weakening membership. Replacing the CSI frontend can retain a surviving mount owner's connections. Losing that owner, the kernel or the host requires normal unpublish/unstage/remount; transparent open-descriptor recovery is not promised. Permanently lost original-node repair and reclamation remain blocked under the current contract.