Add upstream plex chart

This commit is contained in:
Waqar Ahmed 2020-12-06 23:55:26 +05:00
parent 66c3d0d0e0
commit 753e183b60
17 changed files with 1325 additions and 0 deletions

24
test/plex/.helmignore Normal file
View File

@ -0,0 +1,24 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# OWNERS file for Kubernetes
OWNERS

15
test/plex/Chart.yaml Normal file
View File

@ -0,0 +1,15 @@
apiVersion: v2
appVersion: 1.20.2.3402
description: Plex Media Server
name: plex
version: 2.1.0
keywords:
- plex
home: https://plex.tv/
icon: https://www.plex.tv/wp-content/uploads/2018/01/pmp-icon-1.png
sources:
- https://github.com/k8s-at-home/charts/tree/master/charts/plex
- https://hub.docker.com/r/plexinc/pms-docker/
maintainers:
- name: billimek
email: jeff@billimek.com

4
test/plex/OWNERS Normal file
View File

@ -0,0 +1,4 @@
approvers:
- billimek
reviewers:
- billimek

48
test/plex/README.md Normal file
View File

@ -0,0 +1,48 @@
# Plex Media Server helm chart
This is an opinionated helm chart for Plex Media Center based on the [official container image](https://hub.docker.com/r/plexinc/pms-docker/).
This chart is 'forked' from the excellent [munnerz/kube-plex](https://github.com/munnerz/kube-plex) repo in order to allow for more timely updates and publishing to a helm registry. **NOTE:** This chart is not compatible as an upgrade from the `kube-plex` chart.
## TL;DR
```shell
helm repo add k8s-at-home https://k8s-at-home.com/charts/
helm install k8s-at-home/plex
```
## Installing the Chart
To install the chart with the release name `plex`:
```console
helm install plex k8s-at-home/plex
```
## Uninstalling the Chart
To uninstall/delete the `plex` deployment:
```console
helm delete plex
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
## Configuration
Read through the [values.yaml](https://github.com/k8s-at-home/charts/blob/master/charts/plex/values.yaml) file. It has several commented out suggested values.
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
```console
helm install plex \
--set timezone="America/New York" \
k8s-at-home/plex
```
Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example,
```console
helm install plex -f values.yaml k8s-at-home/plex
```

View File

@ -0,0 +1,64 @@
#!/usr/bin/with-contenv bash
# This file is based off of the official 40-plex-first-run
# Here: https://github.com/plexinc/pms-docker/blob/master/root/etc/cont-init.d/40-plex-first-run
# It should live in /etc/cont-init.d/
# If we are debugging, enable trace
if [ "${DEBUG,,}" = "true" ]; then
set -x
fi
function getPref {
local key="$1"
xmlstarlet sel -T -t -m "/Preferences" -v "@${key}" -n "${prefFile}"
}
function setPref {
local key="$1"
local value="$2"
count="$(xmlstarlet sel -t -v "count(/Preferences/@${key})" "${prefFile}")"
count=$(($count + 0))
if [[ $count > 0 ]]; then
xmlstarlet ed --inplace --update "/Preferences/@${key}" -v "${value}" "${prefFile}"
else
xmlstarlet ed --inplace --insert "/Preferences" --type attr -n "${key}" -v "${value}" "${prefFile}"
fi
}
home="$(echo ~plex)"
pmsApplicationSupportDir="${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR:-${home}/Library/Application Support}"
prefFile="${pmsApplicationSupportDir}/Plex Media Server/Preferences.xml"
if [ ! -z "${ADVERTISE_IP}" ]; then
setPref "customConnections" "${ADVERTISE_IP}"
fi
if [ ! -z "${ALLOWED_NETWORKS}" ]; then
setPref "allowedNetworks" "${ALLOWED_NETWORKS}"
fi
# Set transcoder temp if not yet set
if [ -z "$(getPref "TranscoderTempDirectory")" ]; then
setPref "TranscoderTempDirectory" "/transcode"
fi
# Parse list of all exported variables that start with PLEX_PREFERENCE_
# The format of which is PLEX_PREFERENCE_<SOMETHING>="Key=Value"
# Where Key is the EXACT key to use in the Plex Preference file
# And Value is the EXACT value to use in the Plex Preference file for that key.
# Please note it looks like many of the key's are camelCase in some fashion.
# Additionally there are likely some preferences where environment variable injection
# doesn't really work for.
for var in "${!PLEX_PREFERENCE_@}"; do
value=${!var}
PreferenceValue=${value#*=}
PreferenceKey=${value%=*}
setPref $PreferenceKey $PreferenceValue
done
# touch /.firstRunComplete
# echo "Plex Media Server first run setup complete"
echo "Plex Media Server preferences update run complete"

View File

@ -0,0 +1,53 @@
#!/usr/bin/with-contenv bash
# This file contains part of the official PLEX 40-plex-first-run
# Here: https://github.com/plexinc/pms-docker/blob/master/root/etc/cont-init.d/40-plex-first-run
# It should live in /etc/cont-init.d/
# If we are debugging, enable trace
if [ "${DEBUG,,}" = "true" ]; then
set -x
fi
function setPref {
local key="$1"
local value="$2"
count="$(xmlstarlet sel -t -v "count(/Preferences/@${key})" "${prefFile}")"
count=$(($count + 0))
if [[ $count > 0 ]]; then
xmlstarlet ed --inplace --update "/Preferences/@${key}" -v "${value}" "${prefFile}"
else
xmlstarlet ed --inplace --insert "/Preferences" --type attr -n "${key}" -v "${value}" "${prefFile}"
fi
}
home="$(echo ~plex)"
pmsApplicationSupportDir="${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR:-${home}/Library/Application Support}"
prefFile="${pmsApplicationSupportDir}/Plex Media Server/Preferences.xml"
# If PKCSMANGLER__PFXINCONTAINERPATH is set, then assume we want to move the PFX Cert to that location
if [ ! -z "${PKCSMANGLER_PFXINCONTAINERPATH}" ]; then
# If it ends up a problem, we may need to set some kind of "don't replace existing PFX cert"
cp -f /shared/cert.pfx "${PKCSMANGLER_PFXINCONTAINERPATH}"
# If PKCSMANGLER__CUSTOMCERTDOMAIN is set, then assume we want to set the PLEX Preference customCertificatePath because we enabled setting PLEX Preferences
if [ ! -z "${PKCSMANGLER_CUSTOMCERTDOMAIN}" ]; then
setPref "customCertificatePath" "${PKCSMANGLER_PFXINCONTAINERPATH}"
fi
fi
# If PKCSMANGLER_PFXPASSWORD is set, then assume we want to set the PLEX Preference customCertificateKey
if [ ! -z "${PKCSMANGLER_PFXPASSWORD}" ]; then
setPref "customCertificateKey" "${PKCSMANGLER_PFXPASSWORD}"
fi
# If PKCSMANGLER__CUSTOMCERTDOMAIN is set, then assume we want to set the PLEX Preference customCertificateDomain
if [ ! -z "${PKCSMANGLER_CUSTOMCERTDOMAIN}" ]; then
PreferenceValue=${PKCSMANGLER_CUSTOMCERTDOMAIN#*=}
PreferenceKey=${PKCSMANGLER_CUSTOMCERTDOMAIN%=*}
setPref $PreferenceKey $PreferenceValue
fi
# touch /.firstRunComplete
# echo "Plex Media Server first run setup complete"
echo "PKCS Mangler run complete"

View File

@ -0,0 +1,19 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}
{{- end }}
{{- else if contains "NodePort" .Values.serviceTCP.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "plex.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.serviceTCP.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "plex.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "plex.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.serviceTCP.port }}
{{- else if contains "ClusterIP" .Values.serviceTCP.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "plex.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
{{- end }}

View File

@ -0,0 +1,81 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "plex.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "plex.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "plex.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Common labels
*/}}
{{- define "plex.labels" -}}
helm.sh/chart: {{ include "plex.chart" . }}
{{ include "plex.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}
{{/*
Selector labels
*/}}
{{- define "plex.selectorLabels" -}}
app.kubernetes.io/name: {{ include "plex.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
{{/*
Create the name of the service account to use
*/}}
{{- define "plex.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
{{ default (include "plex.fullname" .) .Values.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.serviceAccount.name }}
{{- end -}}
{{- end -}}
{{/*
abstract: |
Joins a list of values into a comma separated string
values: |
test:
- foo
- bar
usage: |
{{ include "joinListWithComma" .Values.test }}
return: |
foo,bar
*/}}
{{- define "joinListWithComma" -}}
{{- $local := dict "first" true -}}
{{- range $k, $v := . -}}{{- if not $local.first -}},{{- end -}}{{- $v -}}{{- $_ := set $local "first" false -}}{{- end -}}
{{- end -}}

View File

@ -0,0 +1,42 @@
{{- if .Values.plexPreferences.enabled -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Values.plexPreferences.configmap.name }}
labels:
{{- include "plex.labels" . | nindent 4 }}
{{- if .Values.plexPreferences.configmap.labels }}
{{ toYaml .Values.plexPreferences.configmap.labels | indent 4 }}
{{- end }}
{{- with .Values.plexPreferences.configmap.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
data:
# At some point figure out how to use a value/Variable here to be able to specify
# a different file or something.
{{ (tpl (.Files.Glob "configs/41-plex-preferences").AsConfig . ) | indent 2 }}
{{- end -}}
{{- if .Values.certificate.pkcsMangler.enabled }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Values.certificate.pkcsMangler.configmap.name }}
labels:
{{- include "plex.labels" . | nindent 4 }}
{{- if .Values.certificate.pkcsMangler.configmap.labels }}
{{ toYaml .Values.certificate.pkcsMangler.configmap.labels | indent 4 }}
{{- end }}
{{- with .Values.certificate.pkcsMangler.configmap.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
data:
# At some point figure out how to use a value/Variable here to be able to specify
# a different file or something.
{{ (tpl (.Files.Glob "configs/42-pkcs-mangler").AsConfig . ) | indent 2 }}
{{- end -}}

View File

@ -0,0 +1,357 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "plex.fullname" . }}
labels:
{{- include "plex.labels" . | nindent 4 }}
{{- if .Values.deploymentAnnotations }}
annotations:
{{- range $key, $value := .Values.deploymentAnnotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- end }}
spec:
replicas: 1
revisionHistoryLimit: 3
strategy:
type: {{ .Values.strategyType }}
selector:
matchLabels:
{{- include "plex.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "plex.selectorLabels" . | nindent 8 }}
{{- if .Values.podAnnotations }}
annotations:
{{- range $key, $value := .Values.podAnnotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.hostNetwork }}
hostNetwork: {{ .Values.hostNetwork }}
dnsPolicy: ClusterFirstWithHostNet
{{- end }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
{{- if .Values.certificate.pkcsMangler.enabled }}
initContainers:
# This is ugly, but it does work to create a pks file that will work with PLEX from the tls.crt and tls.key that cert-manager normally creates
{{- if .Values.certificate.pkcsMangler.enabled }}
- name: pkcsmangler-init-container
image: "{{ .Values.certificate.pkcsMangler.image.repository }}:{{ .Values.certificate.pkcsMangler.image.tag }}"
imagePullPolicy: Always
command: ["/bin/sh"]
args: ["-c", "openssl pkcs12 -export -passout pass:$(PKCSMANGLER_PFXPASSWORD) -out /shared/cert.pfx -inkey {{ .Values.certificate.pkcsMangler.certificateSecret.volume.mountPath }}/{{ .Values.certificate.pkcsMangler.certificateSecret.keyName }} -in {{ .Values.certificate.pkcsMangler.certificateSecret.volume.mountPath }}/{{ .Values.certificate.pkcsMangler.certificateSecret.crtName }}; chmod 0444 /shared/cert.pfx"]
env:
- name: "PKCSMANGLER_PFXPASSWORD"
valueFrom:
secretKeyRef:
name: {{ .Values.certificate.pkcsMangler.pfxPassword.secretName }}
key: {{ .Values.certificate.pkcsMangler.pfxPassword.passwordKey }}
volumeMounts:
- name: shared
mountPath: /shared
- name: {{ .Values.certificate.pkcsMangler.certificateSecret.volume.name }}
mountPath: {{ .Values.certificate.pkcsMangler.certificateSecret.volume.mountPath }}
{{- end }}
{{- end }}
containers:
{{- if .Values.logging.promtail.enabled }}
- name: {{ .Chart.Name }}-promtail
image: "{{ .Values.logging.promtail.image.repository }}:{{ .Values.logging.promtail.image.tag }}"
imagePullPolicy: {{ .Values.logging.promtail.image.pullPolicy }}
args:
- -config.file=/etc/promtail/promtail.yaml
volumeMounts:
- name: promtail-config
mountPath: /etc/promtail/promtail.yaml
subPath: promtail.yaml
readOnly: true
- name: shared-logs
mountPath: /plex-logs
{{- end }}
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: pms
protocol: TCP
containerPort: 32400
- name: plex-dlna
protocol: TCP
containerPort: 32469
- name: plex-dlna-udp
protocol: UDP
containerPort: 1900
- name: plex-gdm1
protocol: UDP
containerPort: 32410
- name: plex-gdm2
protocol: UDP
containerPort: 32412
- name: plex-gdm3
protocol: UDP
containerPort: 32413
- name: plex-gdm4
protocol: UDP
containerPort: 32414
env:
- name: TZ
value: "{{ .Values.timezone }}"
# TODO: move this to a secret?
- name: PLEX_CLAIM
value: "{{ .Values.claimToken }}"
# plex env vars
- name: PMS_INTERNAL_ADDRESS
value: http://{{ template "plex.fullname" . }}:32400
- name: PMS_IMAGE
value: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
- name: KUBE_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: TRANSCODE_PVC
{{- if .Values.persistence.transcode.claimName }}
value: "{{ .Values.persistence.transcode.claimName }}"
{{- else }}
value: "{{ template "plex.fullname" . }}-transcode"
{{- end }}
{{- if .Values.persistence.data.enabled }}
- name: DATA_PVC
{{- if .Values.persistence.data.claimName }}
value: "{{ .Values.persistence.data.claimName }}"
{{- else }}
value: "{{ template "plex.fullname" . }}-data"
{{- end }}
{{- end }}
- name: CONFIG_PVC
{{- if .Values.persistence.config.claimName }}
value: "{{ .Values.persistence.config.claimName }}"
{{- else }}
value: "{{ template "plex.fullname" . }}-config"
{{- end }}
{{- if .Values.proxy.enabled }}
{{- if .Values.proxy.http }}
- name: "HTTP_PROXY"
value: "{{.Values.proxy.http}}"
{{- end }}
{{- if .Values.proxy.https }}
- name: "HTTPS_PROXY"
value: "{{.Values.proxy.https}}"
{{- end }}
{{- if .Values.proxy.noproxy }}
- name: "NO_PROXY"
value: "{{.Values.proxy.noproxy}}"
{{- end }}
{{- end }}
{{- if .Values.advertiseIp }}
- name: "ADVERTISE_IP"
value: "{{.Values.advertiseIp}}"
{{- end }}
{{- if .Values.changeConfigDirOwnership }}
- name: "CHANGE_CONFIG_DIR_OWNERSHIP"
value: "{{.Values.changeConfigDirOwnership}}"
{{- end }}
{{- if .Values.allowedNetworks }}
- name: "ALLOWED_NETWORKS"
value: "{{include "joinListWithComma" .Values.allowedNetworks}}"
{{- end }}
{{- if .Values.plexUid }}
- name: "PLEX_UID"
value: "{{.Values.plexUid}}"
{{- end }}
{{- if .Values.plexGid }}
- name: "PLEX_GID"
value: "{{.Values.plexGid}}"
{{- end }}
# Extra ENV Values supplied by user
{{- range $key, $value := .Values.extraEnv }}
- name: {{ $key }}
value: {{ $value }}
{{- end }}
# This is part of pkcsMangler
{{- if .Values.certificate.pkcsMangler.enabled }}
- name: "PKCSMANGLER_PFXINCONTAINERPATH"
value: "{{.Values.certificate.pkcsMangler.pfxInContainerPath}}"
{{- if .Values.certificate.pkcsMangler.setPlexPreferences.enabled }}
- name: "PKCSMANGLER_PFXPASSWORD"
valueFrom:
secretKeyRef:
name: {{ .Values.certificate.pkcsMangler.pfxPassword.secretName }}
key: {{ .Values.certificate.pkcsMangler.pfxPassword.passwordKey }}
- name: "PKCSMANGLER_CUSTOMCERTDOMAIN"
value: "customCertificateDomain={{.Values.certificate.pkcsMangler.setPlexPreferences.customCertificateDomain}}"
{{- end }}
{{- end }}
readinessProbe:
httpGet:
path: /identity
port: 32400
failureThreshold: {{ .Values.probes.readiness.failureThreshold }}
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
livenessProbe:
httpGet:
path: /identity
port: 32400
failureThreshold: {{ .Values.probes.liveness.failureThreshold }}
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
startupProbe:
httpGet:
path: /identity
port: 32400
initialDelaySeconds: {{ .Values.probes.startup.initialDelaySeconds }}
failureThreshold: {{ .Values.probes.startup.failureThreshold }}
periodSeconds: {{ .Values.probes.startup.periodSeconds }}
volumeMounts:
{{- if .Values.persistence.data.enabled }}
- name: data
mountPath: /data
{{- if .Values.persistence.data.subPath }}
subPath: {{ .Values.persistence.data.subPath }}
{{ end }}
{{ end }}
- name: config
mountPath: /config
{{- if .Values.persistence.config.subPath }}
subPath: {{ .Values.persistence.config.subPath }}
{{ end }}
- name: transcode
mountPath: /transcode
{{- if .Values.persistence.transcode.subPath }}
subPath: {{ .Values.persistence.transcode.subPath }}
{{ end }}
{{- range .Values.persistence.extraData }}
- mountPath: "/data-{{ .name }}"
{{- if .subPath }}
subPath: {{ .subPath }}
{{ end }}
name: "extradata-{{ .name }}"
{{- end }}
{{- range .Values.persistence.extraMounts }}
{{- if .mountPath }}
- mountPath: /{{ .mountPath }}
{{- else }}
- mountPath: /{{ .name }}
{{- end }}
{{- if .subPath }}
subPath: {{ .subPath }}
{{ end }}
name: {{ .name }}
{{- end }}
- name: shared
mountPath: /shared
- name: shared-logs
mountPath: "/config/Library/Application Support/Plex Media Server/Logs"
{{- if .Values.plexPreferences.enabled }}
- name: {{ .Values.plexPreferences.volume.name }}
mountPath: {{ .Values.plexPreferences.volume.mountPath }}
subPath: {{ .Values.plexPreferences.volume.subPath }}
{{- end }}
{{- if .Values.certificate.pkcsMangler.enabled }}
- name: {{ .Values.certificate.pkcsMangler.volume.name }}
mountPath: {{ .Values.certificate.pkcsMangler.volume.mountPath }}
subPath: {{ .Values.certificate.pkcsMangler.volume.subPath }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
##### VOLUMES START #####
volumes:
{{- if .Values.persistence.data.enabled }}
- name: data
persistentVolumeClaim:
{{- if .Values.persistence.data.claimName }}
claimName: "{{ .Values.persistence.data.claimName }}"
{{- else }}
claimName: "{{ template "plex.fullname" . }}-data"
{{- end }}
{{- end }}
- name: config
persistentVolumeClaim:
{{- if .Values.persistence.config.claimName }}
claimName: "{{ .Values.persistence.config.claimName }}"
{{- else }}
claimName: "{{ template "plex.fullname" . }}-config"
{{- end }}
- name: transcode
{{- if .Values.persistence.transcode.enabled }}
persistentVolumeClaim:
{{- if .Values.persistence.transcode.claimName }}
claimName: "{{ .Values.persistence.transcode.claimName }}"
{{- else }}
claimName: "{{ template "plex.fullname" . }}-transcode"
{{- end }}
{{- else }}
{{- if .Values.persistence.transcode.emptyDir.medium }}
emptyDir:
medium: "{{ .Values.persistence.transcode.emptyDir.medium }}"
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}
{{- range .Values.persistence.extraData }}
- name: "extradata-{{ .name }}"
persistentVolumeClaim:
{{- if .claimName }}
claimName: "{{ .claimName }}"
{{- else }}
claimName: "extradata-{{ .name }}"
{{- end }}
{{- end }}
{{- range .Values.persistence.extraMounts }}
{{- if .claimName }}
- name: {{ .name }}
persistentVolumeClaim:
claimName: {{ .claimName }}
{{- end }}
{{- end }}
- name: shared
emptyDir: {}
- name: shared-logs
emptyDir: {}
{{- if .Values.plexPreferences.enabled }}
- name: {{ .Values.plexPreferences.volume.name }}
configMap:
name: {{ .Values.plexPreferences.configmap.name }}
defaultMode: {{ .Values.plexPreferences.volume.defaultMode }}
{{- end }}
{{- if .Values.certificate.pkcsMangler.enabled }}
- name: {{ .Values.certificate.pkcsMangler.volume.name }}
configMap:
name: {{ .Values.certificate.pkcsMangler.configmap.name }}
defaultMode: {{ .Values.certificate.pkcsMangler.volume.defaultMode }}
- name: {{ .Values.certificate.pkcsMangler.certificateSecret.volume.name }}
secret:
secretName: {{ .Values.certificate.pkcsMangler.certificateSecret.name }}
{{- end }}
{{- if .Values.logging.promtail.enabled }}
- name: promtail-config
projected:
defaultMode: 0444
sources:
- configMap:
name: {{ template "plex.fullname" . }}-promtail
items:
- key: promtail.yaml
path: promtail.yaml
{{- end }}
##### VOLUMES END #####
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@ -0,0 +1,40 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "plex.fullname" . -}}
{{- $svcPort := .Values.serviceTCP.port -}}
{{- $ingressPath := .Values.ingress.path -}}
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "plex.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ . | quote }}
http:
paths:
- path: {{ $ingressPath }}
backend:
serviceName: {{ $fullName }}-tcp
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,36 @@
{{- if .Values.logging.promtail.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "plex.fullname" . }}-promtail
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ include "plex.name" . }}
helm.sh/chart: {{ include "plex.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
data:
promtail.yaml: |
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: {{ .Values.logging.promtail.loki.url }}
scrape_configs:
- job_name: plex-logs
static_configs:
- targets:
- localhost
labels:
job: plex-logs
__path__: "/plex-logs/*.log"
- job_name: plex-plugin-logs
static_configs:
- targets:
- localhost
labels:
job: plex-plugin-logs
__path__: "/plex-logs/PMS Plugin Logs/*.log"
{{- end }}

View File

@ -0,0 +1,18 @@
{{- if .Values.certificate.pkcsMangler.enabled -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.certificate.pkcsMangler.pfxPassword.secretName }}
labels:
{{- include "plex.labels" . | nindent 4 }}
{{- if .Values.certificate.pkcsMangler.pfxPassword.labels }}
{{ toYaml .Values.certificate.pkcsMangler.pfxPassword.labels | indent 4 }}
{{- end }}
{{- with .Values.certificate.pkcsMangler.pfxPassword.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
type: Opaque
stringData:
{{ .Values.certificate.pkcsMangler.pfxPassword.passwordKey }}: {{ .Values.certificate.pkcsMangler.pfxPassword.value }}
{{- end -}}

View File

@ -0,0 +1,57 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "plex.fullname" . }}-tcp
labels:
{{- include "plex.labels" . | nindent 4 }}
{{- if .Values.serviceTCP.labels }}
{{ toYaml .Values.serviceTCP.labels | indent 4 }}
{{- end }}
{{- with .Values.serviceTCP.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if (or (eq .Values.serviceTCP.type "ClusterIP") (empty .Values.serviceTCP.type)) }}
type: ClusterIP
{{- if .Values.serviceTCP.clusterIP }}
clusterIP: {{ .Values.serviceTCP.clusterIP }}
{{end}}
{{- else if eq .Values.serviceTCP.type "LoadBalancer" }}
type: {{ .Values.serviceTCP.type }}
{{- if .Values.serviceTCP.loadBalancerIP }}
loadBalancerIP: {{ .Values.serviceTCP.loadBalancerIP }}
{{- end }}
{{- if .Values.serviceTCP.loadBalancerSourceRanges }}
loadBalancerSourceRanges:
{{ toYaml .Values.serviceTCP.loadBalancerSourceRanges | indent 4 }}
{{- end -}}
{{- else }}
type: {{ .Values.serviceTCP.type }}
{{- end }}
{{- if .Values.serviceTCP.externalIPs }}
externalIPs:
{{ toYaml .Values.serviceTCP.externalIPs | indent 4 }}
{{- end }}
{{- if .Values.serviceTCP.externalTrafficPolicy }}
externalTrafficPolicy: {{ .Values.serviceTCP.externalTrafficPolicy }}
{{- end }}
ports:
- name: pms
port: {{ .Values.serviceTCP.port }}
protocol: TCP
targetPort: pms
{{ if (and (eq .Values.serviceTCP.type "NodePort") (not (empty .Values.serviceTCP.nodePort))) }}
nodePort: {{.Values.serviceTCP.nodePort}}
{{ end }}
- name: http
port: 80
targetPort: pms
- name: https
port: 443
targetPort: pms
- name: plex-dlna
port: 1900
targetPort: plex-dlna
selector:
{{- include "plex.selectorLabels" . | nindent 4 }}

View File

@ -0,0 +1,61 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "plex.fullname" . }}-udp
labels:
{{- include "plex.labels" . | nindent 4 }}
{{- if .Values.serviceUDP.labels }}
{{ toYaml .Values.serviceUDP.labels | indent 4 }}
{{- end }}
{{- with .Values.serviceUDP.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if (or (eq .Values.serviceUDP.type "ClusterIP") (empty .Values.serviceUDP.type)) }}
type: ClusterIP
{{- if .Values.serviceUDP.clusterIP }}
clusterIP: {{ .Values.serviceUDP.clusterIP }}
{{end}}
{{- else if eq .Values.serviceUDP.type "LoadBalancer" }}
type: {{ .Values.serviceUDP.type }}
{{- if .Values.serviceUDP.loadBalancerIP }}
loadBalancerIP: {{ .Values.serviceUDP.loadBalancerIP }}
{{- end }}
{{- if .Values.serviceUDP.loadBalancerSourceRanges }}
loadBalancerSourceRanges:
{{ toYaml .Values.serviceUDP.loadBalancerSourceRanges | indent 4 }}
{{- end -}}
{{- else }}
type: {{ .Values.serviceUDP.type }}
{{- end }}
{{- if .Values.serviceUDP.externalIPs }}
externalIPs:
{{ toYaml .Values.serviceUDP.externalIPs | indent 4 }}
{{- end }}
{{- if .Values.serviceUDP.externalTrafficPolicy }}
externalTrafficPolicy: {{ .Values.serviceUDP.externalTrafficPolicy }}
{{- end }}
ports:
- name: plex-dlna-udp
port: 1900
protocol: UDP
targetPort: plex-dlna-udp
- name: plex-gdm1
port: 32410
protocol: UDP
targetPort: plex-gdm1
- name: plex-gdm2
port: 32412
protocol: UDP
targetPort: plex-gdm2
- name: plex-gdm3
port: 32413
protocol: UDP
targetPort: plex-gdm3
- name: plex-gdm4
port: 32414
protocol: UDP
targetPort: plex-gdm4
selector:
{{- include "plex.selectorLabels" . | nindent 4 }}

View File

@ -0,0 +1,57 @@
{{- if and (not .Values.persistence.transcode.claimName) .Values.persistence.transcode.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ template "plex.fullname" . }}-transcode
labels:
{{- include "plex.labels" . | nindent 4 }}
component: transcode
spec:
accessModes:
- {{ .Values.persistence.config.accessMode | quote }}
resources:
requests:
storage: {{ .Values.persistence.transcode.size | quote }}
{{- if .Values.persistence.transcode.storageClass }}
storageClassName: {{ .Values.persistence.transcode.storageClass | quote }}
{{- end }}
---
{{- end }}
{{- if not .Values.persistence.config.claimName }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ template "plex.fullname" . }}-config
labels:
{{- include "plex.labels" . | nindent 4 }}
component: config
spec:
accessModes:
- {{ .Values.persistence.config.accessMode | quote }}
resources:
requests:
storage: {{ .Values.persistence.config.size | quote }}
{{- if .Values.persistence.config.storageClass }}
storageClassName: {{ .Values.persistence.config.storageClass | quote }}
{{- end }}
---
{{- end }}
{{- if and (not .Values.persistence.data.claimName) .Values.persistence.data.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ template "plex.fullname" . }}-data
labels:
{{- include "plex.labels" . | nindent 4 }}
component: data
spec:
accessModes:
- {{ .Values.persistence.data.accessMode | quote }}
resources:
requests:
storage: {{ .Values.persistence.data.size | quote }}
{{- if .Values.persistence.data.storageClass }}
storageClassName: {{ .Values.persistence.data.storageClass | quote }}
{{- end }}
---
{{- end }}

349
test/plex/values.yaml Normal file
View File

@ -0,0 +1,349 @@
# Default values
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# The Image to use for PLEX
image:
repository: plexinc/pms-docker
tag: 1.20.2.3402-0fec14d92
pullPolicy: IfNotPresent
##### START --> Official PLEX container environment variables
# Override this with the plex claim token from plex.tv/claim
claimToken: ""
# Set the timezone of the plex server
timezone: "UTC"
# add your pod network subnet to the `List of IP addresses and networks that are allowed without auth`
# This will override the manual settings, so only use this if you will not need to change it manually.
# This list will be automatically converted to a command seperated string when passed to the container.
# You would specify this when using helm CLI with --set allowedNetworks="{127.0.0.1,10.54.2.0/24}"
# allowedNetworks:
# - 127.0.0.1
# - 10.54.2.0/24
# Instruct the Plex Media Server Container to Change the Configuration Directory Ownership
# Default is true, you would only need to set this if you want to disable it.
# changeConfigDirOwnership: true
# advertiseIp This variable defines the additional IPs on which the server may be be found.
# For example: http://10.1.1.23:32400.
# This adds to the list where the server advertises that it can be found.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# advertiseIp: "http://10.1.1.23:32400"
# Set The user id of the plex user created inside the container.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexUid: 1000
# Set The group id of the plex group created inside the container
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexGid: 1000
##### END --> Official PLEX container environment variables
# You can add as many Additional ENV variables here
# The following is the same as --set extraEnv.TMPDIR="/transcode"
# extraEnv:
# TMPDIR: /transcode
# upgrade strategy type (e.g. Recreate or RollingUpdate)
strategyType: Recreate
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
serviceTCP:
type: ClusterIP
port: 32400
## Specify the nodePort value for the LoadBalancer and NodePort service types.
## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport
##
# nodePort:
## Provide any additional annotations which may be required. This can be used to
## set the LoadBalancer service type to internal only.
## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer
##
annotations: {}
# metallb.universe.tf/allow-shared-ip: plex-svc
labels: {}
## Use loadBalancerIP to request a specific static IP,
## otherwise leave blank
##
loadBalancerIP:
# loadBalancerSourceRanges: []
## Set the externalTrafficPolicy in the Service to either Cluster or Local
# externalTrafficPolicy: Cluster
serviceUDP:
type: ClusterIP
## Provide any additional annotations which may be required. This can be used to
## set the LoadBalancer service type to internal only.
## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer
##
annotations: {}
# metallb.universe.tf/allow-shared-ip: plex-svc
labels: {}
## Use loadBalancerIP to request a specific static IP,
## otherwise leave blank
##
loadBalancerIP:
# loadBalancerSourceRanges: []
## Set the externalTrafficPolicy in the Service to either Cluster or Local
# externalTrafficPolicy: Cluster
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
path: /
hosts:
- chart-example.local
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
plexPreferences:
# Enable init script that will read all environment variables starting with PLEX_PREFERENCE_
# and take the value (of PLEX_PREFERENCE_<whatever>) as the Key:Value option to set in Plex Preference.xml
# You can use extraEnv to add the addtional ENV's to the container.
# NOTE: Plex preference options are camelCase and CASE SENSITIVE!
# You can do horrible things to your PLEX configuration if you are not careful.
# --set extraEnv.PLEX_PREFERENCE_1="FriendlyName=plex-kubeernetes-test1" `
# --set extraEnv.PLEX_PREFERENCE_2="EnableIPv6=0" `
# --set extraEnv.PLEX_PREFERENCE_3="logDebug=0" `
# --set extraEnv.PLEX_PREFERENCE_4="DisableTLSv1_0=1" `
# --set extraEnv.PLEX_PREFERENCE_5="LanNetworksBandwidth=xxx.xxx.xxx.0/18\,xxx.xxx.xxx.0/24\,xxx.xxx.xxx.0/24" `
# --set extraEnv.PLEX_PREFERENCE_6="TranscoderQuality=2" `
# --set extraEnv.PLEX_PREFERENCE_7="TreatWanIpAsLocal=0" `
# --set extraEnv.PLEX_PREFERENCE_8="TranscoderH264BackgroundPreset=fast"
# Why not use a single ENV?
# I thought using multiple environment variables would be less confusing
# It should work easily with CLI and value.yaml usage
# There is only minimal parsing required on the ENV value, as the only deliminator is =
# From what I can see, all the PLEX preferences that are NOT currently supported by the OFFICIAL
# Container are simple enough to work with this.
enabled: false
configmap:
labels: {}
annotations: {}
# Right now you can't really change this, additionally the configmap data is
# not configurable.
name: 41-plex-preferences
volume:
name: 41-plex-preferences
defaultMode: 493 # 0755 in octal permission notation
# Using mountPath & SubPath allow you to volume mount a configMap AS A FILE
# Unfortunately this also means that updates to the configMap are not automtically
# propagated to the file contents. But it's better then replacing the entire
# /etc/cont-init.d/ directory which is the "normal" behavior when doing volume
# mounts.
mountPath: /etc/cont-init.d/41-plex-preferences
subPath: 41-plex-preferences
hostNetwork: false
persistence:
transcode:
# We want to enable a transcode pvc
enabled: false
# Optionally specify claimName to manually override the PVC to be used for
# the transcode directory. If claimName is specified, storageClass and size
# are ignored.
## claimName: "plex-transcode-pvc"
# Optionally specify a storage class to be used for the transcode directory.
# If not specified and claimName is not specified, the default storage
# class will be used.
storageClass: ""
# subPath: some-subpath
# The requested size of the volume to be used when creating a
# PersistentVolumeClaim.
size: 20Gi
# Access mode for this volume
accessMode: ReadWriteOnce
# If not using a transcode PVC, specify emptyDir.medium="Memory" to use a tmpfs (in-memory)
# Volume for /transcode. Warning! this will greatly increase the amount of memory the plex pod is using
# AND it will count toward any ram pod/namespace limits. Additionally all data will be lost if/when the
# pod is moved to another node. --set persistence.transcode.emptyDir.medium="Memory" `
emptyDir:
medium: ""
# medium: "Memory"
data:
# We want to enable a data pvc
enabled: true
# Optionally specify claimName to manually override the PVC to be used for
# the data directory. If claimName is specified, storageClass and size are
# ignored.
## claimName: "plex-data-pvc"
# Optionally specify a storage class to be used for the data directory.
# If not specified and claimName is not specified, the default storage
# class will be used.
storageClass: ""
# subPath: some-subpath
# The requested size of the volume to be used when creating a
# PersistentVolumeClaim.
size: 40Gi
# Access mode for this volume
accessMode: ReadWriteOnce
extraData: []
# Optionally specifify additional Data mounts. These will be mounted as
# /data-${name}. This should be in the same format as the above 'data',
# with the additional field 'name'
# - claimName: "special-tv"
# name: 'foo'
# subPath: optional/sub/path
extraMounts: []
## Include additional claims that can be mounted inside the
## pod. This is useful if you wish to use different paths with categories
## Claim will me mounted as /{mountPath} if specified. If no {mountPath} is given,
## mountPath will default to {name}
# - name: video
# # if claimName is specified the a new volume will mounted, if omitted the mount will be considered to be associated with one of the standard volumes (e.g data, config, transcode).
# # This useful to mount data to a different subPath
# claimName: optional-claim
# mountPath: /mnt/path/in/pod
# subPath: optional/sub/path
config:
# Optionally specify claimName to manually override the PVC to be used for
# the config directory. If claimName is specified, storageClass and size
# are ignored.
## claimName: "plex-config-pvc"
# Optionally specify a storage class to be used for the config directory.
# If not specified and claimName is not specified, the default storage
# class will be used.
# subPath: some-subpath
storageClass: ""
# The requested size of the volume to be used when creating a
# PersistentVolumeClaim.
size: 20Gi
# Access mode for this volume
accessMode: ReadWriteOnce
# Certificate(s) in Plex
certificate:
# Assuming you have a kubernetes certificate secret (say from cert-manager) that has a tls.crt and tls.key but NO PFX!
# pkcsMangler to the rescue. The pkcsMangler part will add the supplied pfxPassword to a kubernetes secret
# This is so it's not in the clear in the YAML of the deployment in the kubernetes api.
# We will then use an OpenSSL init container to create a pfx file using the supplied secret (only available in container)
# Then we will use an init script (via configMap) to move the pfx file out of /shared (it's temporary storage) to
# the location specified in pfxInContainerPath.
pkcsMangler:
enabled: false
# The Image to use for pkcsMangler
image:
repository: tlsprint/openssl
tag: 1.1.1f
configmap:
labels: {}
annotations: {}
# Right now you can't really change this, additionally the configmap data is
# not configurable.
name: 42-pkcs-mangler
volume:
name: 42-pkcs-mangler
defaultMode: 493 # 0755 in octal permission notation
# Using mountPath & SubPath allow you to volume mount a configMap AS A FILE
# Unfortunately this also means that updates to the configMap are not automtically
# propagated to the file contents. But it's better then replacing the entire
# /etc/cont-init.d/ directory which is the "normal" behavior when doing volume
# mounts.
mountPath: /etc/cont-init.d/42-pkcs-mangler
subPath: 42-pkcs-mangler
setPlexPreferences:
enabled: true # Set Plex Preferences related to Certificates
customCertificateDomain: "" # If not empty, Set the Plex Preference customCertificateDomain
# Use spec.certificate.pkcsMangler.pfxPassword.value to Set the Plex Preference customCertificateKey
# Use spec.certificate.pkcsMangler.pfxInContainerPath to Set the Plex Preference customCertificatePath
pfxPassword:
value: "setpassword"
# We wlll create a Kubernetes Secret for spec.certificate.pkcsMangler.pfxPassword.value
# These are your options.
secretName: "plex-media-server-pfx-password"
passwordKey: "pfx-password"
labels: {}
annotations: {}
pfxInContainerPath: "/config/plex.pfx" # This is full path in the container pkcsMangler will copy the pfx file to
# This is the SSL Certificate Secret that will provide our crt and key file. If you used cert-manager to create
# the certificate, these defaults should work for you. This Secret (and volume details) are only used by the
# pkcsMangler Init Container.
certificateSecret:
name: ""
keyName: "tls.key"
crtName: "tls.crt"
volume:
name: plex-certs
mountPath: /etc/plex-certs
# Logging configuration
logging:
promtail:
enabled: false
image:
repository: grafana/promtail
tag: 1.6.0
pullPolicy: IfNotPresent
loki:
url: http://loki.logs.svc.cluster.local:3100/loki/api/v1/push
# Probes configuration
probes:
liveness:
failureThreshold: 5
periodSeconds: 10
readiness:
failureThreshold: 5
periodSeconds: 10
startup:
initialDelaySeconds: 5
failureThreshold: 30
periodSeconds: 10
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}
podAnnotations: {}
deploymentAnnotations: {}
proxy:
# This allows to set a proxy environment variable, which PMS uses to fetch the token and assets like movie cover
enabled: false
# http: "http://proxy:8080"
# https: "https://proxy:8080"
# noproxy: "localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/12"