# services/jellyfin/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: jellyfin namespace: jellyfin labels: app: jellyfin atlas.bstein.dev/workload-profile: heavy spec: replicas: 1 strategy: type: RollingUpdate rollingUpdate: maxSurge: 0 maxUnavailable: 1 selector: matchLabels: app: jellyfin template: metadata: labels: app: jellyfin atlas.bstein.dev/workload-profile: heavy annotations: vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: "pegasus" vault.hashicorp.com/agent-inject-secret-ldap-config.xml: "kv/data/atlas/pegasus/jellyfin-ldap-config" vault.hashicorp.com/agent-inject-template-ldap-config.xml: | {{- with secret "kv/data/atlas/pegasus/jellyfin-ldap-config" -}}{{ index .Data.data "ldap-config.xml" }}{{- end -}} spec: serviceAccountName: pegasus-vault-sync # Clean up any lingering OIDC artifacts and strip the injected script tag initContainers: - name: strip-oidc image: docker.io/jellyfin/jellyfin:10.11.5@sha256:6d819e9ab067efcf712993b23455cc100ee5585919bb297ea5a109ac00cb626e securityContext: runAsUser: 0 runAsGroup: 0 command: - /bin/sh - -c - | set -euxo pipefail cp -a /jellyfin/jellyfin-web/. /web-root # remove injected OIDC script tags everywhere just in case for f in $(find /web-root -type f -name 'index.html'); do sed -i '/oidc\/inject/d' "$f" printf '%s\n' "$f" done # clean any lingering OIDC plugin artifacts on the config volume rm -rf "/config/plugins/OIDC Authentication_"* /config/plugins/configurations/JellyfinOIDCPlugin.v2.xml || true volumeMounts: - name: web-root mountPath: /web-root - name: config mountPath: /config # Force all users to authenticate via the LDAP plugin provider by updating the DB on start. # This keeps Flux enforcement for auth provider drift (e.g., after UI edits). - name: set-ldap-auth-provider image: docker.io/library/alpine:3.20@sha256:765942a4039992336de8dd5db680586e1a206607dd06170ff0a37267a9e01958 securityContext: runAsUser: 0 runAsGroup: 0 command: - /bin/sh - -c - | set -euxo pipefail apk add --no-cache sqlite db="/config/data/jellyfin.db" if [ -f "$db" ]; then sqlite3 "$db" "UPDATE Users SET AuthenticationProviderId='Jellyfin.Plugin.LDAP_Auth.LdapAuthenticationProviderPlugin', Password=NULL, EnableLocalPassword=0 WHERE AuthenticationProviderId!='Jellyfin.Plugin.LDAP_Auth.LdapAuthenticationProviderPlugin';" else echo "db not found at $db, skipping" fi volumeMounts: - name: config mountPath: /config nodeSelector: kubernetes.io/hostname: titan-22 priorityClassName: media-core runtimeClassName: nvidia terminationGracePeriodSeconds: 60 tolerations: - key: atlas.bstein.dev/media-primary operator: Equal value: "true" effect: PreferNoSchedule securityContext: runAsUser: 1000 fsGroup: 65532 fsGroupChangePolicy: OnRootMismatch runAsGroup: 65532 containers: - name: jellyfin image: docker.io/jellyfin/jellyfin:10.11.5@sha256:6d819e9ab067efcf712993b23455cc100ee5585919bb297ea5a109ac00cb626e imagePullPolicy: IfNotPresent command: - /entrypoint.sh args: - /jellyfin/jellyfin ports: - name: http containerPort: 8096 startupProbe: httpGet: path: /health port: http periodSeconds: 5 timeoutSeconds: 2 failureThreshold: 60 readinessProbe: httpGet: path: /health port: http periodSeconds: 5 timeoutSeconds: 2 failureThreshold: 3 livenessProbe: httpGet: path: /health port: http periodSeconds: 15 timeoutSeconds: 2 failureThreshold: 4 env: - name: JELLYFIN_PublishedServerUrl value: "https://stream.bstein.dev" - name: PUID value: "1000" - name: PGID value: "65532" - name: UMASK value: "002" - name: NVIDIA_DRIVER_CAPABILITIES value: compute,video,utility - name: VAULT_COPY_FILES value: /vault/secrets/ldap-config.xml:/config/plugins/configurations/LDAP-Auth.xml resources: requests: cpu: "2" memory: 2Gi ephemeral-storage: 8Gi nvidia.com/gpu.shared: "1" limits: cpu: "8" memory: 8Gi ephemeral-storage: 80Gi nvidia.com/gpu.shared: "1" volumeMounts: - name: jellyfin-vault-entrypoint mountPath: /entrypoint.sh subPath: vault-entrypoint.sh - name: config mountPath: /config - name: cache mountPath: /cache - name: media mountPath: /media - name: web-root mountPath: /jellyfin/jellyfin-web lifecycle: postStart: exec: command: - /bin/sh - -c - | set -eux for f in $(find /jellyfin/jellyfin-web -type f -name 'index.html'); do sed -i '/oidc\/inject/d' "$f" || true done securityContext: runAsUser: 0 runAsGroup: 0 allowPrivilegeEscalation: false readOnlyRootFilesystem: false volumes: - name: jellyfin-vault-entrypoint configMap: name: jellyfin-vault-entrypoint defaultMode: 493 - name: web-root emptyDir: {} - name: config persistentVolumeClaim: claimName: jellyfin-config-astreae - name: cache emptyDir: sizeLimit: 64Gi - name: media persistentVolumeClaim: claimName: jellyfin-media-asteria-new