The Storage Model
Syself Autopilot ships one storage backend: the Hetzner CSI driver, with a single default StorageClass called standard. (CSI is the standard way Kubernetes talks to a storage system.) When a claim names standard, or names no class at all, it gets a network-attached Hetzner Cloud volume. For anything else you install and run the tool yourself: fast local disks through TopoLVM, shared read-write-many storage through JuiceFS, and database management through an operator like CloudNativePG.
You ask for storage with a PersistentVolumeClaim, or PVC. A PVC is a short request: how much space you need, and which kind of storage. A StorageClass names the kind. Whichever backend serves the claim, the PVC, the mounts, and the kubectl commands stay the same. Only the StorageClass name changes.
A pod can move to another machine, and local data does not move with it. If the pod's data sits on a local disk on the old machine, it starts on the new machine with an empty disk. Databases run best on local disks for speed, and you reach one through TopoLVM, which you install.
Which backend serves a claim#
The choice depends on what the workload needs and the node the pod lands on:
flowchart TD
S["You need persistent storage"] --> RWX{"Do pods on different nodes write the same files?"}
RWX -->|"yes (RWX)"| J["JuiceFS on S3-compatible object storage (you install it)"]
RWX -->|"no"| DB{"Is it a database?"}
DB -->|"yes"| P["CloudNativePG on local disks (you install it): replication, failover, PITR"]
DB -->|"no"| N{"Which node type runs the pod?"}
N -->|"bare-metal server"| T["TopoLVM local disk (you install it): local-nvme / local-ssd / local-hdd (fast, pinned to the server)"]
N -->|"cloud node"| C["Hetzner CSI volume: standard (network-attached, Ceph-replicated, follows the pod)"]You name a StorageClass in the claim, and that name plus the node the pod runs on decides the backend.
On a bare-metal server where you have installed TopoLVM, it hands out the extra disks as PersistentVolumes, one StorageClass per disk type: local-nvme, local-ssd, local-hdd. On a cloud node, a claim against standard (the cluster default, and the one backend the platform ships) goes to the Hetzner CSI driver, which creates and attaches a Hetzner Cloud block volume.
Local disks and pinning#
The local backend is TopoLVM, which you install yourself. Once it is running, a database pod claims a local disk the same way it claims any other volume: an ordinary ReadWriteOnce PersistentVolumeClaim. Only the StorageClass name (local-nvme, local-ssd, or local-hdd) tells TopoLVM which disk type to hand out. Nothing about the claim is special to bare metal except that name.
The disk sits in the same machine as the pod, so latency is low and steady.
Whether your data survives depends on what happens to the machine.
Reprovisioning the same server: your data survives. Syself Autopilot does not repair a node. It rewrites the OS on the same hardware, and the data disks stay attached through that. A reused bare-metal machine also keeps a constant node name, so when the node comes back it reattaches its old volume. Maintenance, OS upgrades, a full reprovision of that server all leave the data in place.
Moving the workload to a different server: your data does not come with it. The data stays on the original disk, so a pod that reschedules onto another physical machine starts with an empty volume. No setting copies the data elsewhere. That is the tradeoff for keeping every read off the network.
Warning
Local data is pinned, not replicated. If a pod moves to a different physical server it starts empty, and the old data sits on the original disk with no pod attached. If data cannot be re-created, do not keep it on a single local disk. Run a workload that keeps its own copies on more than one server, or back the data up to object storage.
See Use local storage on bare metal for setup.
Cloud volumes#
The Hetzner CSI driver creates and attaches a cloud volume automatically. Hetzner replicates each one with Ceph, so a single disk failure on their side does not lose it. The volume re-attaches wherever the pod is scheduled next. The driver runs one helper pod on every node (Kubernetes calls this a DaemonSet), so it uses one pod slot per node.
Note
A cloud PVC stays Pending until a pod that uses it gets scheduled. The driver needs the pod's placement to create the volume in the right Hetzner zone, so it waits for the pod before it provisions.
Every read and write crosses the network, which adds latency a local disk does not have. Cloud volumes fit testing, development, and workloads whose I/O needs are light. Because every read and write crosses the network, cloud volumes are too slow for a production database.
See Use Hetzner Cloud Volumes for StorageClass details, expansion, and deletion.
Shared writes (ReadWriteMany)#
Both backends allow one writer at a time. Kubernetes calls this ReadWriteOnce. A cloud volume attaches to one node at a time, and a local disk never leaves its server. Neither lets pods on different nodes write the same files at once.
When you need many nodes writing the same files (Kubernetes calls it ReadWriteMany, or RWX), use JuiceFS. It stores data in S3-compatible object storage and presents it as a filesystem that many pods on many nodes can write to at once. You install and run it yourself. Every read and write crosses the network to object storage, so JuiceFS is slower than a local disk. Use it for shared access, not for speed.
Databases#
A local disk does not replicate, so a database has to replicate itself. For PostgreSQL, CloudNativePG does that.
CloudNativePG is an operator: a program that runs inside the cluster and manages the database for you.
It keeps live copies of the database on other servers. Put those copies on separate physical machines. If a server is lost, CloudNativePG fails over to a replica and you keep the data. It also takes point-in-time backups (restore to any chosen moment) to your own object-storage bucket, in standard PostgreSQL format.
See ReadWriteMany with JuiceFS , Run databases , and Back up and restore .
Local disks versus cloud volumes#
The trade-off is speed against mobility. A local disk keeps every read inside the machine, so it is fast and steady and comes with the server, but the data stays behind when a pod moves. A cloud volume crosses the network, so it is slower and metered per gigabyte, but it follows the pod and Hetzner replicates it. Put state on bare-metal local disks when the workload can replicate itself, so a database under CloudNativePG gets local-NVMe speed and survives a lost server through its replicas; use cloud volumes when the workload cannot replicate itself and its I/O needs are light. Local versus network performance has the latency and throughput numbers, and the storage classes reference lists every class.
The two node types behind these two kinds of storage are provisioned as described in bare metal, cloud, and accelerators .
Next: backup and disaster recovery covers protecting pinned data against the loss of a whole machine. Node lifecycle covers what a reprovision keeps and what a replace loses.
Networking and Cilium
How one eBPF layer (Cilium) does pod networking, service load balancing, the host firewall, and network policy in every cluster, and where L7 policy still falls short.
Bare Metal, Cloud, and Accelerators
A cloud VM and a rented dedicated server become the same immutable Syself Linux node; run a cheap bare-metal base and add cloud pools only for burst.