Plex on Kubernetes

00-plex-ns.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: plex

01-plex-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: plex-movies-pv
  labels:
    usage: movies
    app: plex
spec:
  storageClassName: "manual"
  capacity:
    storage: 100Gi
  accessModes:
    - ReadOnlyMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: NFS_SERVER
    path: "PATH_TO_MOVIES"

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: plex-tv-pv
  labels:
    usage: tv
    app: plex
spec:
  storageClassName: "manual"
  capacity:
    storage: 100Gi
  accessModes:
    - ReadOnlyMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: NFS_SERVER
    path: "PATH_TO_TV_SHOWS"

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: "plex-data-pv"
  labels:
    usage: data
    app: plex
spec:
  storageClassName: "manual"
  capacity:
    storage: "10Gi"
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "PLEX_DATA_PATH"

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: tautulli-logs-pv
  labels:
    usage: logs
    app: tautulli
spec:
  storageClassName: "manual"
  capacity:
    storage: 10Gi
  accessModes:
    - ReadOnlyMany
  hostPath:
    path: "/PLEX_DATA_PATH/Library/Application Support/Plex Media Server/Logs"

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: tautulli-data-pv
  labels:
    usage: data
    app: tautulli
spec:
  storageClassName: "manual"
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: NFS_SERVER
    path: "TAUTULLI_DATA_PATH"

02-plex.pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  namespace: "plex"
  name: "plex-movies-pvc"
spec:
  storageClassName: "manual"
  accessModes:
    - ReadOnlyMany
  resources:
    requests:
      storage: "100Gi"
  selector:
    matchLabels:
      usage: movies
      app: plex

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  namespace: "plex"
  name: "plex-tv-pvc"
spec:
  storageClassName: "manual"
  accessModes:
    - ReadOnlyMany
  resources:
    requests:
      storage: "100Gi"
  selector:
    matchLabels:
      usage: tv
      app: plex

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  namespace: "plex"
  name: "plex-data-pvc"
spec:
  storageClassName: "manual"
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: "10Gi"
  selector:
    matchLabels:
      usage: data
      app: plex

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  namespace: "plex"
  name: "tautulli-logs-pvc"
spec:
  storageClassName: "manual"
  accessModes:
    - ReadOnlyMany
  resources:
    requests:
      storage: "10Gi"
  selector:
    matchLabels:
      usage: logs
      app: tautulli

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  namespace: "plex"
  name: "tautulli-data-pvc"
spec:
  storageClassName: "manual"
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: "10Gi"
  selector:
    matchLabels:
      usage: data
      app: tautulli

03-plex-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: plex
  namespace: plex
  labels:
    app: plex
spec:
  replicas: 1
  selector:
    matchLabels:
      app: plex
  template:
    metadata:
      labels:
        app: plex
    spec:
      containers:
      - name: plex-app
        image: plexinc/pms-docker
        imagePullPolicy: Always
        ports:
        - containerPort: 32400
        env:
        - name: ADVERTISE_IP
          value: "http://HOST_IP:32400/"
        - name: VERSION
          value: "latest"
        - name: PUID
          value: "65534"
        - name: PGID
          value: "65534"
        - name: TZ
          value: "America/Los_Angeles"
        volumeMounts:
        - name: plex-data
          mountPath: /config
        - name: plex-movies
          mountPath: /movies
        - name: plex-tv
          mountPath: /tv
      - name: tautulli
        image: linuxserver/tautulli
        imagePullPolicy: Always
        ports:
        - containerPort: 8181
        env:
        - name: PGID
          value: "65534"
        - name: PUID
          value: "65534"
        - name: TZ
          value: "America/Los_Angeles"
        volumeMounts:
        - name: tautulli-data
          mountPath: /config
        - name: tautulli-logs
          mountPath: /logs
      volumes:
      - name: plex-data
        persistentVolumeClaim:
          claimName: plex-data-pvc
      - name: plex-movies
        persistentVolumeClaim:
          claimName: plex-movies-pvc
      - name: plex-tv
        persistentVolumeClaim:
          claimName: plex-tv-pvc
      - name: tautulli-logs
        persistentVolumeClaim:
          claimName: tautulli-logs-pvc
      - name: tautulli-data
        persistentVolumeClaim:
          claimName: tautulli-data-pvc

04-plex-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: plex
  namespace: plex
spec:
  selector:
    app: plex
  ports:
  - name: plex
    port: 32400
    targetPort: 32400
  externalIPs: ["HOST_IP"]

---
apiVersion: v1
kind: Service
metadata:
  name: tautulli-svc
  namespace: plex
spec:
  ports:
  - name: tautulli
    port: 8181
  selector:
    app: plex

05-tautulli-ingress.yaml

kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
  name: tautulli-ingress
  namespace: plex
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
  rules:
    - host: TAUTULLI_HOSTNAME
      http:
        paths:
          - path: /
            backend:
              serviceName: tautulli-svc
              servicePort: 8181
kubectl create -f .

On your router create a DNS record for plex.direct that points to the IP of your Plex host.

Bypass DNS rebind protection for plex.direct on your router/firewall.

For pfsense add server:private-domain: "plex.direct" to Custom Options in DNS Resolver.