diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-10 10:57:44 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-10 10:57:44 +0300 |
| commit | cd837ea69dc4afe69d48c0f33b3011a8023996d1 (patch) | |
| tree | e1a5a395af36691021dd18defdd3d0061d19b207 | |
| parent | 19f8e01ac35aeca761e08a74c087d62b78c8c021 (diff) | |
navidrome: move /data PVC from NFS to local-path on r1
SQLite over NFS causes two problems: file-lock races on rolling
restarts (fixed with Recreate strategy but underlying fragility
remains), and 19s image-cache init at startup due to stunnel TLS
latency on every cache read.
Replace navidrome-data-pv/pvc (static hostPath over NFS at
/data/nfs/k3svolumes/navidrome/data) with a dynamic local-path PVC
provisioned on r1 (/var/lib/rancher/k3s/storage). Pin the deployment
to r1 via nodeSelector so the local PV is always reachable.
Existing DB and cache migrated: navidrome.db (23 MB), image/background/
plugin caches (~118 MB) copied via a migration pod before first start.
Result: startupTime=41ms (was ~20s), Image cache init=29ms (was ~19s).
Music PVC stays on NFS (200 GB library, unchanged).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| -rw-r--r-- | f3s/navidrome/helm-chart/templates/deployment.yaml | 8 | ||||
| -rw-r--r-- | f3s/navidrome/helm-chart/templates/persistent-volume.yaml | 34 |
2 files changed, 25 insertions, 17 deletions
diff --git a/f3s/navidrome/helm-chart/templates/deployment.yaml b/f3s/navidrome/helm-chart/templates/deployment.yaml index 5a3862e..d85bb47 100644 --- a/f3s/navidrome/helm-chart/templates/deployment.yaml +++ b/f3s/navidrome/helm-chart/templates/deployment.yaml @@ -18,6 +18,12 @@ spec: labels: app: navidrome spec: + # Pin to r1 so the local-path PVC (which lives on r1's disk at + # /var/lib/rancher/k3s/storage) is always reachable. Without this, if + # the pod reschedules to a different node it would not find the data + # volume and Navidrome would start with an empty DB. + nodeSelector: + kubernetes.io/hostname: r1.lan.buetow.org containers: - name: navidrome image: deluan/navidrome:latest @@ -34,7 +40,7 @@ spec: httpGet: path: /ping port: 4533 - # Allow up to 5 min for cold start (NFS cache warm-up, scan, etc.) + # Allow up to 5 min for cold start (DB open, first scan, etc.) initialDelaySeconds: 15 periodSeconds: 5 timeoutSeconds: 3 diff --git a/f3s/navidrome/helm-chart/templates/persistent-volume.yaml b/f3s/navidrome/helm-chart/templates/persistent-volume.yaml index 960bee3..3ca2867 100644 --- a/f3s/navidrome/helm-chart/templates/persistent-volume.yaml +++ b/f3s/navidrome/helm-chart/templates/persistent-volume.yaml @@ -1,31 +1,33 @@ -apiVersion: v1 -kind: PersistentVolume -metadata: - name: navidrome-data-pv -spec: - capacity: - storage: 10Gi - volumeMode: Filesystem - accessModes: - - ReadWriteOnce - persistentVolumeReclaimPolicy: Retain - hostPath: - path: /data/nfs/k3svolumes/navidrome/data - type: Directory ---- +# navidrome-data: local-path PVC (dynamic provisioning). +# The SQLite DB, image cache, and artwork cache must NOT live on NFS because: +# 1. SQLite file-lock semantics are fragile over NFS: under concurrent +# access (e.g. rolling restart) the new pod blocks on fcntl() until +# the old pod fully releases its locks. +# 2. Every image/background cache read traverses the stunnel TLS tunnel, +# adding latency to every UI thumbnail and a 19 s "Image cache" init +# at startup. +# The local-path storageClass provisions a directory on the node's own disk +# (/var/lib/rancher/k3s/storage), eliminating both problems. The deployment +# pins the pod to r1 via nodeSelector so the local PV is always reachable. +# Trade-off: if r1 is down and the pod reschedules, it starts with a fresh +# DB (loses play counts / scrobble queue) — acceptable for a home server. apiVersion: v1 kind: PersistentVolumeClaim metadata: name: navidrome-data-pvc namespace: services spec: - storageClassName: "" + # local-path is the k3s default dynamic provisioner; WaitForFirstConsumer + # means the PV is created on the node where the pod is first scheduled. + storageClassName: local-path accessModes: - ReadWriteOnce resources: requests: storage: 10Gi --- +# navidrome-music: keep on NFS — 200 GB library shared across nodes. +# This is a static PV backed by hostPath at the NFS mount point. apiVersion: v1 kind: PersistentVolume metadata: |
