From 9cdcdf62bc8c45373cec3915209aaf9888e93a73 Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Sat, 22 Aug 2026 16:17:23 +1000 Subject: [PATCH] arrstack: provision shared Ceph RGW bucket for media assets (#387) ## Why Servarr MediaCover assets (movie/series posters and fanart) and app backups currently live on each replica's local `/config`, which is an `emptyDir`. A poster the leader downloads is invisible to the other replicas behind the Service, so covers render inconsistently and backups are leader-local. This provisions a shared Ceph RGW (S3) bucket to hold those assets instead. ## Changes - Add an `arrstack-media` `ObjectStoreUser` + `Bucket` (cephrgw-operator), mirroring the CNPG backup pattern. The operator mints the `arrstack-media-s3` credential Secret in-namespace (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `S3_ENDPOINT`), so **no Vault KV seeding is required**. - Wire the radarr Deployment to the bucket via `Radarr__MediaCover__S3__*` env (creds from the operator Secret; estate CA mounted at `/etc/ssl/vault-ca/ca.crt` for RGW TLS validation). ## Notes - The env keys are unknown to the current `-unkin2` image and are ignored by it; they activate once the `-unkin3+` image (radarr MediaCover-S3 support, separate radarr PR) ships. sonarr/prowlarr wiring and backups-to-S3 follow in later PRs. - `kubectl kustomize apps/base/arrstack` builds clean. Reviewed-on: https://git.unkin.net/unkin/argocd-apps/pulls/387 Co-authored-by: unkin-agent Co-committed-by: unkin-agent --- apps/base/arrstack/kustomization.yaml | 1 + apps/base/arrstack/media-bucket.yaml | 34 +++++++++++++++++++++ apps/base/arrstack/radarr/deployment.yaml | 37 +++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 apps/base/arrstack/media-bucket.yaml diff --git a/apps/base/arrstack/kustomization.yaml b/apps/base/arrstack/kustomization.yaml index 5015628..2f16ec7 100644 --- a/apps/base/arrstack/kustomization.yaml +++ b/apps/base/arrstack/kustomization.yaml @@ -9,6 +9,7 @@ resources: - pv-media-movies.yaml - pvc-media-tv.yaml - pvc-media-movies.yaml + - media-bucket.yaml - postgres - sonarr - radarr diff --git a/apps/base/arrstack/media-bucket.yaml b/apps/base/arrstack/media-bucket.yaml new file mode 100644 index 0000000..e9dd338 --- /dev/null +++ b/apps/base/arrstack/media-bucket.yaml @@ -0,0 +1,34 @@ +--- +# Shared Ceph RGW (S3) bucket for arrstack media assets (Servarr MediaCover +# posters/fanart and, later, application backups), provisioned by the in-estate +# cephrgw-operator. Moving these off each replica's local /config (an emptyDir) +# lets any radarr/sonarr/prowlarr replica serve covers and store backups without +# leader-local state. The operator mints the S3 credential Secret +# (arrstack-media-s3) in this namespace with keys AWS_ACCESS_KEY_ID, +# AWS_SECRET_ACCESS_KEY and S3_ENDPOINT, so no Vault KV seeding is required. +apiVersion: ceph.unkin.net/v1alpha1 +kind: ObjectStoreUser +metadata: + name: arrstack-media + namespace: arrstack +spec: + displayName: "arrstack media assets owner" + uid: arrstack-media + maxBuckets: 5 + secretName: arrstack-media-s3 + retainOnDelete: true +--- +apiVersion: ceph.unkin.net/v1alpha1 +kind: Bucket +metadata: + name: arrstack-media + namespace: arrstack +spec: + placementTarget: ec + bucketName: arrstack-media + ownerRef: arrstack-media + versioning: false + tags: + app: arrstack + purpose: media-assets + retainOnDelete: true diff --git a/apps/base/arrstack/radarr/deployment.yaml b/apps/base/arrstack/radarr/deployment.yaml index a19e944..7924997 100644 --- a/apps/base/arrstack/radarr/deployment.yaml +++ b/apps/base/arrstack/radarr/deployment.yaml @@ -98,6 +98,33 @@ spec: secretKeyRef: name: radarr-apikey key: apitoken + # MediaCover object store (shared Ceph RGW bucket). Serves posters/fanart + # from S3 so any replica can render them instead of the leader-local + # emptyDir /config. Consumed by the -unkin3+ image; older images ignore + # these unknown config keys. Creds Secret is minted by cephrgw-operator. + - name: Radarr__MediaCover__S3__Endpoint + valueFrom: + secretKeyRef: + name: arrstack-media-s3 + key: S3_ENDPOINT + - name: Radarr__MediaCover__S3__AccessKey + valueFrom: + secretKeyRef: + name: arrstack-media-s3 + key: AWS_ACCESS_KEY_ID + - name: Radarr__MediaCover__S3__SecretKey + valueFrom: + secretKeyRef: + name: arrstack-media-s3 + key: AWS_SECRET_ACCESS_KEY + - name: Radarr__MediaCover__S3__Bucket + value: arrstack-media + - name: Radarr__MediaCover__S3__Prefix + value: radarr + - name: Radarr__MediaCover__S3__ForcePathStyle + value: "true" + - name: Radarr__MediaCover__S3__CaCertPath + value: /etc/ssl/vault-ca/ca.crt livenessProbe: httpGet: path: /radarr/ping @@ -126,9 +153,19 @@ spec: mountPath: /config - name: media-movies mountPath: /media/movies + - name: vault-ca + mountPath: /etc/ssl/vault-ca + readOnly: true volumes: - name: config emptyDir: {} - name: media-movies persistentVolumeClaim: claimName: media-movies + # Estate CA for validating the Ceph RGW (s3.ceph.unkin.net) TLS cert. + - name: vault-ca + secret: + secretName: vault-ca-cert + items: + - key: ca.crt + path: ca.crt