Skip to main content

Kubernetes Deployment

This guide covers deploying Jellyfin on Kubernetes using the official Helm chart.

Prerequisites​

  • Kubernetes cluster (v1.19+)
  • Helm 3.x installed
  • kubectl configured for your cluster
  • Sufficient storage for media and configuration
  • Ingress controller (e.g. traefik) for external access (required for this tutorial, see official docs for alternatives)

Installation​

1. Add Helm Repository​

helm repo add jellyfin https://jellyfin.github.io/jellyfin-helm
helm repo update

2. Custom Installation​

For complete installation instructions and configuration options, see the official Jellyfin Helm chart repository.

Create a values.yaml file for customization:

# values.yaml
replicaCount: 1

image:
pullPolicy: IfNotPresent

persistence:
config:
enabled: true
size: 5Gi
storageClass: ''
media:
enabled: true
size: 100Gi
storageClass: ''

ingress:
enabled: true
className: 'traefik'
hosts:
- host: jellyfin.example.com
paths:
- path: /
pathType: Prefix

resources:
limits:
cpu: 2000m
memory: 4Gi
requests:
cpu: 500m
memory: 1Gi

nodeSelector: {}
tolerations: []
affinity: {}

Install with custom values:

helm install jellyfin jellyfin/jellyfin -f values.yaml

Configuration Options​

Service Types​

This guide covers ClusterIP service type (default) for internal access only, with external access via ingress controller. Alternatives include LoadBalancer and NodePort services.

Persistence​

Using Existing Persistent Volume Claims​

persistence:
config:
enabled: true
existingClaim: 'jellyfin-config-pvc'
media:
enabled: true
existingClaim: 'jellyfin-media-pvc'

Creating New PVCs via Helm​

persistence:
config:
enabled: true
size: 5Gi
storageClass: 'fast-ssd'
media:
enabled: true
size: 100Gi
storageClass: 'slow-hdd'

Ingress​

Basic Ingress Configuration​

ingress:
enabled: true
className: 'traefik'
hosts:
- host: jellyfin.example.com
paths:
- path: /
pathType: Prefix

Advanced Ingress with TLS​

ingress:
enabled: true
className: 'traefik'
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.middlewares: default-jellyfin-buffering@kubernetescrd
hosts:
- host: jellyfin.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: jellyfin-tls
hosts:
- jellyfin.example.com

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: jellyfin-buffering
namespace: default
spec:
buffering:
maxRequestBodyBytes: 0

Accessing Jellyfin​

Port Forwarding (Development)​

kubectl port-forward svc/jellyfin 8096:8096

Access at: http://localhost:8096

External Access​

Once ingress is configured, access Jellyfin at your configured domain (e.g., https://jellyfin.example.com).

Monitoring​

Health Checks​

The chart includes readiness and liveness probes:

livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 30
periodSeconds: 10

readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 5

Metrics​

Enable Prometheus metrics if available:

metrics:
enabled: true
serviceMonitor:
enabled: true

Troubleshooting​

Common Issues​

  1. Permission Denied: Ensure proper security context for media access
  2. Storage Issues: Verify persistent volume claims are bound
  3. Network Access: Check service type and ingress configuration

Debug Commands​

# Check pod status
kubectl get pods -l app.kubernetes.io/name=jellyfin

# View logs
kubectl logs -f deployment/jellyfin

# Check service
kubectl get svc jellyfin

# Describe pod for events
kubectl describe pod -l app.kubernetes.io/name=jellyfin

Upgrading​

# Update repository
helm repo update

# Upgrade installation
helm upgrade jellyfin jellyfin/jellyfin

# Check upgrade status
helm status jellyfin

Uninstalling​

# Remove Helm release
helm uninstall jellyfin

# Clean up persistent volumes (if needed)
kubectl delete pvc -l app.kubernetes.io/name=jellyfin

Advanced Configuration​

Hardware Acceleration​

For GPU acceleration, add device access and security context:

securityContext:
privileged: true

resources:
limits:
gpu.intel.com/i915: 1
# or nvidia.com/gpu: 1

volumes:
- name: dri
hostPath:
path: /dev/dri

volumeMounts:
- name: dri
mountPath: /dev/dri

Multiple Media Sources​

Mount multiple media sources using additional volumes:

volumes:
- name: movies
persistentVolumeClaim:
claimName: movies-pvc
- name: tv
persistentVolumeClaim:
claimName: tv-pvc

volumeMounts:
- name: movies
mountPath: /movies
- name: tv
mountPath: /tv

Custom Environment Variables​

extraEnvVars:
- name: JELLYFIN_PublishedServerUrl
value: 'https://jellyfin.example.com'
- name: JELLYFIN_CACHE_DIR
value: '/cache'

For more configuration options, see the Jellyfin Helm chart documentation.