NOTE / TERRAIN

The ARR Stack on Kubernetes: Orchestrating the Media Pipeline.

The media stack looks like one application from the sofa. In Kubernetes it is a small distributed system.

A request to watch something may cross a media server, one or more catalogue managers, an indexer, a download client, a VPN boundary and several different storage areas. Each component is simple enough on its own. The operational work lives in the connections between them.

request
  │
  ├──► Sonarr / Radarr / Lidarr
  │          │
  │          ▼
  │       Prowlarr
  │          │
  │          ▼
  │   Transmission + WireGuard
  │          │
  ▼          ▼
Jellyfin ◄── shared media storage
  │
  └──► television

That is why I keep the stack together in the repository. It is not one container, but it is one operational story.

What is in the stack?

The reusable base currently defines the main applications:

Jellyfin      media playback
Sonarr        series management
Radarr        film management
Lidarr        music management
Prowlarr      indexer coordination
Bazarr        subtitle management
Transmission  download client
WireGuard     network boundary for the download path
Whisparr      an additional media catalogue

Some overlays add or alter supporting components. Prowlarr, for example, has used a Flaresolverr companion. The important design choice is that these differences remain visible in overlays rather than being copied into several complete stacks.

Deployment layout

The manifests use a base with development and homelab overlays:

arr-stack/
├── base/
│   ├── one workload per application
│   ├── services
│   └── namespace
├── overlays/
│   ├── dev/
│   └── homelab/
└── fleet.yaml

The homelab overlay runs in the media-stack namespace. Kustomize patches storage, Services, selected workloads and ingress; Rancher Fleet reconciles the result.

This is a place where the base/overlay split pays for itself. The application graph stays recognisable while the storage and network details can change per cluster.

Storage is the architecture

Media workloads make Kubernetes storage abstractions feel very concrete.

The homelab overlay separates small application configuration claims from large media volumes. Configuration occupies gigabytes. The media libraries are expressed in terabytes. Treating them as one undifferentiated PVC would make both backup policy and recovery needlessly expensive.

I divide the data by replaceability:

application configuration
  ├── indexes, histories and preferences
  └── small, valuable, worth frequent backup

download workspace
  ├── transient and partially complete data
  └── useful, but not equally valuable

media library
  ├── large payload
  └── separate retention and recovery decision

The mounts must also agree across applications. If Sonarr sees a file under one path and Transmission reports a different path for the same bytes, every pod can be healthy while imports quietly fail.

The VPN boundary

The download path is coupled to WireGuard. That is deliberate, but it creates an integration that needs its own health check.

Transmission process healthy
≠
download path safely usable

After changing network configuration I validate connectivity from the intended pod context and confirm that the download client can still reach both its external peers and the internal applications that control it.

I do not publish the provider configuration or internal routes. Those values belong to secret and environment-specific inputs, not to the public explanation of the architecture.

Operating the media stack

The first diagnostic pass asks Kubernetes for the whole namespace:

kubectl -n media-stack get deploy,pod,svc,pvc,ingressroute
kubectl -n media-stack get events --sort-by=.lastTimestamp

Then I narrow the problem to one edge of the graph:

kubectl -n media-stack logs deploy/jellyfin --tail=200
kubectl -n media-stack logs deploy/sonarr --tail=200
kubectl -n media-stack logs deploy/radarr --tail=200
kubectl -n media-stack logs deploy/prowlarr --tail=200

The most common categories are more useful than memorising every pod:

catalogue problem
  └── Sonarr, Radarr, Lidarr or Whisparr

search problem
  └── Prowlarr or a supporting resolver

download problem
  └── Transmission, WireGuard or path mapping

playback problem
  └── Jellyfin, storage throughput or media permissions

everything Ready, workflow stuck
  └── integration credentials, URLs or inconsistent mount paths

That last category is the recurring one. Kubernetes readiness proves that the processes are alive. It does not prove that an episode can travel from request to library to playback.

Backup and recovery

Backing up the entire media estate with one policy would confuse size with value.

My useful recovery set starts with:

Kustomize and Fleet configuration in Git
+
application configuration volumes
+
network and integration secret inputs
+
an explicit decision for the media library

The restore order follows the data flow:

1. Restore secrets and small configuration claims
2. Make shared storage available
3. Reconcile the overlay
4. Validate the VPN and download path
5. Validate catalogue-to-downloader path mappings
6. Play a real item through Jellyfin

The final playback test is the recovery test. A page full of green pods is only preparation for it.

Versioning and upgrades

Several images in the homelab overlay currently track moving tags. That keeps the stack fresh, but weakens reproducibility. With many coupled applications, simultaneous unplanned upgrades can make it difficult to identify which interface changed.

The safer long-term shape is pinned versions updated in small groups. Until every image is pinned, I capture running image IDs during incident work and avoid assuming that a rollback to the same YAML means a rollback to the same software.

Things worth remembering

At the time of writing, the stack is:

Namespace      media-stack
Workloads      Jellyfin plus the ARR and download services
Deployment     Kustomize + Rancher Fleet
Storage        separate config, workspace and large media volumes
Network        Traefik for selected UIs, WireGuard for download traffic
Weak point     integration boundaries and moving image tags
Recovery test  complete request-to-playback workflow

From the user side, the ideal media platform has one button. From the operator side, earning that simplicity means making every hidden hand-off explicit.