Files
plex-deployment/README.md
T
feedc0de 1d84fb0bc4
Validate, publish and promote Plex chart / publish (push) Successful in 2s
Validate, publish and promote Plex chart / validate (push) Successful in 1s
Publish Plex chart and replace direct Kubernetes CD
2026-10-23 09:48:55 +02:00

74 lines
3.4 KiB
Markdown

# Plex on Kubernetes
This project runs the existing Plex server as a single high-performance Pod on
`arschrock` in its dedicated `plex` namespace. It is intentionally not highly
available and can never fail over to an ODROID. CPU and memory have scheduling
requests but no limits.
The 500 TB media tree stays on the host and is mounted read-only from
`/komposthaufen/multimedia`. The Pod also requires the existing `Videos`
directory and an init container verifies that the path is backed by bcachefs.
If the encrypted filesystem has not been unlocked and mounted, Plex does not
start. The Deployment also requires the explicit
`media.brunner.ninja/multimedia-ready=true` node label. The shared
`../media-storage-offline.sh` helper removes it and stops the media Pods before
unmounting; `../media-storage-online.sh` validates the mount before restoring
the label.
Persistent Plex configuration, metadata, preview images, and SQLite databases
live on the retained 160 GiB `plex-config` RBD PVC. Transcodes use node-local
ephemeral storage. The official Plex image is pinned to the same version as the
migrated Arch installation.
## One-time migration
`migrate.sh` stops the Arch service, confirms no Plex process remains, checks
both source SQLite databases, creates the PVC, and starts a one-shot copy Job:
```sh
./migrate.sh
kubectl -n plex logs -f job/plex-archlinux-migration
kubectl -n plex wait --for=condition=complete \
job/plex-archlinux-migration --timeout=12h
```
The Job refuses to overwrite a non-empty destination and compares regular-file
counts and byte totals before writing its completion marker. Copy I/O is
deliberately duty-cycle throttled so the migration cannot monopolize bcachefs
and Ceph. Do not delete the source `/var/lib/plex` tree until the Kubernetes
server has been verified and a separate backup exists.
The historical migration scripts remain for recovery; routine deployment is
owned by Argo CD. Plex remains available at
`https://plex.brunner.ninja` and directly on `192.168.0.2:32400`.
## Monitoring
The Pod contains a rootless Plex exporter. Its token is read from the migrated
`Preferences.xml` into a memory-backed volume; it is not duplicated in a
Kubernetes Secret or environment variable. A `ServiceMonitor` and alerts cover
the exporter, Plex API access, restart loops, and PVC capacity. Existing
Tautulli, node-exporter, Netdata, SMART, and bcachefs monitoring remain in use.
## Helm and GitOps
This repository owns the Plex chart: Deployment, Service, media guard,
exporter, ingress option, and monitoring. The chart preserves the existing
Deployment selector used by `media-storage-offline.sh` and
`media-storage-online.sh`. The homelab's node pin, guarded hostPath, existing
PVC, public host and resource requests are selected in the
[GitOps values](https://code.brunner.ninja/feedc0de/homelab-gitops/src/branch/main/apps/plex).
```sh
helm repo add brunner.ninja https://brunner.ninja/charts
helm repo update brunner.ninja
helm upgrade --install plex brunner.ninja/plex --namespace plex --create-namespace
```
To install this checkout manually, run `./install.sh -f my-values.yaml` with
the target namespace and media mount configured. Main-branch CI validates,
publishes the chart using the upstream application Git tag plus `git describe`,
then promotes its exact version to GitOps. CI needs `PACKAGE_USERNAME`,
`PACKAGE_TOKEN`, and `GITOPS_TOKEN`, but no kubeconfig. The Plex image is the
official upstream image and is selected by `Chart.yaml.appVersion`.