/jellyfin-operator

Primary LanguagePythonMIT LicenseMIT

jellyfin-operator

Build Status

This operator deploys the jellyfin media server into Kubernetes or OpenShift.

Deploying the Operator

To deploy it, ensure your kubeconfig is properly set up (ie, that you can use kubectl or oc to connect to it), ensure you have cluster-admin permissions (you will need this to create CustomResourceDefinitions), install ansible and the openshift python client, and run

ansible-playbook deploy.yml

If you'd rather deploy it by hand, you can instead run:

kubectl apply -f deploy/crds/apps_v1alpha1_jellyfin_crd.yaml
kubectl apply -f deploy/role.yaml
kubectl apply -f deploy/role_binding.yaml
kubectl apply -f deploy/service_account.yaml
kubectl apply -f deploy/operator.yaml

Deploying the Jellyfin server

Once this is done, your operator will be running. In order to deploy an instance of jellyfin into your cluster, all you need to do is create an instance of the apps.fabianism.us/v1alpha1 Jellyfin resource. A basic example Jellyfin definition exists in deploy/crds/apps_v1alpha1_jellyfin_cr.yaml. You can create it with

kubectl apply -f deploy/crds/apps_v1alpha1_jellyfin_cr.yaml

This will kick off the deployment of the Jellyfin server. To monitor the status of the deployment, run

kubectl describe jellyfin

and monitor the status field. After some amount of time, a field called URL should appear in the status, this is the URL that the operator has generated for your server. You should be able to access the jellyfin web interface and configure it from there.

Deployment Options

The example deployment will only give you a very basic, ephemeral jellyfin. In order to get a real deployment, you will at least need to add storage options. The following options are supported in the Jellyfin spec:

name description default required
image The jellyfin image to deploy docker.io/jellyfin/jellyfin:latest no
volumes The volumes to create/mount into your container. See VolumeSpec for more detail. yes
nodePort If running on Kubernetes, the port on the host that Jellyfin should listen on. 30001 no
host If running openshift, the host that Jellyfin will be accessible from http://jellyfin-{namespace}.{openshift subdomain} no

VolumeSpec

The volumes field is a map of key:value pairs, where each key is a volume name and the value is a map of key:value pairs defining how the volume is to be created/mounted/accessed.

For configuration persistence, only one volume is required, the config volume. It must be mounted to /config with read-write permissions.

All volumes accept the following options:

name description default required
type The type of volume. Choices are [PersistentVolumeClaim, EmptyDir] yes
mountPath The full path to mount in the container. The name of the volume (ie, config -> /config). no
claimName The name of the PersistentVolumeClaim to use. The name of the volume. no
size The size of the volume to be created When type is PersistentVolumeClaim and create is true.
create Whether the PersistentVolumeClaim be created if it does not exist. no no
storageClassName The name of the storage class to set for a PersistentVolumeClaim The default storageClass for the cluster. no
accessModes The list of accessModes for a volume. Options are [ReadWriteOnce, ReadWriteMany, ReadOnlyMany] [ReadWriteOnce] no
readOnly Whether the volume should be mounted read only false no

Examples

Below are a few examples of some more complex Jellyfins

Using existing PersistentVolumeClaims
apiVersion: apps.fabianism.us/v1alpha1
kind: Jellyfin
metadata:
  name: existing-persistent-jellyfin
spec:
  image: docker.io/jellyfin/jellyfin:latest
  volumes:
    config:
      type: PersistentVolumeClaim
      claimName: jellyfin-config
      create: no
    media:
      type: PersistentVolumeClaim
      claimName: jellyfin-media
      create: no
      mountPath: /data/media
Using more than one media volume
apiVersion: apps.fabianism.us/v1alpha1
kind: Jellyfin
metadata:
  name: existing-persistent-jellyfin
spec:
  image: docker.io/jellyfin/jellyfin:latest
  volumes:
    # This is an existing claim
    config:
      type: PersistentVolumeClaim
      claimName: jellyfin-config
      create: no
    # But these media claims are being created
    tv:
      type: PersistentVolumeClaim
      claimName: jellyfin-tv
      create: yes
      mountPath: /data/media/tv
    movies:
      type: PersistentVolumeClaim
      claimName: jellyfin-movies
      create: yes
      mountPath: /data/media/movies