Files
jellyfin-deployment/README.md
T
feedc0de e6fe3ed57e
Validate, publish and promote Jellyfin chart / publish (push) Successful in 2s
Validate, publish and promote Jellyfin chart / validate (push) Successful in 1s
Publish Jellyfin chart and replace direct Kubernetes CD
2026-10-23 09:49:00 +02:00

3.6 KiB

Jellyfin on Kubernetes

This project runs the existing Jellyfin server as one high-performance Pod on arschrock in its dedicated jellyfin namespace. It is intentionally not highly available and cannot fail over to an ODROID. CPU and memory have scheduling requests but no limits.

The 500 TB media tree remains on the host and is mounted read-only at its existing /komposthaufen/multimedia path. The Pod requires the existing Videos directory and verifies that the path is backed by bcachefs before the server starts. The Deployment also requires the explicit media.brunner.ninja/multimedia-ready=true node label. The shared ../media-storage-offline.sh helper removes it and stops the media Pods before unmounting; ../media-storage-online.sh validates the mount before restoring the label.

The retained 80 GiB jellyfin-config RBD PVC contains the migrated Arch data, configuration, metadata, preview images, databases, and logs. Cache and transcode activity use node-local ephemeral storage. The official Jellyfin image is pinned to version 12.2. Before this major-version migration, the complete PVC was backed up cold to the bcachefs-backed /komposthaufen/backups/jellyfin directory on arschrock.

One-time migration

migrate.sh stops the Arch service, confirms no Jellyfin process remains, checks every source SQLite database, creates the PVC, and starts a one-shot copy Job:

./migrate.sh
kubectl -n jellyfin logs -f job/jellyfin-archlinux-migration
kubectl -n jellyfin wait --for=condition=complete \
  job/jellyfin-archlinux-migration --timeout=12h

The Job resumes an interrupted copy using rsync, checks all copied files with checksums, and then compares regular-file counts and byte totals before writing its completion marker. Copy I/O is deliberately duty-cycle throttled so the migration cannot monopolize bcachefs and Ceph. Do not delete the Arch source trees until the Kubernetes server has been verified and a separate backup exists.

The historical migration scripts remain for recovery; routine deployment is owned by Argo CD. Jellyfin remains available at https://jellyfin.brunner.ninja and directly on 192.168.0.2:8096.

Monitoring

The init container enables Jellyfin's native Prometheus endpoint. The ServiceMonitor scrapes it internally, while the higher-priority Traefik route restricts public access to /metrics. Alerts cover scrape availability, restart loops, and PVC capacity. Existing node-exporter, Netdata, SMART, and bcachefs monitoring remain in use.

Helm and GitOps

This repository owns the Jellyfin chart: Deployment, Service, media guard, ingress option, metrics middleware, and monitoring. The chart preserves the existing Deployment selector used by media-storage-offline.sh and media-storage-online.sh. The homelab's node pin, guarded hostPath, existing PVC, public host and resource requests are selected in the GitOps values.

helm repo add brunner.ninja https://brunner.ninja/charts
helm repo update brunner.ninja
helm upgrade --install jellyfin brunner.ninja/jellyfin --namespace jellyfin --create-namespace

To install this checkout manually, run ./install.sh -f my-values.yaml with the target namespace and media mount configured. Main-branch CI validates, publishes the chart using the upstream application Git tag plus git describe, then promotes its exact version to GitOps. CI needs PACKAGE_USERNAME, PACKAGE_TOKEN, and GITOPS_TOKEN, but no kubeconfig. The Jellyfin image is the official upstream image and is selected by Chart.yaml.appVersion.