2025-08-25 12:35:36 -05:00
# services/jellyfin/deployment.yaml
apiVersion : apps/v1
kind : Deployment
metadata :
name : jellyfin
namespace : jellyfin
labels :
app : jellyfin
2026-05-19 12:48:40 -03:00
atlas.bstein.dev/workload-profile : heavy
2025-08-25 12:35:36 -05:00
spec :
2025-10-07 23:28:40 -05:00
replicas : 1
2025-09-02 19:46:21 -05:00
strategy :
2025-09-02 20:12:29 -05:00
type : RollingUpdate
rollingUpdate :
maxSurge : 0
maxUnavailable : 1
2025-08-25 12:35:36 -05:00
selector :
matchLabels :
app : jellyfin
template :
metadata :
labels :
app : jellyfin
2026-05-19 12:48:40 -03:00
atlas.bstein.dev/workload-profile : heavy
2026-01-14 23:15:19 -03:00
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 : |
2026-01-14 23:34:39 -03:00
{{- with secret "kv/data/atlas/pegasus/jellyfin-ldap-config" -}}{{ index .Data.data "ldap-config.xml" }}{{- end -}}
2025-08-25 12:35:36 -05:00
spec :
2026-01-14 23:15:19 -03:00
serviceAccountName : pegasus-vault-sync
2025-12-24 15:26:02 -03:00
# Clean up any lingering OIDC artifacts and strip the injected script tag
2025-12-19 21:13:31 -03:00
initContainers :
2025-12-24 15:26:02 -03:00
- name : strip-oidc
2026-08-22 22:10:46 -03:00
image : docker.io/jellyfin/jellyfin:10.11.5@sha256:6d819e9ab067efcf712993b23455cc100ee5585919bb297ea5a109ac00cb626e
2025-12-20 13:32:36 -03:00
securityContext :
runAsUser : 0
2025-12-24 15:26:02 -03:00
runAsGroup : 0
command :
- /bin/sh
- -c
2025-12-20 13:32:36 -03:00
- |
2025-12-24 15:26:02 -03:00
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
2025-12-19 21:30:04 -03:00
volumeMounts :
2025-12-24 15:26:02 -03:00
- name : web-root
mountPath : /web-root
2025-12-19 21:30:04 -03:00
- name : config
mountPath : /config
2025-12-24 17:25:07 -03:00
# 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
2026-08-22 22:10:46 -03:00
image : docker.io/library/alpine:3.20@sha256:765942a4039992336de8dd5db680586e1a206607dd06170ff0a37267a9e01958
2025-12-24 17:25:07 -03:00
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
2026-01-01 12:22:22 -03:00
sqlite3 "$db" "UPDATE Users SET AuthenticationProviderId='Jellyfin.Plugin.LDAP_Auth.LdapAuthenticationProviderPlugin', Password=NULL, EnableLocalPassword=0 WHERE AuthenticationProviderId!='Jellyfin.Plugin.LDAP_Auth.LdapAuthenticationProviderPlugin';"
2025-12-24 17:25:07 -03:00
else
echo "db not found at $db, skipping"
fi
volumeMounts :
- name : config
mountPath : /config
2026-08-22 22:10:46 -03:00
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
2025-12-24 15:26:02 -03:00
securityContext :
runAsUser : 1000
fsGroup : 65532
fsGroupChangePolicy : OnRootMismatch
runAsGroup : 65532
2025-08-25 12:35:36 -05:00
containers :
- name : jellyfin
2026-08-22 22:10:46 -03:00
image : docker.io/jellyfin/jellyfin:10.11.5@sha256:6d819e9ab067efcf712993b23455cc100ee5585919bb297ea5a109ac00cb626e
2025-08-25 12:35:36 -05:00
imagePullPolicy : IfNotPresent
2026-01-14 23:15:19 -03:00
command :
- /entrypoint.sh
args :
- /jellyfin/jellyfin
2025-08-25 12:35:36 -05:00
ports :
- name : http
containerPort : 8096
2026-08-22 22:10:46 -03:00
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
2025-08-25 12:35:36 -05:00
env :
- name : JELLYFIN_PublishedServerUrl
value : "https://stream.bstein.dev"
2025-09-18 08:52:58 -05:00
- name : PUID
value : "1000"
- name : PGID
value : "65532"
- name : UMASK
value : "002"
2026-08-22 22:10:46 -03:00
- name : NVIDIA_DRIVER_CAPABILITIES
value : compute,video,utility
2026-01-14 23:15:19 -03:00
- name : VAULT_COPY_FILES
value : /vault/secrets/ldap-config.xml:/config/plugins/configurations/LDAP-Auth.xml
2025-08-25 12:35:36 -05:00
resources :
requests :
2026-08-22 22:10:46 -03:00
cpu : "2"
memory : 2Gi
ephemeral-storage : 8Gi
nvidia.com/gpu.shared : "1"
2026-05-19 12:48:40 -03:00
limits :
2026-08-22 22:10:46 -03:00
cpu : "8"
memory : 8Gi
ephemeral-storage : 80Gi
nvidia.com/gpu.shared : "1"
2025-08-25 12:35:36 -05:00
volumeMounts :
2026-01-14 23:15:19 -03:00
- name : jellyfin-vault-entrypoint
mountPath : /entrypoint.sh
subPath : vault-entrypoint.sh
2025-08-25 12:35:36 -05:00
- name : config
mountPath : /config
- name : cache
mountPath : /cache
- name : media
mountPath : /media
2025-12-24 15:26:02 -03:00
- 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
2025-08-25 12:35:36 -05:00
securityContext :
2025-12-20 13:32:36 -03:00
runAsUser : 0
runAsGroup : 0
2025-08-25 12:35:36 -05:00
allowPrivilegeEscalation : false
readOnlyRootFilesystem : false
volumes :
2026-01-14 23:15:19 -03:00
- name : jellyfin-vault-entrypoint
configMap :
name : jellyfin-vault-entrypoint
defaultMode : 493
2025-12-24 15:26:02 -03:00
- name : web-root
emptyDir : {}
2025-08-25 12:35:36 -05:00
- name : config
persistentVolumeClaim :
2025-09-02 19:46:21 -05:00
claimName : jellyfin-config-astreae
2025-08-25 12:35:36 -05:00
- name : cache
2026-08-22 22:10:46 -03:00
emptyDir :
sizeLimit : 64Gi
2025-08-25 12:35:36 -05:00
- name : media
persistentVolumeClaim :
2025-10-07 23:26:27 -05:00
claimName : jellyfin-media-asteria-new