--- apiVersion: apps/v1 kind: Deployment metadata: name: sonarr namespace: arrstack 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: 3 strategy: type: RollingUpdate selector: matchLabels: app: sonarr template: metadata: labels: app: sonarr 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. 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. - name: wait-for-db image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/waitfordb:v0.1.0 env: - name: WAITFORDB_TIMEOUT value: 5m - name: WAITFORDB_SSLMODE value: disable - name: PGHOST value: arrstack-postgres-rw.arrstack.svc.cluster.local - name: PGPORT value: "5432" - name: PGDATABASE value: sonarr-main - name: PGUSER valueFrom: secretKeyRef: name: sonarr-db key: username - name: PGPASSWORD valueFrom: secretKeyRef: name: sonarr-db key: password resources: requests: cpu: 10m memory: 32Mi limits: cpu: 100m memory: 64Mi containers: - name: sonarr image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/sonarr:v5.0.0-unkin4 imagePullPolicy: IfNotPresent command: - /app/Sonarr 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. - -nosingleinstancecheck ports: - name: http containerPort: 8989 protocol: TCP envFrom: - configMapRef: name: sonarr-env env: - name: Sonarr__Postgres__User valueFrom: secretKeyRef: name: sonarr-db key: username - name: Sonarr__Postgres__Password valueFrom: secretKeyRef: name: sonarr-db key: password - name: Sonarr__Auth__ApiKey valueFrom: secretKeyRef: name: sonarr-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. - name: Sonarr__MediaCoverS3__Endpoint valueFrom: secretKeyRef: name: arrstack-media-s3 key: S3_ENDPOINT - name: Sonarr__MediaCoverS3__AccessKey valueFrom: secretKeyRef: name: arrstack-media-s3 key: AWS_ACCESS_KEY_ID - name: Sonarr__MediaCoverS3__SecretKey valueFrom: secretKeyRef: name: arrstack-media-s3 key: AWS_SECRET_ACCESS_KEY - name: Sonarr__MediaCoverS3__Bucket value: arrstack-media - name: Sonarr__MediaCoverS3__Prefix value: sonarr - 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. - name: Sonarr__BackupS3__Endpoint valueFrom: secretKeyRef: name: arrstack-backups-s3 key: S3_ENDPOINT - name: Sonarr__BackupS3__AccessKey valueFrom: secretKeyRef: name: arrstack-backups-s3 key: AWS_ACCESS_KEY_ID - name: Sonarr__BackupS3__SecretKey valueFrom: secretKeyRef: name: arrstack-backups-s3 key: AWS_SECRET_ACCESS_KEY - name: Sonarr__BackupS3__Bucket value: arrstack-backups - name: Sonarr__BackupS3__Prefix value: sonarr - name: Sonarr__BackupS3__ForcePathStyle value: "true" - name: Sonarr__BackupS3__CaCertPath value: /etc/ssl/vault-ca/ca.crt livenessProbe: httpGet: path: /sonarr/ping port: http initialDelaySeconds: 30 periodSeconds: 30 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /sonarr/ping port: http initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 resources: requests: cpu: 100m memory: 256Mi limits: cpu: "1" memory: 1Gi volumeMounts: - name: config mountPath: /config - name: media-tv mountPath: /media/tv - name: vault-ca mountPath: /etc/ssl/vault-ca readOnly: true volumes: - name: config emptyDir: {} - name: media-tv persistentVolumeClaim: claimName: media-tv # 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