Add Navidrome music streaming server (#79)

## Summary
- Deploy Navidrome music streaming server to k8s
- NFS mount for music library from sifaka:/volume1/music (read-only)
- Local PVC for SQLite database and config (10Gi)
- Tailscale ingress for dj.tail8d86e.ts.net
- Caddy reverse proxy for dj.ops.eblu.me
- Homepage annotations for dashboard discovery in Media group

## Deployment and Testing
- [ ] Sync `apps` application to pick up new Application definition
- [ ] Set navidrome app to feature branch and sync
- [ ] Verify NFS mount with `kubectl exec`
- [ ] Provision Caddy for dj.ops.eblu.me
- [ ] Access https://dj.ops.eblu.me and create initial admin user
- [ ] Verify Homepage shows DJ in Media group
- [ ] Reset to main and resync after merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/79
This commit is contained in:
Erich Blume 2026-01-31 20:19:31 -08:00
commit ade21cc49e
9 changed files with 183 additions and 0 deletions

View file

@ -0,0 +1,18 @@
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: navidrome
namespace: argocd
spec:
project: default
source:
repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/blumeops.git
targetRevision: main
path: argocd/manifests/navidrome
destination:
server: https://kubernetes.default.svc
namespace: navidrome
syncPolicy:
syncOptions:
- CreateNamespace=true

View file

@ -0,0 +1,63 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: navidrome
namespace: navidrome
spec:
replicas: 1
selector:
matchLabels:
app: navidrome
template:
metadata:
labels:
app: navidrome
spec:
containers:
- name: navidrome
image: deluan/navidrome:latest
ports:
- containerPort: 4533
name: http
env:
- name: ND_SCANSCHEDULE
value: "1h"
- name: ND_LOGLEVEL
value: "info"
- name: ND_MUSICFOLDER
value: "/music"
- name: ND_DATAFOLDER
value: "/data"
volumeMounts:
- name: music
mountPath: /music
readOnly: true
- name: data
mountPath: /data
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /ping
port: 4533
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /ping
port: 4533
initialDelaySeconds: 5
periodSeconds: 10
volumes:
- name: music
persistentVolumeClaim:
claimName: navidrome-music
- name: data
persistentVolumeClaim:
claimName: navidrome-data

View file

@ -0,0 +1,25 @@
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: navidrome-tailscale
namespace: navidrome
annotations:
tailscale.com/proxy-class: "default"
gethomepage.dev/enabled: "true"
gethomepage.dev/name: "DJ"
gethomepage.dev/group: "Media"
gethomepage.dev/icon: "navidrome.png"
gethomepage.dev/description: "Music streaming server"
gethomepage.dev/href: "https://dj.ops.eblu.me"
gethomepage.dev/pod-selector: "app=navidrome"
spec:
ingressClassName: tailscale
defaultBackend:
service:
name: navidrome
port:
number: 4533
tls:
- hosts:
- dj

View file

@ -0,0 +1,11 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: navidrome
resources:
- pv-nfs.yaml
- pvc-music.yaml
- pvc-data.yaml
- deployment.yaml
- service.yaml
- ingress-tailscale.yaml

View file

@ -0,0 +1,22 @@
# NFS PersistentVolume for Navidrome music library
# Requires: NFS share on sifaka at /volume1/music with NFS permissions for indri
#
# To create on Synology:
# 1. Control Panel > Shared Folder > Create
# 2. Name: music, Location: Volume 1
# 3. Control Panel > File Services > NFS > NFS Rules
# 4. Add rule for "music" share: Hostname=indri, Privilege=Read-Only, Squash=No mapping
apiVersion: v1
kind: PersistentVolume
metadata:
name: navidrome-music-nfs-pv
spec:
capacity:
storage: 1Ti
accessModes:
- ReadOnlyMany
persistentVolumeReclaimPolicy: Retain
storageClassName: ""
nfs:
server: sifaka
path: /volume1/music

View file

@ -0,0 +1,13 @@
# PersistentVolumeClaim for Navidrome data (SQLite database, config, cache)
# Uses minikube's default storage class for local provisioning
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: navidrome-data
namespace: navidrome
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi

View file

@ -0,0 +1,15 @@
# PersistentVolumeClaim for Navidrome music library
# Binds to the NFS PV for sifaka:/volume1/music
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: navidrome-music
namespace: navidrome
spec:
accessModes:
- ReadOnlyMany
storageClassName: ""
volumeName: navidrome-music-nfs-pv
resources:
requests:
storage: 1Ti

View file

@ -0,0 +1,13 @@
---
apiVersion: v1
kind: Service
metadata:
name: navidrome
namespace: navidrome
spec:
selector:
app: navidrome
ports:
- name: http
port: 4533
targetPort: 4533