Skip to content

Repository files navigation

Sonarr Kubernetes Operator

A Kubernetes operator for Sonarr written in Rust using kube-rs.

This operator allows you to manage Sonarr resources declaratively through Kubernetes Custom Resources, enabling GitOps workflows for TV series management.

Features

  • Declarative Configuration: Define Sonarr resources as Kubernetes manifests
  • GitOps Ready: Manage Sonarr configuration through version control
  • Multi-Instance Support: Manage multiple Sonarr instances from a single operator
  • Automatic Synchronization: Resources are continuously reconciled with Sonarr
  • Finalizers: Clean up resources in Sonarr when Kubernetes resources are deleted
  • 19 CRDs: Comprehensive coverage of Sonarr configuration options

Supported Resources

The operator manages 19 CRDs in the devopsarr.io/v1alpha1 API group:

Main Instance

  • Sonarr - The Sonarr server instance configuration

Content

Profiles

Integrations

Organization

Quality

Metadata

Config (Singletons per instance)

For detailed API specifications, see the CRD Reference.

Quick Start

Prerequisites

  • Kubernetes cluster (1.28+)
  • Helm 3.8+ (for OCI registry support)
  • k3d for local development (optional)

Installation (Helm — recommended)

Install the operator and its CRDs from the OCI chart on GHCR:

helm install sonarr-operator \
  oci://ghcr.io/devopsarr/charts/sonarr-operator \
  --namespace sonarr-operator-system \
  --create-namespace

The chart installs the operator Deployment, RBAC, and all 19 CRDs. CRDs are annotated helm.sh/resource-policy: keep, so they (and any Sonarr resources) survive a helm uninstall.

To install a specific version, pass --version <X.Y.Z>. To skip CRD installation (when managing them out-of-band), pass --set crds.install=false. To allow helm uninstall to remove CRDs as well, pass --set crds.keep=false. See the chart README for the full values reference.

Installation (raw manifests — alternative)

Render the chart locally or use the per-release CRD asset:

# Option A: render from chart source
helm template sonarr-operator charts/sonarr-operator \
  --namespace sonarr-operator-system | kubectl apply -f -

# Option B: download CRDs from a release and apply the static deploy/ manifests
kubectl apply -f https://github.com/devopsarr/k8s-operator-sonarr/releases/latest/download/crds.yaml
kubectl apply -f deploy/namespace.yaml
kubectl apply -f deploy/rbac.yaml
kubectl apply -f deploy/deployment.yaml

Create a Sonarr instance

A minimal example lives at deploy/examples/sonarr-minimal.yaml.

# Optional: pre-create an API key Secret (omit to have the operator generate one)
kubectl create secret generic sonarr-api-key \
  --from-literal=api-key="$(openssl rand -hex 16)"

kubectl apply -f deploy/examples/sonarr-minimal.yaml
kubectl wait sonarr/sonarr --for=condition=Ready --timeout=5m

Create child resources

apiVersion: devopsarr.io/v1alpha1
kind: SonarrTag
metadata:
  name: anime
spec:
  sonarrInstanceRef:
    name: sonarr
  label: "anime"
---
apiVersion: devopsarr.io/v1alpha1
kind: SonarrRootFolder
metadata:
  name: tv-shows
spec:
  sonarrInstanceRef:
    name: my-sonarr
  path: "/media/tv"

Development

Building

make build        # Release binary
make build-debug  # Debug binary
make crds         # Generate CRD manifests
make docs         # Generate CRD documentation

Linting & Testing

make lint              # Format check + clippy
make test              # Unit tests
make integration-test  # Integration tests (requires cluster with CRDs)

Local E2E Testing

The local E2E workflow uses k3d to create a cluster with Sonarr:

# Terminal 1: Create cluster + deploy Sonarr
make e2e-up

# Terminal 2: Run the operator locally
make run-debug

# Terminal 3: Run E2E tests
make e2e

# Cleanup
make e2e-down

See docs/TESTING.md for more details.

Deploy to a Local Cluster

make deploy    # Build image, import into k3d, deploy operator
make undeploy  # Remove operator from cluster

Architecture

The operator implements the Kubernetes Operator pattern to declaratively manage Sonarr configuration. It runs as a Deployment in the cluster and watches 19 CRDs in the devopsarr.io/v1alpha1 API group.

How It Works

                        Kubernetes Cluster
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  ┌──────────────┐  watches   ┌───────────────────────────┐  │
│  │ Sonarr       │◄───────────│ Sonarr Operator           │  │
│  │ CRDs (19)    │            │ (Rust / kube-rs)          │  │
│  │              │            │                           │  │
│  │ devopsarr.io │ status     │ ┌───────────────────────┐ │  │
│  │ /v1alpha1    │◄───────────│ │ 19 Controllers        │ │  │
│  └──────────────┘  updates   │ │ (one per CRD type)    │ │  │
│                              │ └───────────┬───────────┘ │  │
│  ┌──────────────┐            └─────────────┼─────────────┘  │
│  │ K8s Secrets  │                          │                │
│  │ (API keys)   │──────────────────────────┤                │
│  └──────────────┘   credentials            │                │
│                                            │ HTTP REST API  │
│                                            │ (v3/v4)        │
│                                            ▼                │
│                              ┌───────────────────────────┐  │
│                              │ Sonarr Instance(s)        │  │
│                              │ (Pods / Services)         │  │
│                              └───────────────────────────┘  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Resource Hierarchy

All sub-resource CRDs reference a parent Sonarr instance via sonarrInstanceRef:

Sonarr (instance connection: URL + API key)
├── Content:      SonarrSeries
├── Profiles:     SonarrQualityProfile, SonarrLanguageProfile, SonarrDelayProfile
├── Integrations: SonarrDownloadClient, SonarrIndexer, SonarrNotification, SonarrImportList
├── Organization: SonarrTag, SonarrAutoTag, SonarrRootFolder
├── Quality:      SonarrQualityDefinition, SonarrCustomFormat
├── Metadata:     SonarrMetadata
└── Config:       SonarrMediaManagementConfig, SonarrNamingConfig,
                  SonarrIndexerConfig, SonarrDownloadClientConfig

Reconciliation Loop

Each controller runs an independent reconciliation loop:

  1. Watch — Detect create/update/delete events on the CRD
  2. Resolve — Look up the SonarrInstanceRef to get URL and API key from the Sonarr CR and its Secret
  3. Apply — Call the Sonarr REST API to create or update the resource
  4. Status — Write the Sonarr resource ID and a Ready condition back to the CRD status
  5. Finalize — On deletion, remove the resource from Sonarr before allowing the CR to be garbage-collected
  6. Requeue — Re-reconcile every 5 minutes to catch out-of-band changes (errors requeue after 60 seconds)

Configuration

Environment Variables

Variable Description Default
RUST_LOG Log level (trace, debug, info, warn, error) info

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes using Conventional Commits (git commit -m 'feat: add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the GPL-3.0 License - see the LICENSE file for details.

Acknowledgments

  • Sonarr - The PVR for Usenet and BitTorrent users
  • kube-rs - Rust client for Kubernetes
  • sonarr-rs - Sonarr API client for Rust

About

K8S operator for sonarr

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages