diff --git a/apps/base/arrstack/kustomization.yaml b/apps/base/arrstack/kustomization.yaml index e14ec46..f975b7d 100644 --- a/apps/base/arrstack/kustomization.yaml +++ b/apps/base/arrstack/kustomization.yaml @@ -15,12 +15,12 @@ resources: - backups-bucket.yaml - postgres - valkey - - sonarr - - radarr - prowlarr - - nzbget - sonarr-kids - radarr-kids - nzbget-kids + - sonarr-adult + - radarr-adult + - nzbget-adult - arrproxy - mediamover diff --git a/apps/base/arrstack/nzbget/deployment.yaml b/apps/base/arrstack/nzbget-adult/deployment.yaml similarity index 73% rename from apps/base/arrstack/nzbget/deployment.yaml rename to apps/base/arrstack/nzbget-adult/deployment.yaml index 0fbd16f..38ee800 100644 --- a/apps/base/arrstack/nzbget/deployment.yaml +++ b/apps/base/arrstack/nzbget-adult/deployment.yaml @@ -2,7 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: nzbget + name: nzbget-adult namespace: arrstack spec: replicas: 1 @@ -11,25 +11,25 @@ spec: type: Recreate selector: matchLabels: - app: nzbget + app: nzbget-adult template: metadata: labels: - app: nzbget + app: nzbget-adult spec: securityContext: fsGroup: 1000 fsGroupChangePolicy: OnRootMismatch initContainers: - # Seed download layout onto the shared media PVCs (not /config or an - # emptyDir) so completed downloads land beside the arr libraries and - # imports are same-filesystem hardlink moves. Reuses the image's own - # template (inherits correct WebDir/ConfigTemplate) and appends the - # path/category overrides once; nzbget honours the last value for a - # repeated option, and the grep guard keeps re-runs idempotent so admin - # UI edits to the persisted /config/nzbget.conf survive restarts. + # Seed download layout onto the adult media subtrees (not /config or an + # emptyDir) so completed adult downloads land beside the adult arr libraries + # and imports are same-filesystem hardlink moves. The media mounts use the + # tvshows/adult and movies/adult subPaths, so the in-container paths match + # the kids nzbget while the data stays scoped to the adult subtree. Reuses + # the image's own template and appends the path/category overrides once; + # the grep guard keeps re-runs idempotent so admin UI edits survive. - name: seed-config - image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/linuxserver/nzbget:version-v26.2 + image: docker.io/linuxserver/nzbget:version-v26.2 command: - sh - -c @@ -42,11 +42,12 @@ spec: cat >> /config/nzbget.conf << 'CONF' # arrstack-managed download layout (appended once; last value wins). - # Downloads land on the shared media PVCs by category so sonarr/radarr - # import with atomic hardlink moves (download dir + library share one - # filesystem per media type). InterDir is empty: nzbget writes each - # download straight into its category DestDir, so BOTH tv and movies - # stay on their own PVC with no cross-filesystem intermediate copy. + # Downloads land on the shared media PVCs by category so sonarr-adult/ + # radarr-adult import with atomic hardlink moves (download dir + + # library share one filesystem per media type). InterDir is empty: + # nzbget writes each download straight into its category DestDir, so + # BOTH tv and movies stay on their own PVC with no cross-filesystem + # intermediate copy. MainDir=/media/tv InterDir= DestDir=/media/tv/downloads @@ -77,11 +78,13 @@ spec: mountPath: /config - name: media-tv mountPath: /media/tv + subPath: tvshows/adult - name: media-movies mountPath: /media/movies + subPath: movies/adult containers: - name: nzbget - image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/linuxserver/nzbget:version-v26.2 + image: docker.io/linuxserver/nzbget:version-v26.2 imagePullPolicy: IfNotPresent ports: - name: http @@ -123,12 +126,14 @@ spec: mountPath: /config - name: media-tv mountPath: /media/tv + subPath: tvshows/adult - name: media-movies mountPath: /media/movies + subPath: movies/adult volumes: - name: config persistentVolumeClaim: - claimName: nzbget-config + claimName: nzbget-adult-config - name: media-tv persistentVolumeClaim: claimName: media-tv diff --git a/apps/base/arrstack/nzbget/kustomization.yaml b/apps/base/arrstack/nzbget-adult/kustomization.yaml similarity index 79% rename from apps/base/arrstack/nzbget/kustomization.yaml rename to apps/base/arrstack/nzbget-adult/kustomization.yaml index a7f5633..ed46412 100644 --- a/apps/base/arrstack/nzbget/kustomization.yaml +++ b/apps/base/arrstack/nzbget-adult/kustomization.yaml @@ -6,5 +6,3 @@ resources: - pvc-config.yaml - deployment.yaml - service.yaml - - gateway.yaml - - httproute.yaml diff --git a/apps/base/arrstack/nzbget-adult/pvc-config.yaml b/apps/base/arrstack/nzbget-adult/pvc-config.yaml new file mode 100644 index 0000000..4717e05 --- /dev/null +++ b/apps/base/arrstack/nzbget-adult/pvc-config.yaml @@ -0,0 +1,16 @@ +--- +# NZBGet (adult) config + queue/temp state. RWO on cephrbd (block, fast-delete). +# The download data itself lives on the shared media PVCs, not here. +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: nzbget-adult-config + namespace: arrstack +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + storageClassName: cephrbd-fast-delete + volumeMode: Filesystem diff --git a/apps/base/arrstack/nzbget/service.yaml b/apps/base/arrstack/nzbget-adult/service.yaml similarity index 81% rename from apps/base/arrstack/nzbget/service.yaml rename to apps/base/arrstack/nzbget-adult/service.yaml index 43e29f4..1482ed1 100644 --- a/apps/base/arrstack/nzbget/service.yaml +++ b/apps/base/arrstack/nzbget-adult/service.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Service metadata: - name: nzbget + name: nzbget-adult namespace: arrstack spec: ports: @@ -11,5 +11,5 @@ spec: protocol: TCP targetPort: http selector: - app: nzbget + app: nzbget-adult type: ClusterIP diff --git a/apps/base/arrstack/nzbget/gateway.yaml b/apps/base/arrstack/nzbget/gateway.yaml deleted file mode 100644 index a0e42e5..0000000 --- a/apps/base/arrstack/nzbget/gateway.yaml +++ /dev/null @@ -1,37 +0,0 @@ ---- -apiVersion: gateway.networking.k8s.io/v1 -kind: Gateway -metadata: - labels: - traefik.io/instance: internal - annotations: - cert-manager.io/cluster-issuer: vault-issuer - cert-manager.io/common-name: nzbget.k8s.syd1.au.unkin.net - cert-manager.io/private-key-size: "4096" - external-dns.alpha.kubernetes.io/hostname: nzbget.k8s.syd1.au.unkin.net - external-dns.alpha.kubernetes.io/target: 198.18.200.4 - name: nzbget - namespace: arrstack -spec: - gatewayClassName: traefik-internal - listeners: - - allowedRoutes: - namespaces: - from: Same - hostname: nzbget.k8s.syd1.au.unkin.net - name: http - port: 80 - protocol: HTTP - - allowedRoutes: - namespaces: - from: Same - hostname: nzbget.k8s.syd1.au.unkin.net - name: https - port: 443 - protocol: HTTPS - tls: - certificateRefs: - - group: "" - kind: Secret - name: nzbget-tls - mode: Terminate diff --git a/apps/base/arrstack/nzbget/httproute.yaml b/apps/base/arrstack/nzbget/httproute.yaml deleted file mode 100644 index b4aa2fb..0000000 --- a/apps/base/arrstack/nzbget/httproute.yaml +++ /dev/null @@ -1,49 +0,0 @@ ---- -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: nzbget-http-redirect - namespace: arrstack -spec: - hostnames: - - nzbget.k8s.syd1.au.unkin.net - parentRefs: - - group: gateway.networking.k8s.io - kind: Gateway - name: nzbget - sectionName: http - rules: - - filters: - - type: RequestRedirect - requestRedirect: - scheme: https - statusCode: 301 - matches: - - path: - type: PathPrefix - value: / ---- -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: nzbget-route - namespace: arrstack -spec: - hostnames: - - nzbget.k8s.syd1.au.unkin.net - parentRefs: - - group: gateway.networking.k8s.io - kind: Gateway - name: nzbget - sectionName: https - rules: - - backendRefs: - - group: "" - kind: Service - name: nzbget - port: 6789 - weight: 1 - matches: - - path: - type: PathPrefix - value: / diff --git a/apps/base/arrstack/nzbget/pvc-config.yaml b/apps/base/arrstack/nzbget/pvc-config.yaml deleted file mode 100644 index 52c365b..0000000 --- a/apps/base/arrstack/nzbget/pvc-config.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -# NZBGet config + queue/temp state. RWO on cephrbd (block). Retain: this is -# state. The download data itself lives on the shared media PVCs, not here. -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: nzbget-config - namespace: arrstack -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 5Gi - storageClassName: cephrbd-fast-retain - volumeMode: Filesystem diff --git a/apps/base/arrstack/postgres/cnpg_cluster.yaml b/apps/base/arrstack/postgres/cnpg_cluster.yaml index 0240dbe..3e73c54 100644 --- a/apps/base/arrstack/postgres/cnpg_cluster.yaml +++ b/apps/base/arrstack/postgres/cnpg_cluster.yaml @@ -50,30 +50,6 @@ spec: owner: app managed: roles: - - name: sonarr - ensure: present - comment: Sonarr application role (owns sonarr-main) - login: true - superuser: false - createdb: false - createrole: false - inherit: true - replication: false - connectionLimit: -1 - passwordSecret: - name: sonarr-db - - name: radarr - ensure: present - comment: Radarr application role (owns radarr-main) - login: true - superuser: false - createdb: false - createrole: false - inherit: true - replication: false - connectionLimit: -1 - passwordSecret: - name: radarr-db - name: prowlarr ensure: present comment: Prowlarr application role (owns prowlarr-main) @@ -110,6 +86,30 @@ spec: connectionLimit: -1 passwordSecret: name: radarr-kids-db + - name: sonarr-adult + ensure: present + comment: Sonarr (adult) application role (owns sonarr-adult-main) + login: true + superuser: false + createdb: false + createrole: false + inherit: true + replication: false + connectionLimit: -1 + passwordSecret: + name: sonarr-adult-db + - name: radarr-adult + ensure: present + comment: Radarr (adult) application role (owns radarr-adult-main) + login: true + superuser: false + createdb: false + createrole: false + inherit: true + replication: false + connectionLimit: -1 + passwordSecret: + name: radarr-adult-db enablePDB: true enableSuperuserAccess: false failoverDelay: 0 diff --git a/apps/base/arrstack/postgres/database-radarr-adult.yaml b/apps/base/arrstack/postgres/database-radarr-adult.yaml new file mode 100644 index 0000000..4689a37 --- /dev/null +++ b/apps/base/arrstack/postgres/database-radarr-adult.yaml @@ -0,0 +1,15 @@ +--- +# Per-app database owned by the radarr-adult managed role. The fork's provider +# runs its own schema migrations on first start (advisory-locked, so only one +# replica migrates). retain: the database survives a Database CRD delete. +apiVersion: postgresql.cnpg.io/v1 +kind: Database +metadata: + name: radarr-adult-main + namespace: arrstack +spec: + cluster: + name: arrstack-postgres + name: radarr-adult-main + owner: radarr-adult + databaseReclaimPolicy: retain diff --git a/apps/base/arrstack/postgres/database-radarr.yaml b/apps/base/arrstack/postgres/database-radarr.yaml deleted file mode 100644 index e30da8f..0000000 --- a/apps/base/arrstack/postgres/database-radarr.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -# Per-app database owned by the radarr managed role. The fork's provider runs its -# own schema migrations on first start (advisory-locked, so only one replica -# migrates). retain: the database survives a Database CRD delete. -apiVersion: postgresql.cnpg.io/v1 -kind: Database -metadata: - name: radarr-main - namespace: arrstack -spec: - cluster: - name: arrstack-postgres - name: radarr-main - owner: radarr - databaseReclaimPolicy: retain diff --git a/apps/base/arrstack/postgres/database-sonarr-adult.yaml b/apps/base/arrstack/postgres/database-sonarr-adult.yaml new file mode 100644 index 0000000..f19c24c --- /dev/null +++ b/apps/base/arrstack/postgres/database-sonarr-adult.yaml @@ -0,0 +1,15 @@ +--- +# Per-app database owned by the sonarr-adult managed role. The fork's provider +# runs its own schema migrations on first start (advisory-locked, so only one +# replica migrates). retain: the database survives a Database CRD delete. +apiVersion: postgresql.cnpg.io/v1 +kind: Database +metadata: + name: sonarr-adult-main + namespace: arrstack +spec: + cluster: + name: arrstack-postgres + name: sonarr-adult-main + owner: sonarr-adult + databaseReclaimPolicy: retain diff --git a/apps/base/arrstack/postgres/database-sonarr.yaml b/apps/base/arrstack/postgres/database-sonarr.yaml deleted file mode 100644 index aa9f521..0000000 --- a/apps/base/arrstack/postgres/database-sonarr.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -# Per-app database owned by the sonarr managed role. The fork's provider runs its -# own schema migrations on first start (advisory-locked, so only one replica -# migrates). retain: the database survives a Database CRD delete. -apiVersion: postgresql.cnpg.io/v1 -kind: Database -metadata: - name: sonarr-main - namespace: arrstack -spec: - cluster: - name: arrstack-postgres - name: sonarr-main - owner: sonarr - databaseReclaimPolicy: retain diff --git a/apps/base/arrstack/postgres/kustomization.yaml b/apps/base/arrstack/postgres/kustomization.yaml index 13dbd95..4fd42b9 100644 --- a/apps/base/arrstack/postgres/kustomization.yaml +++ b/apps/base/arrstack/postgres/kustomization.yaml @@ -6,8 +6,8 @@ resources: - vaultstaticsecret.yaml - cnpg_cluster.yaml - cnpg_backup.yaml - - database-sonarr.yaml - - database-radarr.yaml - database-prowlarr.yaml - database-sonarr-kids.yaml - database-radarr-kids.yaml + - database-sonarr-adult.yaml + - database-radarr-adult.yaml diff --git a/apps/base/arrstack/postgres/vaultstaticsecret.yaml b/apps/base/arrstack/postgres/vaultstaticsecret.yaml index bfab34b..2fbe9b8 100644 --- a/apps/base/arrstack/postgres/vaultstaticsecret.yaml +++ b/apps/base/arrstack/postgres/vaultstaticsecret.yaml @@ -10,40 +10,6 @@ # (wave 1) reconciles the roles. apiVersion: secrets.hashicorp.com/v1beta1 kind: VaultStaticSecret -metadata: - name: sonarr-db - namespace: arrstack -spec: - destination: - create: true - name: sonarr-db - overwrite: true - hmacSecretData: true - mount: kv - path: kubernetes/namespace/arrstack/default/sonarr-db - refreshAfter: 5m - type: kv-v2 - vaultAuthRef: default ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: radarr-db - namespace: arrstack -spec: - destination: - create: true - name: radarr-db - overwrite: true - hmacSecretData: true - mount: kv - path: kubernetes/namespace/arrstack/default/radarr-db - refreshAfter: 5m - type: kv-v2 - vaultAuthRef: default ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret metadata: name: prowlarr-db namespace: arrstack @@ -92,3 +58,37 @@ spec: refreshAfter: 5m type: kv-v2 vaultAuthRef: default +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: sonarr-adult-db + namespace: arrstack +spec: + destination: + create: true + name: sonarr-adult-db + overwrite: true + hmacSecretData: true + mount: kv + path: kubernetes/namespace/arrstack/default/sonarr-adult-db + refreshAfter: 5m + type: kv-v2 + vaultAuthRef: default +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: radarr-adult-db + namespace: arrstack +spec: + destination: + create: true + name: radarr-adult-db + overwrite: true + hmacSecretData: true + mount: kv + path: kubernetes/namespace/arrstack/default/radarr-adult-db + refreshAfter: 5m + type: kv-v2 + vaultAuthRef: default diff --git a/apps/base/arrstack/radarr-adult/configmap.yaml b/apps/base/arrstack/radarr-adult/configmap.yaml new file mode 100644 index 0000000..3dfea17 --- /dev/null +++ b/apps/base/arrstack/radarr-adult/configmap.yaml @@ -0,0 +1,25 @@ +--- +# Non-secret env for the -unkin2 fork (adult tier). Identical mechanism to the +# kids radarr, pointed at its own shared-Postgres database (radarr-adult-main) +# and its own UrlBase (/3aa168/radarr) so arrproxy path-routing reaches the adult +# instance separately. Shares the one arrstack Valkey (keys namespaced by the +# fork's radarr:ratelimit: prefix). User/Password/ApiKey come from Secrets (see +# deployment.yaml), not here. +apiVersion: v1 +kind: ConfigMap +metadata: + name: radarr-adult-env + namespace: arrstack +data: + Radarr__Postgres__Host: arrstack-postgres-rw.arrstack.svc.cluster.local + Radarr__Postgres__Port: "5432" + Radarr__Postgres__MainDb: radarr-adult-main + Radarr__Log__DbEnabled: "false" + Radarr__Auth__Method: External + Radarr__Auth__Required: DisabledForLocalAddresses + Radarr__App__InstanceName: Radarr + Radarr__Server__Port: "7878" + Radarr__Server__UrlBase: /3aa168/radarr + Radarr__Update__Mechanism: External + Radarr__Redis__Host: valkey-arrstack-valkey.arrstack.svc.cluster.local + Radarr__Redis__Port: "6379" diff --git a/apps/base/arrstack/radarr/deployment.yaml b/apps/base/arrstack/radarr-adult/deployment.yaml similarity index 74% rename from apps/base/arrstack/radarr/deployment.yaml rename to apps/base/arrstack/radarr-adult/deployment.yaml index a802326..dee8d6f 100644 --- a/apps/base/arrstack/radarr/deployment.yaml +++ b/apps/base/arrstack/radarr-adult/deployment.yaml @@ -2,43 +2,40 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: radarr + name: radarr-adult namespace: arrstack annotations: - # radarr-env is a plain (unhashed) ConfigMap consumed by fixed-name envFrom, - # so editing it does not roll the Deployment on its own. Reloader watches the - # referenced ConfigMap and triggers a rolling restart on change, so adding the - # Redis env activates the #14 features on the next ArgoCD sync without a manual - # `rollout restart`. + # Reloader rolls the Deployment when radarr-adult-env changes (plain envFrom + # ConfigMap does not trigger a rollout on its own). configmap.reloader.stakater.com/auto: "true" spec: # Active-active: the -unkin2 fork keeps all state in the shared Postgres # (arrstack-postgres) and coordinates via Postgres advisory locks, so N - # replicas run concurrently behind the radarr Service. RollingUpdate is safe — - # no SQLite, no RWO lock. + # replicas run concurrently behind the radarr-adult Service. RollingUpdate is + # safe — no SQLite, no RWO lock. replicas: 3 strategy: type: RollingUpdate selector: matchLabels: - app: radarr + app: radarr-adult template: metadata: labels: - app: radarr + app: radarr-adult spec: securityContext: - # Fork image has no USER (runs as root by default); pin it to a non-root - # UID and group-write the shared RWX CephFS /config (MediaCover etc.). - # OnRootMismatch avoids a recursive chown of the whole media tree. + # Fork image has no USER; pin it to a non-root UID and group-write the + # shared RWX CephFS media subtree. OnRootMismatch avoids a recursive + # chown of the whole media tree. runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 fsGroupChangePolicy: OnRootMismatch initContainers: - # Gate the app on its own Postgres database+role being reachable, instead - # of relying on ArgoCD sync-waves (which deadlock if apps aren't Healthy). - # waitfordb reads the PG* env as a libpq fallback, so the password never lands in argv. + # Gate the app on its own Postgres database+role being reachable. + # waitfordb reads the PG* env as a libpq fallback, so the password never + # lands in argv. - name: wait-for-db image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/waitfordb:v0.1.0 env: @@ -51,16 +48,16 @@ spec: - name: PGPORT value: "5432" - name: PGDATABASE - value: radarr-main + value: radarr-adult-main - name: PGUSER valueFrom: secretKeyRef: - name: radarr-db + name: radarr-adult-db key: username - name: PGPASSWORD valueFrom: secretKeyRef: - name: radarr-db + name: radarr-adult-db key: password resources: requests: @@ -78,9 +75,8 @@ spec: args: - -nobrowser - -data=/config - # Required: bypass the single-instance guard so multiple replicas - # can share one /config. Cross-replica safety is the Postgres layer, - # not a local lock file. + # Bypass the single-instance guard so multiple replicas can share one + # /config. Cross-replica safety is the Postgres layer, not a lock file. - -nosingleinstancecheck ports: - name: http @@ -88,27 +84,25 @@ spec: protocol: TCP envFrom: - configMapRef: - name: radarr-env + name: radarr-adult-env env: - name: Radarr__Postgres__User valueFrom: secretKeyRef: - name: radarr-db + name: radarr-adult-db key: username - name: Radarr__Postgres__Password valueFrom: secretKeyRef: - name: radarr-db + name: radarr-adult-db key: password - name: Radarr__Auth__ApiKey valueFrom: secretKeyRef: - name: radarr-apikey + name: radarr-adult-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. + # MediaCover object store (shared arrstack-media Ceph RGW bucket, + # partitioned by the radarr-adult key prefix). - name: Radarr__MediaCover__S3__Endpoint valueFrom: secretKeyRef: @@ -127,14 +121,13 @@ spec: - name: Radarr__MediaCover__S3__Bucket value: arrstack-media - name: Radarr__MediaCover__S3__Prefix - value: radarr + value: radarr-adult - name: Radarr__MediaCover__S3__ForcePathStyle value: "true" - name: Radarr__MediaCover__S3__CaCertPath value: /etc/ssl/vault-ca/ca.crt # Backup object store (shared arrstack-backups Ceph RGW bucket, - # per-app key prefix). Routes the periodic config+DB zip backups off - # the ephemeral /config so any replica can write and restore them. + # partitioned by the radarr-adult key prefix). - name: Radarr__BackupS3__Endpoint valueFrom: secretKeyRef: @@ -153,14 +146,14 @@ spec: - name: Radarr__BackupS3__Bucket value: arrstack-backups - name: Radarr__BackupS3__Prefix - value: radarr + value: radarr-adult - name: Radarr__BackupS3__ForcePathStyle value: "true" - name: Radarr__BackupS3__CaCertPath value: /etc/ssl/vault-ca/ca.crt livenessProbe: httpGet: - path: /radarr/ping + path: /3aa168/radarr/ping port: http initialDelaySeconds: 30 periodSeconds: 30 @@ -168,7 +161,7 @@ spec: failureThreshold: 3 readinessProbe: httpGet: - path: /radarr/ping + path: /3aa168/radarr/ping port: http initialDelaySeconds: 10 periodSeconds: 10 @@ -184,28 +177,31 @@ spec: volumeMounts: - name: config mountPath: /config + # Adult movies subtree of the shared media-movies PVC (same CephFS + # subvolume the kids radarr writes and jellyfin reads). - name: media-movies mountPath: /media/movies + subPath: movies/adult - name: vault-ca mountPath: /etc/ssl/vault-ca readOnly: true # exportarr sidecar: polls the local replica's API and exposes Prometheus - # metrics on :9708 (scraped by the radarr-exportarr VMPodScrape). + # metrics on :9708 (scraped by the radarr-adult-exportarr VMPodScrape). - name: exportarr - image: artifactapi.k8s.syd1.au.unkin.net/ghcr/onedr0p/exportarr:v2.3.0 + image: ghcr.io/onedr0p/exportarr:v2.3.0 imagePullPolicy: IfNotPresent args: - radarr env: - name: PORT value: "9708" - # URL includes the /radarr UrlBase (Radarr__Server__UrlBase). + # URL includes the /3aa168/radarr UrlBase (Radarr__Server__UrlBase). - name: URL - value: http://localhost:7878/radarr + value: http://localhost:7878/3aa168/radarr - name: APIKEY valueFrom: secretKeyRef: - name: radarr-apikey + name: radarr-adult-apikey key: apitoken ports: - name: metrics diff --git a/apps/base/arrstack/sonarr/kustomization.yaml b/apps/base/arrstack/radarr-adult/kustomization.yaml similarity index 83% rename from apps/base/arrstack/sonarr/kustomization.yaml rename to apps/base/arrstack/radarr-adult/kustomization.yaml index 8789f80..5ab2110 100644 --- a/apps/base/arrstack/sonarr/kustomization.yaml +++ b/apps/base/arrstack/radarr-adult/kustomization.yaml @@ -7,6 +7,4 @@ resources: - configmap.yaml - deployment.yaml - service.yaml - - gateway.yaml - - httproute.yaml - vmpodscrape.yaml diff --git a/apps/base/arrstack/radarr/service.yaml b/apps/base/arrstack/radarr-adult/service.yaml similarity index 81% rename from apps/base/arrstack/radarr/service.yaml rename to apps/base/arrstack/radarr-adult/service.yaml index 08d154f..656979f 100644 --- a/apps/base/arrstack/radarr/service.yaml +++ b/apps/base/arrstack/radarr-adult/service.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Service metadata: - name: radarr + name: radarr-adult namespace: arrstack spec: ports: @@ -11,5 +11,5 @@ spec: protocol: TCP targetPort: http selector: - app: radarr + app: radarr-adult type: ClusterIP diff --git a/apps/base/arrstack/radarr-adult/vaultstaticsecret.yaml b/apps/base/arrstack/radarr-adult/vaultstaticsecret.yaml new file mode 100644 index 0000000..5ee6760 --- /dev/null +++ b/apps/base/arrstack/radarr-adult/vaultstaticsecret.yaml @@ -0,0 +1,25 @@ +--- +# radarr-adult API key. Seeded out-of-band at +# kv/kubernetes/namespace/arrstack/default/radarr-adult (key: apitoken); the +# default k8s role's templated policy already grants read on +# kv/data/kubernetes/namespace/{{sa_namespace}}/{{sa_name}}/* for the +# arrstack/default ServiceAccount, so no terraform-vault change is needed. VSO +# syncs it into the radarr-adult-apikey Secret consumed by the Deployment. +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: radarr-adult-apikey + namespace: arrstack + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + destination: + create: true + name: radarr-adult-apikey + overwrite: true + hmacSecretData: true + mount: kv + path: kubernetes/namespace/arrstack/default/radarr-adult + refreshAfter: 5m + type: kv-v2 + vaultAuthRef: default diff --git a/apps/base/arrstack/radarr/vmpodscrape.yaml b/apps/base/arrstack/radarr-adult/vmpodscrape.yaml similarity index 54% rename from apps/base/arrstack/radarr/vmpodscrape.yaml rename to apps/base/arrstack/radarr-adult/vmpodscrape.yaml index 097f571..8abaab8 100644 --- a/apps/base/arrstack/radarr/vmpodscrape.yaml +++ b/apps/base/arrstack/radarr-adult/vmpodscrape.yaml @@ -1,16 +1,16 @@ --- -# Scrape the exportarr sidecar (:9708) on every radarr pod. Picked up by the +# Scrape the exportarr sidecar (:9708) on every radarr-adult pod. Picked up by the # observability VMAgent (selectAllByDefault). Pod-level rather than -# VMServiceScrape because the radarr Service doesn't expose the metrics port. +# VMServiceScrape because the radarr-adult Service doesn't expose the metrics port. apiVersion: operator.victoriametrics.com/v1beta1 kind: VMPodScrape metadata: - name: radarr-exportarr + name: radarr-adult-exportarr namespace: arrstack spec: selector: matchLabels: - app: radarr + app: radarr-adult podMetricsEndpoints: - port: metrics path: /metrics diff --git a/apps/base/arrstack/radarr/configmap.yaml b/apps/base/arrstack/radarr/configmap.yaml deleted file mode 100644 index 17eedce..0000000 --- a/apps/base/arrstack/radarr/configmap.yaml +++ /dev/null @@ -1,33 +0,0 @@ ---- -# Non-secret env for the -unkin2 fork. The fork reads Servarr config from -# Radarr__
__ env (no config.xml edits, no s6/PUID). Postgres wiring -# points every replica at the same shared DB (arrstack-postgres-rw / radarr-main); -# Auth__Method=External defers UI auth to arrproxy/oauth2-proxy; Server__UrlBase -# keeps the /radarr prefix so arrproxy path-routing works; App__InstanceName is -# identical across replicas (shared session-cookie name). User/Password/ApiKey -# come from Secrets (see deployment.yaml), not here. -apiVersion: v1 -kind: ConfigMap -metadata: - name: radarr-env - namespace: arrstack -data: - Radarr__Postgres__Host: arrstack-postgres-rw.arrstack.svc.cluster.local - Radarr__Postgres__Port: "5432" - Radarr__Postgres__MainDb: radarr-main - Radarr__Log__DbEnabled: "false" - Radarr__Auth__Method: External - Radarr__Auth__Required: DisabledForLocalAddresses - Radarr__App__InstanceName: Radarr - Radarr__Server__Port: "7878" - Radarr__Server__UrlBase: /radarr - Radarr__Update__Mechanism: External - # Shared arrstack Valkey (valkey-operator). Setting Host is what activates the - # fork's #14 Redis features (SignalR backplane, cross-replica cache-invalidation - # bus, distributed rate limiter): RedisOptions.IsConfigured gates purely on a - # non-empty Host, so there is no separate Enabled flag. The operator leaves the - # default user passwordless (jellyfin parity), so no Password/Ssl is wired. - # Channels/keys are namespaced by this fork's radarr:ratelimit: prefix, so the - # one cluster is safe to share with sonarr/prowlarr. - Radarr__Redis__Host: valkey-arrstack-valkey.arrstack.svc.cluster.local - Radarr__Redis__Port: "6379" diff --git a/apps/base/arrstack/radarr/gateway.yaml b/apps/base/arrstack/radarr/gateway.yaml deleted file mode 100644 index 2fb50ca..0000000 --- a/apps/base/arrstack/radarr/gateway.yaml +++ /dev/null @@ -1,37 +0,0 @@ ---- -apiVersion: gateway.networking.k8s.io/v1 -kind: Gateway -metadata: - labels: - traefik.io/instance: internal - annotations: - cert-manager.io/cluster-issuer: vault-issuer - cert-manager.io/common-name: radarr.k8s.syd1.au.unkin.net - cert-manager.io/private-key-size: "4096" - external-dns.alpha.kubernetes.io/hostname: radarr.k8s.syd1.au.unkin.net - external-dns.alpha.kubernetes.io/target: 198.18.200.4 - name: radarr - namespace: arrstack -spec: - gatewayClassName: traefik-internal - listeners: - - allowedRoutes: - namespaces: - from: Same - hostname: radarr.k8s.syd1.au.unkin.net - name: http - port: 80 - protocol: HTTP - - allowedRoutes: - namespaces: - from: Same - hostname: radarr.k8s.syd1.au.unkin.net - name: https - port: 443 - protocol: HTTPS - tls: - certificateRefs: - - group: "" - kind: Secret - name: radarr-tls - mode: Terminate diff --git a/apps/base/arrstack/radarr/httproute.yaml b/apps/base/arrstack/radarr/httproute.yaml deleted file mode 100644 index 002cc5b..0000000 --- a/apps/base/arrstack/radarr/httproute.yaml +++ /dev/null @@ -1,49 +0,0 @@ ---- -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: radarr-http-redirect - namespace: arrstack -spec: - hostnames: - - radarr.k8s.syd1.au.unkin.net - parentRefs: - - group: gateway.networking.k8s.io - kind: Gateway - name: radarr - sectionName: http - rules: - - filters: - - type: RequestRedirect - requestRedirect: - scheme: https - statusCode: 301 - matches: - - path: - type: PathPrefix - value: / ---- -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: radarr-route - namespace: arrstack -spec: - hostnames: - - radarr.k8s.syd1.au.unkin.net - parentRefs: - - group: gateway.networking.k8s.io - kind: Gateway - name: radarr - sectionName: https - rules: - - backendRefs: - - group: "" - kind: Service - name: radarr - port: 7878 - weight: 1 - matches: - - path: - type: PathPrefix - value: / diff --git a/apps/base/arrstack/radarr/pvc-config.yaml b/apps/base/arrstack/radarr/pvc-config.yaml deleted file mode 100644 index b5a2b1e..0000000 --- a/apps/base/arrstack/radarr/pvc-config.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -# Radarr /config. RWX on CephFS so all replicas share it (the -unkin2 fork keeps -# the database in Postgres; /config now holds only config.xml + MediaCover, which -# tolerate — and want — shared access). Retain: this is state. -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: radarr-config - namespace: arrstack -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 5Gi - storageClassName: cephfs-raid5-retain - volumeMode: Filesystem diff --git a/apps/base/arrstack/radarr/vaultstaticsecret.yaml b/apps/base/arrstack/radarr/vaultstaticsecret.yaml deleted file mode 100644 index 3601f9f..0000000 --- a/apps/base/arrstack/radarr/vaultstaticsecret.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -# radarr API key. Seeded at kv/kubernetes/namespace/arrstack/default/radarr -# (key: apitoken); the default k8s role's templated policy already grants read -# on kv/data/kubernetes/namespace/{{sa_namespace}}/{{sa_name}}/* for the -# arrstack/default ServiceAccount, so no terraform-vault change is needed. VSO -# syncs it into the radarr-apikey Secret that the apikey-init initContainer reads -# to enforce in /config/config.xml (Vault is source of truth). -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: radarr-apikey - namespace: arrstack - annotations: - argocd.argoproj.io/sync-wave: "0" -spec: - destination: - create: true - name: radarr-apikey - overwrite: true - hmacSecretData: true - mount: kv - path: kubernetes/namespace/arrstack/default/radarr - refreshAfter: 5m - type: kv-v2 - vaultAuthRef: default diff --git a/apps/base/arrstack/sonarr-adult/configmap.yaml b/apps/base/arrstack/sonarr-adult/configmap.yaml new file mode 100644 index 0000000..15e35f1 --- /dev/null +++ b/apps/base/arrstack/sonarr-adult/configmap.yaml @@ -0,0 +1,25 @@ +--- +# Non-secret env for the -unkin2 fork (adult tier). Identical mechanism to the +# kids sonarr, pointed at its own shared-Postgres database (sonarr-adult-main) +# and its own UrlBase (/3aa168/sonarr) so arrproxy path-routing reaches the adult +# instance separately. Shares the one arrstack Valkey (keys namespaced by the +# fork's sonarr:ratelimit: prefix). User/Password/ApiKey come from Secrets (see +# deployment.yaml), not here. +apiVersion: v1 +kind: ConfigMap +metadata: + name: sonarr-adult-env + namespace: arrstack +data: + Sonarr__Postgres__Host: arrstack-postgres-rw.arrstack.svc.cluster.local + Sonarr__Postgres__Port: "5432" + Sonarr__Postgres__MainDb: sonarr-adult-main + Sonarr__Log__DbEnabled: "false" + Sonarr__Auth__Method: External + Sonarr__Auth__Required: DisabledForLocalAddresses + Sonarr__App__InstanceName: Sonarr + Sonarr__Server__Port: "8989" + Sonarr__Server__UrlBase: /3aa168/sonarr + Sonarr__Update__Mechanism: External + Sonarr__Redis__Host: valkey-arrstack-valkey.arrstack.svc.cluster.local + Sonarr__Redis__Port: "6379" diff --git a/apps/base/arrstack/sonarr/deployment.yaml b/apps/base/arrstack/sonarr-adult/deployment.yaml similarity index 74% rename from apps/base/arrstack/sonarr/deployment.yaml rename to apps/base/arrstack/sonarr-adult/deployment.yaml index f5adc0d..f02c50b 100644 --- a/apps/base/arrstack/sonarr/deployment.yaml +++ b/apps/base/arrstack/sonarr-adult/deployment.yaml @@ -2,43 +2,40 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: sonarr + name: sonarr-adult namespace: arrstack annotations: - # sonarr-env is a plain (unhashed) ConfigMap consumed by fixed-name envFrom, - # so editing it does not roll the Deployment on its own. Reloader watches the - # referenced ConfigMap and triggers a rolling restart on change, so adding the - # Redis env activates the #14 features on the next ArgoCD sync without a manual - # `rollout restart`. + # Reloader rolls the Deployment when sonarr-adult-env changes (plain envFrom + # ConfigMap does not trigger a rollout on its own). configmap.reloader.stakater.com/auto: "true" spec: # Active-active: the -unkin2 fork keeps all state in the shared Postgres # (arrstack-postgres) and coordinates via Postgres advisory locks, so N - # replicas run concurrently behind the sonarr Service. RollingUpdate is safe — - # no SQLite, no RWO lock. + # replicas run concurrently behind the sonarr-adult Service. RollingUpdate is + # safe — no SQLite, no RWO lock. replicas: 3 strategy: type: RollingUpdate selector: matchLabels: - app: sonarr + app: sonarr-adult template: metadata: labels: - app: sonarr + app: sonarr-adult spec: securityContext: - # Fork image has no USER (runs as root by default); pin it to a non-root - # UID and group-write the shared RWX CephFS /config (MediaCover etc.). - # OnRootMismatch avoids a recursive chown of the whole media tree. + # Fork image has no USER; pin it to a non-root UID and group-write the + # shared RWX CephFS media subtree. OnRootMismatch avoids a recursive + # chown of the whole media tree. runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 fsGroupChangePolicy: OnRootMismatch initContainers: - # Gate the app on its own Postgres database+role being reachable, instead - # of relying on ArgoCD sync-waves (which deadlock if apps aren't Healthy). - # waitfordb reads the PG* env as a libpq fallback, so the password never lands in argv. + # Gate the app on its own Postgres database+role being reachable. + # waitfordb reads the PG* env as a libpq fallback, so the password never + # lands in argv. - name: wait-for-db image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/waitfordb:v0.1.0 env: @@ -51,16 +48,16 @@ spec: - name: PGPORT value: "5432" - name: PGDATABASE - value: sonarr-main + value: sonarr-adult-main - name: PGUSER valueFrom: secretKeyRef: - name: sonarr-db + name: sonarr-adult-db key: username - name: PGPASSWORD valueFrom: secretKeyRef: - name: sonarr-db + name: sonarr-adult-db key: password resources: requests: @@ -78,9 +75,8 @@ spec: args: - -nobrowser - -data=/config - # Required: bypass the single-instance guard so multiple replicas - # can share one /config. Cross-replica safety is the Postgres layer, - # not a local lock file. + # Bypass the single-instance guard so multiple replicas can share one + # /config. Cross-replica safety is the Postgres layer, not a lock file. - -nosingleinstancecheck ports: - name: http @@ -88,29 +84,25 @@ spec: protocol: TCP envFrom: - configMapRef: - name: sonarr-env + name: sonarr-adult-env env: - name: Sonarr__Postgres__User valueFrom: secretKeyRef: - name: sonarr-db + name: sonarr-adult-db key: username - name: Sonarr__Postgres__Password valueFrom: secretKeyRef: - name: sonarr-db + name: sonarr-adult-db key: password - name: Sonarr__Auth__ApiKey valueFrom: secretKeyRef: - name: sonarr-apikey + name: sonarr-adult-apikey key: apitoken # MediaCover object store (shared arrstack-media Ceph RGW bucket, - # partitioned from radarr by the sonarr key prefix). Serves - # posters/fanart from S3 so any replica renders them instead of the - # leader-local emptyDir /config. Consumed by the -unkin3+ image; - # older images ignore these unknown config keys. Creds Secret minted - # by cephrgw-operator. + # partitioned by the sonarr-adult key prefix). - name: Sonarr__MediaCoverS3__Endpoint valueFrom: secretKeyRef: @@ -129,14 +121,13 @@ spec: - name: Sonarr__MediaCoverS3__Bucket value: arrstack-media - name: Sonarr__MediaCoverS3__Prefix - value: sonarr + value: sonarr-adult - name: Sonarr__MediaCoverS3__ForcePathStyle value: "true" - name: Sonarr__MediaCoverS3__CaCertPath value: /etc/ssl/vault-ca/ca.crt # Backup object store (shared arrstack-backups Ceph RGW bucket, - # per-app key prefix). Routes the periodic config+DB zip backups off - # the ephemeral /config so any replica can write and restore them. + # partitioned by the sonarr-adult key prefix). - name: Sonarr__BackupS3__Endpoint valueFrom: secretKeyRef: @@ -155,14 +146,14 @@ spec: - name: Sonarr__BackupS3__Bucket value: arrstack-backups - name: Sonarr__BackupS3__Prefix - value: sonarr + value: sonarr-adult - name: Sonarr__BackupS3__ForcePathStyle value: "true" - name: Sonarr__BackupS3__CaCertPath value: /etc/ssl/vault-ca/ca.crt livenessProbe: httpGet: - path: /sonarr/ping + path: /3aa168/sonarr/ping port: http initialDelaySeconds: 30 periodSeconds: 30 @@ -170,7 +161,7 @@ spec: failureThreshold: 3 readinessProbe: httpGet: - path: /sonarr/ping + path: /3aa168/sonarr/ping port: http initialDelaySeconds: 10 periodSeconds: 10 @@ -186,28 +177,31 @@ spec: volumeMounts: - name: config mountPath: /config + # Adult TV subtree of the shared media-tv PVC (same CephFS subvolume + # the kids sonarr writes and jellyfin reads). - name: media-tv mountPath: /media/tv + subPath: tvshows/adult - name: vault-ca mountPath: /etc/ssl/vault-ca readOnly: true # exportarr sidecar: polls the local replica's API and exposes Prometheus - # metrics on :9707 (scraped by the sonarr-exportarr VMPodScrape). + # metrics on :9707 (scraped by the sonarr-adult-exportarr VMPodScrape). - name: exportarr - image: artifactapi.k8s.syd1.au.unkin.net/ghcr/onedr0p/exportarr:v2.3.0 + image: ghcr.io/onedr0p/exportarr:v2.3.0 imagePullPolicy: IfNotPresent args: - sonarr env: - name: PORT value: "9707" - # URL includes the /sonarr UrlBase (Sonarr__Server__UrlBase). + # URL includes the /3aa168/sonarr UrlBase (Sonarr__Server__UrlBase). - name: URL - value: http://localhost:8989/sonarr + value: http://localhost:8989/3aa168/sonarr - name: APIKEY valueFrom: secretKeyRef: - name: sonarr-apikey + name: sonarr-adult-apikey key: apitoken ports: - name: metrics diff --git a/apps/base/arrstack/radarr/kustomization.yaml b/apps/base/arrstack/sonarr-adult/kustomization.yaml similarity index 83% rename from apps/base/arrstack/radarr/kustomization.yaml rename to apps/base/arrstack/sonarr-adult/kustomization.yaml index 8789f80..5ab2110 100644 --- a/apps/base/arrstack/radarr/kustomization.yaml +++ b/apps/base/arrstack/sonarr-adult/kustomization.yaml @@ -7,6 +7,4 @@ resources: - configmap.yaml - deployment.yaml - service.yaml - - gateway.yaml - - httproute.yaml - vmpodscrape.yaml diff --git a/apps/base/arrstack/sonarr/service.yaml b/apps/base/arrstack/sonarr-adult/service.yaml similarity index 81% rename from apps/base/arrstack/sonarr/service.yaml rename to apps/base/arrstack/sonarr-adult/service.yaml index 3ee669d..c9b37b3 100644 --- a/apps/base/arrstack/sonarr/service.yaml +++ b/apps/base/arrstack/sonarr-adult/service.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Service metadata: - name: sonarr + name: sonarr-adult namespace: arrstack spec: ports: @@ -11,5 +11,5 @@ spec: protocol: TCP targetPort: http selector: - app: sonarr + app: sonarr-adult type: ClusterIP diff --git a/apps/base/arrstack/sonarr-adult/vaultstaticsecret.yaml b/apps/base/arrstack/sonarr-adult/vaultstaticsecret.yaml new file mode 100644 index 0000000..a62121e --- /dev/null +++ b/apps/base/arrstack/sonarr-adult/vaultstaticsecret.yaml @@ -0,0 +1,25 @@ +--- +# sonarr-adult API key. Seeded out-of-band at +# kv/kubernetes/namespace/arrstack/default/sonarr-adult (key: apitoken); the +# default k8s role's templated policy already grants read on +# kv/data/kubernetes/namespace/{{sa_namespace}}/{{sa_name}}/* for the +# arrstack/default ServiceAccount, so no terraform-vault change is needed. VSO +# syncs it into the sonarr-adult-apikey Secret consumed by the Deployment. +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: sonarr-adult-apikey + namespace: arrstack + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + destination: + create: true + name: sonarr-adult-apikey + overwrite: true + hmacSecretData: true + mount: kv + path: kubernetes/namespace/arrstack/default/sonarr-adult + refreshAfter: 5m + type: kv-v2 + vaultAuthRef: default diff --git a/apps/base/arrstack/sonarr/vmpodscrape.yaml b/apps/base/arrstack/sonarr-adult/vmpodscrape.yaml similarity index 54% rename from apps/base/arrstack/sonarr/vmpodscrape.yaml rename to apps/base/arrstack/sonarr-adult/vmpodscrape.yaml index 82f61f4..899f1c7 100644 --- a/apps/base/arrstack/sonarr/vmpodscrape.yaml +++ b/apps/base/arrstack/sonarr-adult/vmpodscrape.yaml @@ -1,16 +1,16 @@ --- -# Scrape the exportarr sidecar (:9707) on every sonarr pod. Picked up by the +# Scrape the exportarr sidecar (:9707) on every sonarr-adult pod. Picked up by the # observability VMAgent (selectAllByDefault). Pod-level rather than -# VMServiceScrape because the sonarr Service doesn't expose the metrics port. +# VMServiceScrape because the sonarr-adult Service doesn't expose the metrics port. apiVersion: operator.victoriametrics.com/v1beta1 kind: VMPodScrape metadata: - name: sonarr-exportarr + name: sonarr-adult-exportarr namespace: arrstack spec: selector: matchLabels: - app: sonarr + app: sonarr-adult podMetricsEndpoints: - port: metrics path: /metrics diff --git a/apps/base/arrstack/sonarr/configmap.yaml b/apps/base/arrstack/sonarr/configmap.yaml deleted file mode 100644 index dd2242c..0000000 --- a/apps/base/arrstack/sonarr/configmap.yaml +++ /dev/null @@ -1,33 +0,0 @@ ---- -# Non-secret env for the -unkin2 fork. The fork reads Servarr config from -# Sonarr__
__ env (no config.xml edits, no s6/PUID). Postgres wiring -# points every replica at the same shared DB (arrstack-postgres-rw / sonarr-main); -# Auth__Method=External defers UI auth to arrproxy/oauth2-proxy; Server__UrlBase -# keeps the /sonarr prefix so arrproxy path-routing works; App__InstanceName is -# identical across replicas (shared session-cookie name). User/Password/ApiKey -# come from Secrets (see deployment.yaml), not here. -apiVersion: v1 -kind: ConfigMap -metadata: - name: sonarr-env - namespace: arrstack -data: - Sonarr__Postgres__Host: arrstack-postgres-rw.arrstack.svc.cluster.local - Sonarr__Postgres__Port: "5432" - Sonarr__Postgres__MainDb: sonarr-main - Sonarr__Log__DbEnabled: "false" - Sonarr__Auth__Method: External - Sonarr__Auth__Required: DisabledForLocalAddresses - Sonarr__App__InstanceName: Sonarr - Sonarr__Server__Port: "8989" - Sonarr__Server__UrlBase: /sonarr - Sonarr__Update__Mechanism: External - # Shared arrstack Valkey (valkey-operator). Setting Host is what activates the - # fork's #14 Redis features (SignalR backplane, cross-replica cache-invalidation - # bus, distributed rate limiter): RedisOptions.IsConfigured gates purely on a - # non-empty Host, so there is no separate Enabled flag. The operator leaves the - # default user passwordless (jellyfin parity), so no Password/Ssl is wired. - # Channels/keys are namespaced by this fork's sonarr:ratelimit: prefix, so the - # one cluster is safe to share with radarr/prowlarr. - Sonarr__Redis__Host: valkey-arrstack-valkey.arrstack.svc.cluster.local - Sonarr__Redis__Port: "6379" diff --git a/apps/base/arrstack/sonarr/gateway.yaml b/apps/base/arrstack/sonarr/gateway.yaml deleted file mode 100644 index 38ff6b3..0000000 --- a/apps/base/arrstack/sonarr/gateway.yaml +++ /dev/null @@ -1,37 +0,0 @@ ---- -apiVersion: gateway.networking.k8s.io/v1 -kind: Gateway -metadata: - labels: - traefik.io/instance: internal - annotations: - cert-manager.io/cluster-issuer: vault-issuer - cert-manager.io/common-name: sonarr.k8s.syd1.au.unkin.net - cert-manager.io/private-key-size: "4096" - external-dns.alpha.kubernetes.io/hostname: sonarr.k8s.syd1.au.unkin.net - external-dns.alpha.kubernetes.io/target: 198.18.200.4 - name: sonarr - namespace: arrstack -spec: - gatewayClassName: traefik-internal - listeners: - - allowedRoutes: - namespaces: - from: Same - hostname: sonarr.k8s.syd1.au.unkin.net - name: http - port: 80 - protocol: HTTP - - allowedRoutes: - namespaces: - from: Same - hostname: sonarr.k8s.syd1.au.unkin.net - name: https - port: 443 - protocol: HTTPS - tls: - certificateRefs: - - group: "" - kind: Secret - name: sonarr-tls - mode: Terminate diff --git a/apps/base/arrstack/sonarr/httproute.yaml b/apps/base/arrstack/sonarr/httproute.yaml deleted file mode 100644 index 5e11c73..0000000 --- a/apps/base/arrstack/sonarr/httproute.yaml +++ /dev/null @@ -1,49 +0,0 @@ ---- -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: sonarr-http-redirect - namespace: arrstack -spec: - hostnames: - - sonarr.k8s.syd1.au.unkin.net - parentRefs: - - group: gateway.networking.k8s.io - kind: Gateway - name: sonarr - sectionName: http - rules: - - filters: - - type: RequestRedirect - requestRedirect: - scheme: https - statusCode: 301 - matches: - - path: - type: PathPrefix - value: / ---- -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: sonarr-route - namespace: arrstack -spec: - hostnames: - - sonarr.k8s.syd1.au.unkin.net - parentRefs: - - group: gateway.networking.k8s.io - kind: Gateway - name: sonarr - sectionName: https - rules: - - backendRefs: - - group: "" - kind: Service - name: sonarr - port: 8989 - weight: 1 - matches: - - path: - type: PathPrefix - value: / diff --git a/apps/base/arrstack/sonarr/pvc-config.yaml b/apps/base/arrstack/sonarr/pvc-config.yaml deleted file mode 100644 index baa87c7..0000000 --- a/apps/base/arrstack/sonarr/pvc-config.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -# Sonarr /config. RWX on CephFS so all replicas share it (the -unkin2 fork keeps -# the database in Postgres; /config now holds only config.xml + MediaCover, which -# tolerate — and want — shared access). Retain: this is state. -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: sonarr-config - namespace: arrstack -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 5Gi - storageClassName: cephfs-raid5-retain - volumeMode: Filesystem diff --git a/apps/base/arrstack/sonarr/vaultstaticsecret.yaml b/apps/base/arrstack/sonarr/vaultstaticsecret.yaml deleted file mode 100644 index 93e9798..0000000 --- a/apps/base/arrstack/sonarr/vaultstaticsecret.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -# sonarr API key. Seeded at kv/kubernetes/namespace/arrstack/default/sonarr -# (key: apitoken); the default k8s role's templated policy already grants read -# on kv/data/kubernetes/namespace/{{sa_namespace}}/{{sa_name}}/* for the -# arrstack/default ServiceAccount, so no terraform-vault change is needed. VSO -# syncs it into the sonarr-apikey Secret that the apikey-init initContainer reads -# to enforce in /config/config.xml (Vault is source of truth). -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: sonarr-apikey - namespace: arrstack - annotations: - argocd.argoproj.io/sync-wave: "0" -spec: - destination: - create: true - name: sonarr-apikey - overwrite: true - hmacSecretData: true - mount: kv - path: kubernetes/namespace/arrstack/default/sonarr - refreshAfter: 5m - type: kv-v2 - vaultAuthRef: default