# services/jellyfin/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: jellyfin namespace: jellyfin labels: app: jellyfin spec: replicas: 1 strategy: type: RollingUpdate rollingUpdate: maxSurge: 0 maxUnavailable: 1 selector: matchLabels: app: jellyfin template: metadata: labels: app: jellyfin spec: nodeSelector: jellyfin: "true" securityContext: runAsUser: 1000 fsGroup: 65532 fsGroupChangePolicy: OnRootMismatch runAsGroup: 65532 initContainers: - name: install-oidc-plugin image: alpine:3.20 securityContext: runAsUser: 0 env: - name: OIDC_PLUGIN_VERSION value: "1.0.2.0" - name: OIDC_PLUGIN_URL value: "https://raw.githubusercontent.com/lolerskatez/JellyfinOIDCPlugin/master/OIDC_Authentication_1.0.2.0.zip" - name: OIDC_ISSUER value: "https://sso.bstein.dev/realms/atlas" - name: OIDC_REDIRECT_URI value: "https://stream.bstein.dev/oauth2/callback" - name: OIDC_LOGOUT_URI value: "https://sso.bstein.dev/realms/atlas/protocol/openid-connect/logout?redirect_uri=https://stream.bstein.dev/" - name: OIDC_SCOPES value: "openid,profile,email,groups" - name: OIDC_ROLE_CLAIM value: "groups" - name: OIDC_CLIENT_ID valueFrom: secretKeyRef: name: jellyfin-oidc key: client-id - name: OIDC_CLIENT_SECRET valueFrom: secretKeyRef: name: jellyfin-oidc key: client-secret volumeMounts: - name: config mountPath: /config command: ["/bin/sh", "-c"] args: - | set -euo pipefail if [ -z "${OIDC_CLIENT_ID:-}" ] || [ -z "${OIDC_CLIENT_SECRET:-}" ]; then echo "OIDC_CLIENT_ID or OIDC_CLIENT_SECRET missing; create secret jellyfin-oidc" >&2 exit 1 fi rm -rf "/config/plugins/LDAP Authentication_20.0.0.0" apk add --no-cache wget unzip plugin_dir="/config/plugins/OIDC Authentication_${OIDC_PLUGIN_VERSION}" config_dir="/config/plugins/configurations" tmp_zip="$(mktemp)" echo "Downloading OIDC plugin ${OIDC_PLUGIN_VERSION} from ${OIDC_PLUGIN_URL}" wget -O "${tmp_zip}" "${OIDC_PLUGIN_URL}" rm -rf "${plugin_dir}" mkdir -p "${plugin_dir}" "${config_dir}" unzip -o "${tmp_zip}" -d "${plugin_dir}" rm -f "${tmp_zip}" cat >"${plugin_dir}/meta.json" <<'EOF' { "category": "Authentication", "changelog": "OIDC SSO authentication plugin; auto user creation and role mapping", "description": "OpenID Connect (OIDC) authentication provider for Jellyfin with SSO support.", "guid": "a1b2c3d4-e5f6-47a8-b9c0-d1e2f3a4b5c6", "name": "OIDC Authentication", "overview": "Enable Single Sign-On (SSO) for Jellyfin using an OpenID Connect provider.", "owner": "lolerskatez", "targetAbi": "10.11.3.0", "timestamp": "2025-12-17T04:00:00Z", "version": "1.0.2.0", "status": "Active", "autoUpdate": false, "imagePath": "", "assemblies": [] } EOF scope_lines="" for s in $(echo "${OIDC_SCOPES}" | tr ',' ' '); do trimmed="$(echo "${s}" | xargs)" [ -z "${trimmed}" ] && continue scope_lines="${scope_lines} ${trimmed}\n" done cat >"${config_dir}/OIDC Authentication.xml" < ${OIDC_ISSUER} ${OIDC_CLIENT_ID} ${OIDC_CLIENT_SECRET} $(printf "%b" "${scope_lines}") ${OIDC_ROLE_CLAIM} ${OIDC_REDIRECT_URI} ${OIDC_LOGOUT_URI} true false EOF chown -R 1000:65532 "${plugin_dir}" "${config_dir}/OIDC Authentication.xml" runtimeClassName: nvidia containers: - name: jellyfin image: docker.io/jellyfin/jellyfin:10.11.5 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 8096 env: - name: NVIDIA_DRIVER_CAPABILITIES value: "compute,video,utility" - name: JELLYFIN_PublishedServerUrl value: "https://stream.bstein.dev" - name: PUID value: "1000" - name: PGID value: "65532" - name: UMASK value: "002" resources: limits: nvidia.com/gpu: 1 # cpu: "4" # memory: 8Gi requests: nvidia.com/gpu: 1 cpu: "500m" memory: 1Gi volumeMounts: - name: config mountPath: /config - name: cache mountPath: /cache - name: media mountPath: /media securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: false volumes: - name: config persistentVolumeClaim: claimName: jellyfin-config-astreae - name: cache persistentVolumeClaim: claimName: jellyfin-cache-astreae - name: media persistentVolumeClaim: claimName: jellyfin-media-asteria-new