Storage
StorageClasses
| StorageClass | Provisioner | What it is | Survives the node going down |
|---|---|---|---|
longhorn |
driver.longhorn.io | Block storage replicated across nodes (/var/lib/longhorn/) |
✅ yes, if there are healthy replicas on other nodes |
longhorn-static |
driver.longhorn.io | The same, for volumes created by hand | ✅ |
local-path |
rancher.io/local-path | A directory on the node (/var/lib/rancher/k3s/storage/) |
❌ no: the pod is tied to that node |
⚠️ Two StorageClasses are marked as default (local-path and longhorn). A PVC without storageClassName lands on either of them. The mark has to be removed from local-path:
kubectl patch sc local-path -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
k3s puts that annotation back on restart unless it is started with
--default-local-storage-pathor with the addon disabled. Check after restarting a master.
Longhorn
- Version 1.11.1 (Helm). Values: cluster/helm/longhorn-system/longhorn.yaml.
defaultReplicaCount: 2in the values, but the volumes have 3 replicas: the PVCs use the StorageClass, which is what wins. Exception:prometheus-grafana, with 2 anddataLocality: best-effortfromgrafana_local.sh(a change on the volume: if the PVC is recreated, it goes back to 3).- Disks under
/var/lib/longhorn/on the 5 amd64 nodes. The worker-3 doesn't take part. - The worker-1 has a spinning HDD: replica rebuilds there are slow and create a lot of I/O pressure.
Volumes
| PVC | Namespace | Size | State | Node in use |
|---|---|---|---|---|
elasticsearch-data-elasticsearch-es-default-0 |
logging | 20 Gi | attached | master-3 |
es-snapshots |
logging | 50 Gi | attached | master-3 |
minio |
minio | 20 Gi | attached | worker-2 |
local-home-confluence-0 |
confluence | 1 Gi | attached | worker-2 |
n8n-data-longhorn |
n8n | 5 Gi | attached | master-1 |
portainer-longhorn |
portainer | 10 Gi | attached | worker-1 |
homelable-data |
homelable | 1 Gi | attached | master-3 |
prometheus-grafana |
monitoring | 2 Gi | attached | worker-2 (Grafana pinned there, wired): 2 replicas with dataLocality: best-effort (grafana_local.sh) |
pihole-config-longhorn |
pihole | 1 Gi | detached (unused) | — |
dnsmasq-config-longhorn |
pihole | 1 Gi | detached (unused) | — |
local-home-confluence-temp |
confluence | 1 Gi | detached (unused) | — |
The three detached volumes are leftovers from half-finished migrations. They can be deleted once it is confirmed they aren't needed.
Applications without persistent storage
| Application | Volume | What is lost on restart |
|---|---|---|
| Jira | local-home and shared-home as emptyDir |
Attachments, indexes and local configuration. The issues are safe in Postgres. |
| Prometheus | no volumeClaimTemplates |
The whole metrics history |
Before moving or restarting anything with data
Rules learned the hard way (see incidentes.md):
- Never run
k3s-agent-uninstall.shork3s-uninstall.shon a node withlocal-pathPVCs without first copying/var/lib/rancher/k3s/storage/. The script deletes it without warning. - Before removing a
nodeSelectoror forcing the first restart of a pod that has been up for a long time, review itsinitContainersfor destructive commands on the same PVC:kubectl -n <ns> get deploy/<name> -o jsonpath='{.spec.template.spec.initContainers}' - Take a Longhorn snapshot of the volume right before touching it.