summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-01-30 23:01:22 +0200
committerPaul Buetow <paul@buetow.org>2026-01-30 23:01:22 +0200
commit8ec2c7fe34625a34c098d18278bd83589da7042f (patch)
treea70e48cff52e138d274673a345e5b43a1710df8a
parent153507db10ad37d7da1720975916b1af1c09ef7d (diff)
Add jellyfin deployment
Amp-Thread-ID: https://ampcode.com/threads/T-019c10b2-ea57-752e-818e-33a56d69d9fa Co-authored-by: Amp <amp@ampcode.com>
-rw-r--r--f3s/argocd-apps/services/jellyfin.yaml28
-rw-r--r--f3s/jellyfin/Justfile38
-rw-r--r--f3s/jellyfin/README.md86
-rw-r--r--f3s/jellyfin/helm-chart/Chart.yaml5
-rw-r--r--f3s/jellyfin/helm-chart/templates/.gitignore2
-rw-r--r--f3s/jellyfin/helm-chart/templates/ingress.yaml15
-rw-r--r--f3s/jellyfin/helm-chart/templates/persistent-volume.yaml28
-rw-r--r--f3s/jellyfin/values.yaml52
8 files changed, 254 insertions, 0 deletions
diff --git a/f3s/argocd-apps/services/jellyfin.yaml b/f3s/argocd-apps/services/jellyfin.yaml
new file mode 100644
index 0000000..f24974e
--- /dev/null
+++ b/f3s/argocd-apps/services/jellyfin.yaml
@@ -0,0 +1,28 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ name: jellyfin
+ namespace: cicd
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+spec:
+ project: default
+ source:
+ repoURL: http://git-server.cicd.svc.cluster.local/conf.git
+ targetRevision: master
+ path: f3s/jellyfin/helm-chart
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: services
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=false
+ retry:
+ limit: 3
+ backoff:
+ duration: 5s
+ factor: 2
+ maxDuration: 1m
diff --git a/f3s/jellyfin/Justfile b/f3s/jellyfin/Justfile
new file mode 100644
index 0000000..46848de
--- /dev/null
+++ b/f3s/jellyfin/Justfile
@@ -0,0 +1,38 @@
+NAMESPACE := "services"
+APP_NAME := "jellyfin"
+
+status:
+ @echo "=== Pods ==="
+ @kubectl get pods -n {{NAMESPACE}} | grep jellyfin
+ @echo ""
+ @echo "=== Services ==="
+ @kubectl get svc -n {{NAMESPACE}} | grep jellyfin
+ @echo ""
+ @echo "=== Ingress ==="
+ @kubectl get ingress -n {{NAMESPACE}} jellyfin-ingress
+ @echo ""
+ @echo "=== PVCs ==="
+ @kubectl get pvc -n {{NAMESPACE}} | grep jellyfin
+ @echo ""
+ @echo "=== ArgoCD Status ==="
+ @kubectl get application {{APP_NAME}} -n cicd -o jsonpath='Sync: {.status.sync.status}, Health: {.status.health.status}' 2>/dev/null && echo ""
+
+logs lines="100":
+ kubectl logs -n {{NAMESPACE}} -l app=jellyfin-server --tail={{lines}} -f
+
+port-forward port="8096":
+ @echo "Forwarding jellyfin to localhost:{{port}}"
+ kubectl port-forward -n {{NAMESPACE}} svc/jellyfin-server {{port}}:8096
+
+sync:
+ @echo "Triggering ArgoCD sync..."
+ @kubectl annotate application {{APP_NAME}} -n cicd argocd.argoproj.io/refresh=normal --overwrite
+ @sleep 2
+ @kubectl get application {{APP_NAME}} -n cicd -o jsonpath='Sync: {.status.sync.status}, Health: {.status.health.status}' && echo ""
+
+argocd-status:
+ argocd app get {{APP_NAME}} --core
+
+restart:
+ @echo "Restarting jellyfin server..."
+ kubectl rollout restart -n {{NAMESPACE}} deployment/jellyfin-server
diff --git a/f3s/jellyfin/README.md b/f3s/jellyfin/README.md
new file mode 100644
index 0000000..1cc9160
--- /dev/null
+++ b/f3s/jellyfin/README.md
@@ -0,0 +1,86 @@
+# Jellyfin Kubernetes Deployment
+
+This directory contains the Kubernetes configuration for deploying [Jellyfin](https://jellyfin.org/) - a free software media system that puts you in control of your media and data.
+
+## Architecture
+
+Jellyfin is a single-component deployment consisting of:
+- **Server**: Main media server with web interface and API
+
+## Prerequisites
+
+1. **Create storage directory on the NFS server**:
+ ```bash
+ for host in f0 f1 f2; do
+ ssh paul@$host "doas mkdir -p /data/nfs/k3svolumes/jellyfin"
+ ssh paul@$host "doas chown -R 911:911 /data/nfs/k3svolumes/jellyfin/"
+ done
+ ```
+
+## Deployment
+
+1. **Install the custom resources** (PVs, PVCs, ingress):
+ ```bash
+ just install-resources
+ ```
+
+2. **Install Jellyfin using Helm** (or ArgoCD):
+ ```bash
+ just sync
+ ```
+
+3. **Check deployment status**:
+ ```bash
+ just status
+ ```
+
+ Wait for all pods to be in `Running` state (may take a few minutes for image pulls).
+
+## Access
+
+Once deployed, Jellyfin will be available at: **https://jelly.f3s.buetow.org**
+
+Default setup instructions:
+1. Navigate to the URL above
+2. Complete the setup wizard on first access
+3. Configure libraries and preferences
+
+## Storage
+
+Persistent storage is configured with:
+- **Data**: Main configuration and metadata at `/data/nfs/k3svolumes/jellyfin`
+- **Media**: Mount your media directories from other NFS sources as needed
+
+## Maintenance
+
+### Restart Jellyfin
+```bash
+just restart
+```
+
+### View logs
+```bash
+just logs
+```
+
+### Port forward for local access
+```bash
+just port-forward
+```
+
+### Uninstall (keeps data)
+```bash
+kubectl delete application jellyfin -n cicd
+```
+
+## Troubleshooting
+
+### Check pod logs
+```bash
+kubectl logs -n services -l app=jellyfin-server --tail=100
+```
+
+### Verify persistent volumes
+```bash
+kubectl get pv,pvc -n services | grep jellyfin
+```
diff --git a/f3s/jellyfin/helm-chart/Chart.yaml b/f3s/jellyfin/helm-chart/Chart.yaml
new file mode 100644
index 0000000..bd2ca92
--- /dev/null
+++ b/f3s/jellyfin/helm-chart/Chart.yaml
@@ -0,0 +1,5 @@
+apiVersion: v2
+name: jellyfin-resources
+description: Custom resources for Jellyfin deployment (PVs, PVCs, Ingress)
+version: 0.1.0
+appVersion: "latest"
diff --git a/f3s/jellyfin/helm-chart/templates/.gitignore b/f3s/jellyfin/helm-chart/templates/.gitignore
new file mode 100644
index 0000000..8eeb559
--- /dev/null
+++ b/f3s/jellyfin/helm-chart/templates/.gitignore
@@ -0,0 +1,2 @@
+# Secrets should not be committed
+*-secret.yaml
diff --git a/f3s/jellyfin/helm-chart/templates/ingress.yaml b/f3s/jellyfin/helm-chart/templates/ingress.yaml
new file mode 100644
index 0000000..de4b028
--- /dev/null
+++ b/f3s/jellyfin/helm-chart/templates/ingress.yaml
@@ -0,0 +1,15 @@
+# Jellyfin Traefik Ingress
+apiVersion: traefik.io/v1alpha1
+kind: IngressRoute
+metadata:
+ name: jellyfin-ingress
+ namespace: services
+spec:
+ entryPoints:
+ - web
+ routes:
+ - match: Host(`jelly.f3s.buetow.org`)
+ kind: Rule
+ services:
+ - name: jellyfin-server
+ port: 8096
diff --git a/f3s/jellyfin/helm-chart/templates/persistent-volume.yaml b/f3s/jellyfin/helm-chart/templates/persistent-volume.yaml
new file mode 100644
index 0000000..bf16da6
--- /dev/null
+++ b/f3s/jellyfin/helm-chart/templates/persistent-volume.yaml
@@ -0,0 +1,28 @@
+# Jellyfin PersistentVolume - Configuration and metadata storage
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: jellyfin-pv
+spec:
+ capacity:
+ storage: 50Gi
+ volumeMode: Filesystem
+ accessModes:
+ - ReadWriteOnce
+ persistentVolumeReclaimPolicy: Retain
+ hostPath:
+ path: /data/nfs/k3svolumes/jellyfin
+ type: Directory
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: jellyfin-pvc
+ namespace: services
+spec:
+ storageClassName: ""
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 50Gi
diff --git a/f3s/jellyfin/values.yaml b/f3s/jellyfin/values.yaml
new file mode 100644
index 0000000..7e083c9
--- /dev/null
+++ b/f3s/jellyfin/values.yaml
@@ -0,0 +1,52 @@
+# Jellyfin Helm Chart Configuration
+# Deploy to services namespace with persistent storage
+
+# Image configuration
+image:
+ repository: jellyfin/jellyfin
+ tag: latest
+ pullPolicy: IfNotPresent
+
+# Persistence
+persistence:
+ config:
+ enabled: true
+ type: pvc
+ existingClaim: jellyfin-pvc
+ mountPath: /config
+ size: 50Gi
+
+# Service configuration
+service:
+ type: ClusterIP
+ port: 8096
+
+# Ingress configuration
+ingress:
+ enabled: true
+ ingressClassName: traefik
+ annotations:
+ traefik.ingress.kubernetes.io/router.entrypoints: web
+ hosts:
+ - host: jelly.f3s.buetow.org
+ paths:
+ - path: /
+ pathType: Prefix
+
+# Resources
+resources:
+ requests:
+ cpu: 100m
+ memory: 256Mi
+ limits:
+ cpu: 2000m
+ memory: 2Gi
+
+# Node selector (if needed)
+nodeSelector: {}
+
+# Tolerations (if needed)
+tolerations: []
+
+# Affinity rules (if needed)
+affinity: {}