A pod that restarts loses everything it didn’t write elsewhere: that’s a container’s basic contract. A PersistentVolumeClaim promises storage that survives that restart, but the promise only holds if something actually provisions a volume behind it. On EKS, GKE, or AKS, the default StorageClass triggers that provisioning through the cloud’s API. On an on-premise cluster, without that provisioner, a PersistentVolumeClaim stays Pending, exactly like a LoadBalancer Service without MetalLB.
What a PVC actually asks for
A PersistentVolumeClaim doesn’t describe a physical disk, but a need: how much space, with which access mode (ReadWriteOnce for a single pod at a time, ReadWriteMany for several pods simultaneously).
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-postgres
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: longhorn
resources:
requests:
storage: 20Gi
storageClassName references the provisioner responsible for satisfying that request. Without a matching provisioner installed on the cluster, that reference points at nothing, and the PVC waits indefinitely.
Longhorn: replicating local disk instead of centralizing
Longhorn turns each node’s local storage into distributed, replicated volumes, with no shared storage hardware (SAN, NAS) to operate separately. Every Longhorn volume is replicated across several nodes (three by default): losing a node doesn’t lose the data, a replica exists elsewhere. The longhorn-manager component driving that replication on every node runs, like MetalLB’s speaker, as a DaemonSet: present everywhere local storage needs managing, no exceptions.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn
provisioner: driver.longhorn.io
parameters:
numberOfReplicas: "3"
staleReplicaTimeout: "2880"
This approach avoids a dependency on centralized storage hardware, often absent or aging precisely in the legacy infrastructures that are candidates for a Kubernetes migration. The trade-off: replication consumes disk space on every participating node (three replicas by default means three times the space used), and performance depends directly on the network between nodes, which every replicated write travels across.
Replication is not a backup
The most common and costly confusion: three replicas protect against a node failure, not against an accidental deletion, application corruption, or a pod overwriting its own data by mistake. An unfortunate deletion replicates just as faithfully as any other write, across all three nodes at once. Longhorn offers snapshots and backups to external object storage (S3 or compatible) for exactly this reason: replication answers an availability question, backup answers a recovery-from-error question, and confusing the two is a discovery nobody wants to make during an incident.
What decides if Longhorn is the right choice
Longhorn fits modest-sized volumes with reasonable performance requirements (SME databases, message queues, persistent caches): the most common use case for a migration from VMs with local disks. A workload demanding extreme I/O performance or very large volumes generally finds a better answer in a distributed storage solution more mature on that specific ground (Rook/Ceph), at the cost of notably higher operational complexity. The criterion isn’t “is Longhorn good enough in absolute terms” but “does the target volume and workload exceed what three-node replication comfortably absorbs.”
Takeaway
A PersistentVolumeClaim stuck in Pending on an on-premise cluster signals the absence of a storage provisioner, exactly like a LoadBalancer Service signals the absence of MetalLB. Longhorn fills that gap by replicating each node’s local disk instead of depending on centralized storage, provided replication is never confused with a backup. This storage foundation gets laid at the same early steps as a Kubernetes migration from VM-based infrastructure.