Kubernetes
On Kubernetes, every sensitive setting lives in a Secret resource and reaches the Deployment through secretKeyRef, so no sensitive values appear in the Deployment manifest itself.
Injecting Secrets via Kubernetes Secret
Section titled “Injecting Secrets via Kubernetes Secret”Create the sovereign-secrets Secret before the Deployment. Keep this file outside of version control, or use a secrets management tool (see the tip below).
apiVersion: v1kind: Secretmetadata: name: sovereign-secretstype: OpaquestringData: admin-username: admin admin-password: Admin1! asset-security-key: <32-char-secret> radarr-api-key: <radarr-api-key> sonarr-api-key: <sonarr-api-key>Or create it from the command line, without a manifest file:
kubectl create secret generic sovereign-secrets \ --from-literal=admin-username=admin \ --from-literal=admin-password=Admin1! \ --from-literal=asset-security-key=<32-char-secret> \ --from-literal=radarr-api-key=<radarr-api-key> \ --from-literal=sonarr-api-key=<sonarr-api-key>Deployment Manifest
Section titled “Deployment Manifest”apiVersion: v1kind: PersistentVolumeClaimmetadata: name: sovereign-dataspec: accessModes: - ReadWriteOnce resources: requests: storage: 256Gi # transcodes are packaged here well ahead of playback; see System Requirements---apiVersion: apps/v1kind: Deploymentmetadata: name: sovereign labels: app: sovereignspec: replicas: 1 strategy: type: Recreate # one SQLite database on one volume: never run two pods at once selector: matchLabels: app: sovereign template: metadata: labels: app: sovereign spec: securityContext: fsGroup: 1654 # the non-root user Sovereign runs as containers: - name: sovereign image: <sovereign-image>:<version> ports: - containerPort: 5000 readinessProbe: httpGet: path: /health port: 5000 env: # Non-sensitive configuration - declared inline # The public HTTPS address your ingress serves, as users type it - name: Sovereign__Authentication__Issuer value: 'https://media.example.com/' # Your cluster's pod network, where the ingress controller's requests come from - name: Sovereign__Network__TrustedProxyNetwork__0 value: '10.244.0.0/16' - name: Sovereign__DataSources__Radarr__0__Url value: 'http://radarr:7878' - name: Sovereign__DataSources__Sonarr__0__Url value: 'http://sonarr:8989' # Sensitive values - injected from the sovereign-secrets Secret - name: Sovereign__Authentication__AdminUsername valueFrom: secretKeyRef: name: sovereign-secrets key: admin-username - name: Sovereign__Authentication__AdminPassword valueFrom: secretKeyRef: name: sovereign-secrets key: admin-password - name: Sovereign__Obfuscation__AssetSecuritySecretKey valueFrom: secretKeyRef: name: sovereign-secrets key: asset-security-key - name: Sovereign__DataSources__Radarr__0__ApiKey valueFrom: secretKeyRef: name: sovereign-secrets key: radarr-api-key - name: Sovereign__DataSources__Sonarr__0__ApiKey valueFrom: secretKeyRef: name: sovereign-secrets key: sonarr-api-key volumeMounts: - name: sovereign-data mountPath: /sovereign-data - name: media mountPath: /media readOnly: true volumes: - name: sovereign-data persistentVolumeClaim: claimName: sovereign-data - name: media hostPath: # single-node/dev only - use NFS CSI driver for multi-node clusters path: /path/to/media---apiVersion: v1kind: Servicemetadata: name: sovereignspec: selector: app: sovereign ports: - port: 5000 targetPort: 5000Apply both files:
kubectl apply -f sovereign-secrets.yamlkubectl apply -f sovereign.yamlReplace <sovereign-image> and <version> with the image and the release you’re deploying, as the Docker page describes. Sovereign doesn’t terminate TLS, so route your ingress to the sovereign Service on port 5000 and set the issuer to the address the ingress serves. Left at a localhost address, nobody outside the pod can sign in. The ingress controller reaches the pod from an address in your cluster’s pod network, so set the trusted proxy network to that range (10.244.0.0/16 is a common default, and k3s uses 10.42.0.0/16). Without it, every user is recorded as the ingress controller and they all share one sign-in rate limit; see Trusted Proxy Networks. /health answers without authentication once startup has finished, which is what the readiness probe waits for.
The container runs as a non-root user (UID 1654), and Sovereign creates its directories on the data volume when it starts. fsGroup makes the volume writable by that user on storage that supports it. Without it, a volume that mounts owned by root stops the server at startup with an access-denied error.
NFS Media Storage
Section titled “NFS Media Storage”Kubernetes can’t provision NFS volumes dynamically on its own, so install the NFS CSI Driver for Kubernetes in your cluster before using an NFS share as a PersistentVolume. The NFS Subdir External Provisioner is an alternative if the CSI driver doesn’t suit your environment.
Once the CSI driver is running, replace the hostPath volume in the Deployment with a PersistentVolumeClaim backed by an NFS StorageClass:
apiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: nfs-mediaprovisioner: nfs.csi.k8s.ioparameters: server: <nfs-server-ip> share: /path/to/mediareclaimPolicy: RetainvolumeBindingMode: ImmediatemountOptions: - nfsvers=4.1 - ro - soft - timeo=100 - retrans=2 - rsize=1048576 - wsize=1048576 - nconnect=4 - actimeo=60---apiVersion: v1kind: PersistentVolumeClaimmetadata: name: sovereign-mediaspec: storageClassName: nfs-media accessModes: - ReadOnlyMany resources: requests: storage: 1TiThen update the volumes section of the Deployment:
volumes: - name: sovereign-data persistentVolumeClaim: claimName: sovereign-data - name: media persistentVolumeClaim: claimName: sovereign-mediaThe mountOptions above are explained option by option on the NFS Media Storage page, along with why the share should be mounted read-only and made to fail fast.
Hardware Acceleration
Section titled “Hardware Acceleration”See Hardware Acceleration for the resource limit snippets that expose an NVIDIA or Intel GPU to the container in Kubernetes.
Titles, artwork, people and descriptions shown in screenshots are fictional and were created for illustration. Sovereign doesn't include or supply any media: it plays the library you bring.