Skip to content

Instantly share code, notes, and snippets.

@darth-veitcher
Last active May 25, 2024 11:31
Show Gist options
  • Save darth-veitcher/802d028d8e3888d673af87fdf0f41609 to your computer and use it in GitHub Desktop.
Save darth-veitcher/802d028d8e3888d673af87fdf0f41609 to your computer and use it in GitHub Desktop.
Plex on Kubernetes
apiVersion: v1
kind: Secret
metadata:
name: plex-claim-token
namespace: media
type: Opaque
data:
token: ${API_TOKEN_OPAQUE}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: plex-config
namespace: media
labels:
app: plex
data:
TZ: "Europe/London"
ADVERTISE_IP: "http://192.168.0.123:32400/"
PLEX_UID: "1000"
PLEX_GID: "1000"
CHANGE_CONFIG_DIR_OWNERSHIP: "false"
ALLOWED_NETWORKS: "192.168.0.0/24"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: plex
namespace: media
labels:
app: plex
spec:
replicas: 1
selector:
matchLabels:
app: plex
strategy:
type: Recreate
template:
metadata:
labels:
app: plex
namespace: media
spec:
containers:
- name: plex
image: plexinc/pms-docker
# use resources otherwise logs will eat your ephemeral-storage
# resulting in root `/` at 100% on nodes and pods becoming
# `evicted`
resources:
requests:
memory: "4Gi"
cpu: "1"
ephemeral-storage: "2Gi"
limits:
memory: "16Gi"
cpu: "2"
ephemeral-storage: "4Gi"
ports:
# https://support.plex.tv/articles/201543147-what-network-ports-do-i-need-to-allow-through-my-firewall/
- containerPort: 32400
name: pms
protocol: TCP
- containerPort: 1900
name: dnla-udp
protocol: UDP
- containerPort: 32469
name: dnla-tcp
protocol: TCP
- containerPort: 3005
name: home-theatre
protocol: TCP
- containerPort: 5353
name: discovery
protocol: TCP
- containerPort: 8324
name: roku
protocol: TCP
- containerPort: 32410
protocol: UDP
- containerPort: 32412
protocol: UDP
- containerPort: 32413
protocol: UDP
- containerPort: 32414
protocol: UDP
envFrom:
- configMapRef:
name: plex-config
env:
# Secrets
- name: PLEX_CLAIM
valueFrom:
secretKeyRef:
name: plex-claim-token
key: token
volumeMounts:
- mountPath: /config
name: config
- mountPath: /transcode
name: transcode
- mountPath: /data
name: media
# Only run this at home
# https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
# nodeSelector:
# topology.kubernetes.io/region: house
# https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
affinity:
nodeAffinity:
# Only run this at home
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- house
# If possible run on the dedicated media box
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: role
operator: In
values:
- media
# https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy
dnsPolicy: ClusterFirst
dnsConfig:
nameservers:
- 192.168.0.122
volumes:
- name: config
hostPath:
path: /mnt/unionfs/storage/plex/config
type: DirectoryOrCreate
- name: transcode
hostPath:
path: /mnt/disks/hot-storage/transcodes
type: DirectoryOrCreate
- name: media
hostPath:
path: /mnt/unionfs/media
type: DirectoryOrCreate
---
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: plex
namespace: media
spec:
secretName: plex-certs
duration: 2160h # 90d
renewBefore: 360h # 15d
organization:
- mydomain
commonName: plex.mydomain.wtf
isCA: false
keySize: 2048
keyAlgorithm: rsa
keyEncoding: pkcs1
usages:
- server auth
- client auth
dnsNames:
- plex.mydomain.wtf
issuerRef:
name: letsencrypt
kind: ClusterIssuer
group: cert-manager.io
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: plex-external-ingress
namespace: media
labels:
app: plex
tier: frontend
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/issuer: "letsencrypt"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
tls:
- hosts:
- plex.mydomain.wtf
secretName: plex-certs
rules:
- host: plex.mydomain.wtf
http:
paths:
- path: /
backend:
serviceName: plex-tcp
servicePort: pms
---
apiVersion: v1
kind: Service
metadata:
name: plex-udp
namespace: media
annotations:
metallb.universe.tf/allow-shared-ip: plex-svc
labels:
app: enternal-dns
spec:
type: LoadBalancer
loadBalancerIP: 192.168.0.123
externalTrafficPolicy: Local
ports:
- name: dnla-udp
port: 1900
protocol: UDP
targetPort: dnla-udp
- name: gdm32410
port: 32410
protocol: UDP
targetPort: 32410
- name: gdm32412
port: 32412
protocol: UDP
targetPort: 32412
- name: gdm32413
port: 32413
protocol: UDP
targetPort: 32413
- name: gdm32414
port: 32414
protocol: UDP
targetPort: 32414
selector:
app: plex
sessionAffinity: None
---
apiVersion: v1
kind: Service
metadata:
name: plex-tcp
namespace: media
annotations:
metallb.universe.tf/allow-shared-ip: plex-svc
labels:
app: plex
spec:
type: LoadBalancer
loadBalancerIP: 192.168.0.123
externalTrafficPolicy: Local
ports:
- name: pms
port: 32400
protocol: TCP
targetPort: pms
- name: home-theatre
port: 3005
protocol: TCP
targetPort: home-theatre
- name: discovery
port: 5353
protocol: TCP
targetPort: discovery
- name: roku
port: 8324
protocol: TCP
targetPort: roku
- name: dnla-tcp
port: 32469
protocol: TCP
targetPort: dnla-tcp
selector:
app: plex
sessionAffinity: None
@darth-veitcher
Copy link
Author

Get your claim token from here

Now encode it into the secret

API_TOKEN_CLEAN=claim-superdupersecret
API_TOKEN_OPAQUE=$(echo -n ${API_TOKEN_CLEAN} | base64)

tee plex-claim.yaml << EOF
apiVersion: v1
kind: Secret
metadata:
  name: plex-claim-token
  namespace: media
type: Opaque
data:
  token: ${API_TOKEN_OPAQUE}
EOF

@KlimDos
Copy link

KlimDos commented Feb 10, 2022

any idea why discovery might not work?

  • pod running fine
  • UI available on 32400
  • LB works fine
  • Endpoints persists which means ports are open

image

trying to connect via telnet says refused

image

UPDATE: found the real reason - node not able to open UDP ports (don't know why)
image

troubleshooting ...

UPDATE#2:

  • as usually k8s is k8s =) nothing is working on that darn sth
    image
    the issue with k8s 1.23 and calico CNI which is used in microk8s
    kubernetes/kubernetes#107170

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment