From cd837ea69dc4afe69d48c0f33b3011a8023996d1 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sun, 10 May 2026 10:57:44 +0300 Subject: 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 --- f3s/navidrome/helm-chart/templates/deployment.yaml | 8 ++++- .../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: -- cgit v1.2.3