---
description: Storage on a Kubernetes Instant Cluster — node-local scratch, raw NVMe volumes, ReadWriteMany volumes on the shared filesystem, and when to use which StorageClass.
revision_date: 27.07.2026
---

# Storage

## Storage classes

Three storage classes are pre-configured:

| StorageClass | Access modes | Backed by | Use for |
| ------------- | ------------- | ---------- | -------- |
| `local-path` (**default**) | RWO | Node root disk (~300 GB, shared with the OS) | Scratch data, per-node caches, checkpoints — tied to one node |
| `shared-path` | **RWX** / ROX / RWO | Shared filesystem (visible on every node) | Datasets, shared model-weight caches, outputs that multiple pods on different nodes mount simultaneously |
| `local-disk` | RWO | Raw node-local NVMe (`/mnt/local_disk`) | Manually managed node-local volumes — by far the fastest I/O |

```console
$ kubectl get storageclass
NAME                   PROVISIONER                             VOLUMEBINDINGMODE
local-disk             kubernetes.io/no-provisioner            WaitForFirstConsumer
local-path (default)   rancher.io/local-path                   WaitForFirstConsumer
shared-path            cluster.local/shared-path-provisioner   Immediate
```

## Node-local scratch (`local-path`, default)

Dynamic PVCs against the default class are provisioned on the node where the consuming pod is scheduled. They live under `/opt/local-path-provisioner` on the node's root disk, which is shared with the OS — size requests are not enforced, so keep them well under the ~300 GB the disk holds. For genuinely I/O-heavy work use `local-disk` (NVMe) instead:

```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: scratch
spec:
  # storageClassName omitted → default (local-path)
  accessModes: [ReadWriteOnce]
  resources:
    requests:
      storage: 50Gi
```

The volume lives and dies with that node: it cannot follow a pod that gets rescheduled elsewhere, and a node replacement loses its contents. Use it for data you can regenerate (caches, temporary checkpoints, preprocessing scratch).

## Shared, multi-node volumes (`shared-path`)

`shared-path` provisions volumes as directories on the cluster's shared filesystem, so the resulting PersistentVolumes have **no node affinity** and support **ReadWriteMany**: any pod on any node can mount the same volume simultaneously. This is the right class for the download-once-use-everywhere pattern:

```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: model-weights
spec:
  storageClassName: shared-path
  accessModes: [ReadWriteMany]
  resources:
    requests:
      storage: 500Gi
```

Performance note: `shared-path` I/O goes over the network to the shared filesystem. For bandwidth-critical inner-loop I/O (e.g. streaming dataloader shards), stage data onto node-local storage first and keep `shared-path` for the shared source of truth. Measured on a B300 cluster with 1 GiB sequential writes (`dd oflag=direct`): `local-disk` ~7.8 GB/s, `local-path` ~270 MB/s, `shared-path` ~80 MB/s.

## The shared filesystem itself

The same shared filesystem backs `/home` on every node (jumphost and workers), sized when you deploy the cluster — see [Shared Filesystem (SFS)](https://docs.verda.com/storage/shared-filesystems-sfs/creating-a-shared-filesystem/). Anything under `/home` is also reachable from pods via `hostPath` volumes if you prefer path-based access over PVCs, e.g. for quick experiments with data you staged over SSH:

```yaml
volumes:
  - name: home-data
    hostPath:
      path: /home/ubuntu/datasets
      type: Directory
```

For production workloads, prefer the `shared-path` StorageClass — PVCs are quota-friendly, self-documenting and survive refactors better than hard-coded host paths.
