Build1 publisher2 min readPublished
An NFS-only StorageClass leaves Zeebe's RocksDB commits without an atomic rename
An air-gapped cluster of 10 servers runs every workload on NFS. The write-up blames that for Elasticsearch and Zeebe I/O failures, and its own numbers rule out Longhorn and local-path on ~100GB node disks.
The Engineer · Build desk

What happened
- A self-managed Kubernetes cluster in an air-gapped private datacenter runs 10 servers with roughly 100GB SSDs each, and NFS is the only StorageClass available to any workload on it.
- The write-up says that setup is adequate for general workloads and fails for the I/O-intensive ones, naming Elasticsearch and Camunda's Zeebe as the applications it cannot serve.
- Elasticsearch data has passed 100GB and keeps growing, which the post gives as the reason the cluster's limited local disk rules out Longhorn and local-path.
- The air gap removes AWS EBS and Azure Disk from consideration, and the post says the DevOps team is left with no straightforward alternative to NFS.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint A single NFS StorageClass sets the admission list for the whole cluster: any product whose storage engine needs atomic rename and a real fsync has to wait for a second class to exist before it can be scheduled at all.
- decision Every path off NFS here starts with hardware someone has to buy and rack inside the air gap, so the next move is a procurement decision taken by whoever owns the datacenter.
- exposure The risk the post describes is carried by the teams that own Zeebe and Elasticsearch, who would see it as corrupted application state and lost writes while the storage layer reports success.
- contradiction The post's case against NFS is about POSIX semantics, but its case against the local-storage options is about disk size, and those two constraints have different remedies.
Zeebe keeps its state in RocksDB [3]. RocksDB commits by renaming a file, and the dev.to write-up argues that NFS's stateless protocol does not guarantee atomicity across a network round trip; it attributes partial writes and data corruption to that gap [5]. The Elasticsearch half of the argument turns on fsync. According to the post, NFS satisfies sync inconsistently and often from the server's cache instead of the underlying storage, so a write can be acknowledged before it is durable, and the post ties write amplification and delayed persistence to that behaviour [6]. It also counts round trips: a stateless protocol needs one per metadata operation, which the post says accumulates into latency and head-of-line blocking on indexing and state-management paths [7].
Those are statements about what the engines require [4]. The post does not report latency measurements, error output, or the NFS version and mount options in use [15]. For the failure to transfer to another cluster, that export would have to be behaving the way the post assumes: sync answered from the server's cache, and rename not atomic under concurrent access. Those are properties of one server and one mount, and a test export against that server would settle both questions.
The capacity half is arithmetic on the post's own numbers. Ten servers at about 100GB of SSD each is roughly 1TB of raw local disk across the whole cluster [10]. The Elasticsearch data is already past 100GB and still growing [8], so one copy of it claims about a tenth of every raw byte the cluster owns [12].
Adding servers does not help the way it looks like it should. Ten more identical machines take aggregate raw capacity to about 2TB [13], and each individual disk is still 100GB, below the size of a single copy of the index [11]. The post excludes Longhorn and local-path on that disk size [8]; it excludes AWS EBS and Azure Disk on the air gap [9].
The consequence the post states for staying put is sustained performance degradation, data integrity risk and a higher probability of downtime [14].
What to watch
- Whether the team publishes the NFS version, server implementation and mount options, which would show whether these failures are protocol-level or configuration-level.
- Whether the promised solutions section names an on-premises block target and the per-node capacity it assumes.
- Whether Elasticsearch growth forces a disk purchase before any StorageClass change lands.