diff --git a/apps/base/arrstack/kustomization.yaml b/apps/base/arrstack/kustomization.yaml index 762a342..2798a6b 100644 --- a/apps/base/arrstack/kustomization.yaml +++ b/apps/base/arrstack/kustomization.yaml @@ -14,6 +14,7 @@ resources: - media-bucket.yaml - backups-bucket.yaml - postgres + - valkey - sonarr - radarr - prowlarr diff --git a/apps/base/arrstack/prowlarr/configmap.yaml b/apps/base/arrstack/prowlarr/configmap.yaml index 353c02b..18b943d 100644 --- a/apps/base/arrstack/prowlarr/configmap.yaml +++ b/apps/base/arrstack/prowlarr/configmap.yaml @@ -22,3 +22,12 @@ data: Prowlarr__Server__Port: "9696" Prowlarr__Server__UrlBase: /prowlarr Prowlarr__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 prowlarr:ratelimit: prefix, so the + # one cluster is safe to share with sonarr/radarr. + Prowlarr__Redis__Host: valkey-arrstack-valkey.arrstack.svc.cluster.local + Prowlarr__Redis__Port: "6379" diff --git a/apps/base/arrstack/prowlarr/deployment.yaml b/apps/base/arrstack/prowlarr/deployment.yaml index bdc3499..6e41040 100644 --- a/apps/base/arrstack/prowlarr/deployment.yaml +++ b/apps/base/arrstack/prowlarr/deployment.yaml @@ -4,6 +4,13 @@ kind: Deployment metadata: name: prowlarr namespace: arrstack + annotations: + # prowlarr-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`. + 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 diff --git a/apps/base/arrstack/radarr/configmap.yaml b/apps/base/arrstack/radarr/configmap.yaml index 8678ced..17eedce 100644 --- a/apps/base/arrstack/radarr/configmap.yaml +++ b/apps/base/arrstack/radarr/configmap.yaml @@ -22,3 +22,12 @@ data: 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/deployment.yaml b/apps/base/arrstack/radarr/deployment.yaml index b64079b..e3120bb 100644 --- a/apps/base/arrstack/radarr/deployment.yaml +++ b/apps/base/arrstack/radarr/deployment.yaml @@ -4,6 +4,13 @@ kind: Deployment metadata: name: radarr 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`. + 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 diff --git a/apps/base/arrstack/sonarr/configmap.yaml b/apps/base/arrstack/sonarr/configmap.yaml index e837b0e..dd2242c 100644 --- a/apps/base/arrstack/sonarr/configmap.yaml +++ b/apps/base/arrstack/sonarr/configmap.yaml @@ -22,3 +22,12 @@ data: 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/deployment.yaml b/apps/base/arrstack/sonarr/deployment.yaml index f2331bc..18cd15f 100644 --- a/apps/base/arrstack/sonarr/deployment.yaml +++ b/apps/base/arrstack/sonarr/deployment.yaml @@ -4,6 +4,13 @@ kind: Deployment metadata: name: sonarr 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`. + 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 diff --git a/apps/base/arrstack/valkey/kustomization.yaml b/apps/base/arrstack/valkey/kustomization.yaml new file mode 100644 index 0000000..f4160f4 --- /dev/null +++ b/apps/base/arrstack/valkey/kustomization.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - valkeycluster.yaml diff --git a/apps/base/arrstack/valkey/valkeycluster.yaml b/apps/base/arrstack/valkey/valkeycluster.yaml new file mode 100644 index 0000000..2c107df --- /dev/null +++ b/apps/base/arrstack/valkey/valkeycluster.yaml @@ -0,0 +1,47 @@ +--- +# Single shared HA Valkey for the arr apps (sonarr/radarr/prowlarr), managed by +# valkey-operator. It activates the fork's #14 Redis features: the SignalR +# backplane, the cross-replica cache-invalidation bus, and the distributed rate +# limiter. One cluster is safe for all three because each fork namespaces its +# keys and pub/sub channels by a per-app prefix (sonarr:ratelimit: / +# radarr:ratelimit: / prowlarr:ratelimit:), so their state never collides. +# +# Modeled on jellyfin-valkey: shards:1 + replicas:2 is one primary with two +# replicas in a single shard group (three ValkeyNodes total); losing the primary +# triggers an automatic failover so a node/pod loss no longer drops the shared +# state the app replicas coordinate through. The operator runs Valkey +# cluster-mode-enabled with protected-mode off and leaves the built-in `default` +# user passwordless, so clients connect with no auth/TLS; StackExchange.Redis +# seeds off the single service and auto-discovers topology plus failovers. +# scheduling.node.spread.shard:Required keeps the three nodes on distinct hosts, +# so one host loss removes at most one node; podDisruptionBudget.mode:Cluster +# lets the operator manage a quorum-aware PDB. Persistence is omitted (/data is an +# emptyDir): the coordination state is ephemeral (short TTLs / transient pub/sub), +# replication+failover already provide redundancy, and an operator-managed PVC +# cannot carry the k8up.io/backup:"false" annotation the namespace k8up Schedule +# needs to skip in-use RWO volumes. +apiVersion: valkey.io/v1alpha1 +kind: ValkeyCluster +metadata: + name: arrstack-valkey + namespace: arrstack +spec: + shards: 1 + replicas: 2 + image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/valkey/valkey:9.0.0 + exporter: + enabled: false + scheduling: + node: + spread: + shard: + mode: Required + podDisruptionBudget: + mode: Cluster + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi