Skip to main content

The documentation here is for an unreleased version of Recyclarr.

Visit the documentation site for the Current Version instead.

Kubernetes (Helm)

Recyclarr has an official Helm chart that runs the Recyclarr server in Kubernetes. It is published to the GitHub Container Registry as an OCI chart:

oci://ghcr.io/recyclarr/charts/recyclarr

The chart version is the Recyclarr version: chart 9.0.0 deploys Recyclarr 9.0.0. A new chart version comes out with each Recyclarr release, and fixes to the chart itself ship with the next release. By default the chart uses the ghcr.io/recyclarr/recyclarr image tagged with that same version.

Example​

This example keeps the server's API key and the Sonarr and Radarr API keys in Secrets you create:

kubectl create secret generic recyclarr-api-key \
--from-literal=api-key="$(openssl rand -hex 32)"
kubectl create secret generic recyclarr-servarr-keys \
--from-literal=SONARR_API_KEY=your-sonarr-api-key \
--from-literal=RADARR_API_KEY=your-radarr-api-key
# values.yaml
apiKey:
existingSecret: recyclarr-api-key
configs:
files:
sonarr.yml: |
sonarr:
main:
base_url: http://sonarr:8989
api_key: !env_var SONARR_API_KEY
radarr.yml: |
radarr:
main:
base_url: http://radarr:7878
api_key: !env_var RADARR_API_KEY
settings:
content: |
server:
schedule:
cron: 0 4 * * *
env:
- name: TZ
value: America/Santiago
envFrom:
- secretRef:
name: recyclarr-servarr-keys
helm install recyclarr oci://ghcr.io/recyclarr/charts/recyclarr -f values.yaml

The server syncs on its built-in schedule. TZ sets the schedule's time zone (default UTC). The pod becomes ready after the first TRaSH Guides download, which can take a few minutes.

API Key​

The server does not start without an API key, so the chart requires one. Set exactly one of these; helm install fails if you set neither or both:

  • apiKey.existingSecret: the name of a Secret you manage, for example one created by hand or by External Secrets Operator. The chart reads the key from the Secret's api-key entry. Set apiKey.existingSecretKey to use a different entry.
  • apiKey.value: the key itself, at least 32 characters. The chart creates a Secret for it. This puts the key in your values file, so prefer existingSecret when the values file is in version control.

The chart mounts the key as a file and sets RECYCLARR_API_KEY_FILE to its path. The server reads the file on every request, so you can rotate the key in the Secret without restarting the pod.

Configuration Files​

The chart mounts your files read-only in the config directory. Each source can come from your values or from a ConfigMap you manage, but not both:

ValuesMounted at
configs.files or configs.existingConfigMap/config/configs/
includes.files or includes.existingConfigMap/config/includes/
settings.content or settings.existingConfigMap/config/settings.yml

configs.files and includes.files map each file name to its contents. File names in configs.files must end in .yml or .yaml. settings.content holds the contents of settings.yml. Without it, the server uses default settings. Write every file's contents as a string (with |), as in the example. Helm then passes YAML tags such as !env_var through unchanged.

In an existing ConfigMap, each key is a file name and its value is the file's contents. A settings ConfigMap must have a settings.yml key. If you generate it with a Kustomize configMapGenerator, set disableNameSuffixHash: true, because Kustomize does not rewrite names inside Helm values.

The server applies edits to its YAML configuration files without a restart (see Configuration Changes), but reads settings.yml and environment variables only when it starts. helm upgrade restarts the pod when files or the API key in your values change. When you change a configs or includes ConfigMap you manage, Kubernetes updates the mounted files after a short delay, and the server picks up the edit. After you change a settings ConfigMap you manage, or a Secret the container reads through env or envFrom, restart the Deployment yourself or use a tool such as Reloader.

Environment Variables​

env and envFrom add environment variables to the container, usually Sonarr and Radarr API keys that your configuration reads with !env_var.

The chart does not mount a secrets.yml file. Set each API key with api_key: !env_var ... from a Secret as shown above. !secret references and the implicit <instance>_api_key lookups from secrets.yml are not available with the chart.

Storage​

The chart puts the state directory (sync state and job history) on a PersistentVolumeClaim and the data directory (downloaded guides and log files) in an emptyDir volume, which Recyclarr rebuilds when the pod starts again.

ValueDefaultDescription
persistence.enabledtrueStore state on a PersistentVolumeClaim
persistence.existingClaimnoneUse this claim instead of creating one
persistence.storageClassnoneStorageClass for the claim; none uses the cluster default
persistence.accessModeReadWriteOnceAccess mode for the claim
persistence.size1GiSize of the claim

Uninstalling the chart keeps the claim, so a later install with the same release name picks up the same state. Delete the claim yourself when you no longer need it.

danger

With persistence.enabled: false, state lives in an emptyDir and is lost whenever the pod is recreated. Recyclarr then no longer knows which Sonarr and Radarr resources it created (see State Directory).

Log files in the data directory are lost when the pod is recreated. Kubernetes collects the server's console output, so you may want to turn off log files with server.logging.files in settings.content.

Running CLI Commands​

The recyclarr CLI in the pod sends commands to the server in the same pod with the same API key, so it needs no setup. helm install prints the exact command for your release:

kubectl exec deploy/recyclarr -- recyclarr sync --preview

Network and Monitoring​

The chart creates a Service with two ports:

PortNameServes
7982httpThe HTTP API
7983managementHealth probes (/livez, /readyz) and /metrics

The chart creates no Ingress or HTTPRoute. The API is meant for clients inside the cluster, such as the CLI in the pod or your own scripts. Change the API port on the Service with service.port and the Service type with service.type. See Network Security before you expose the API outside the cluster.

The pod has startup, liveness, and readiness probes on the management port. To have the Prometheus Operator scrape metrics, set serviceMonitor.enabled: true. Set serviceMonitor.interval to change the scrape interval and serviceMonitor.labels to add labels your Prometheus selects on.

To export telemetry to an OpenTelemetry Collector, set the OpenTelemetry variables in env:

env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://otel-collector.monitoring:4317
- name: OTEL_RESOURCE_ATTRIBUTES
value: deployment.environment=home

Other Values​

The chart runs one replica with the Recreate update strategy, because only one server can use the state volume at a time. The container runs as UID and GID 1000, as a non-root user, with a read-only root filesystem.

Other values follow common Helm chart conventions: image, imagePullSecrets, nameOverride, fullnameOverride, serviceAccount, podAnnotations, podLabels, podSecurityContext, securityContext, resources, nodeSelector, tolerations, and affinity. To see every value and its default, run:

helm show values oci://ghcr.io/recyclarr/charts/recyclarr

Without the Chart​

If you write your own manifests, these are the parts the chart handles for you:

  • Image ghcr.io/recyclarr/recyclarr:9. It runs as UID and GID 1000 and works with a read-only root filesystem when /tmp is a writable volume.
  • Container ports 7982 (API) and 7983 (management). See Monitoring.
  • startupProbe and livenessProbe on /livez, readinessProbe on /readyz, all on the management port. The server opens no port until the first guide download finishes, so give the startup probe several minutes.
  • The API key in a Secret volume, with RECYCLARR_API_KEY_FILE set to the file path. Without a subPath mount, Kubernetes updates the file when the Secret changes, and the server uses the new key without a restart.
  • Config files mounted read-only under /config, a PersistentVolumeClaim for the state directory (RECYCLARR_STATE_DIR), and an emptyDir for the data directory (RECYCLARR_DATA_DIR).
  • One replica with the Recreate strategy.

Dev Chart​

Each dev image has a matching dev chart. These are extremely unstable and not for production Sonarr or Radarr instances. The dev chart for a branch has version 0.0.0-<branch>, with the branch name changed the same way as the image tag, and it defaults to that branch's dev image:

helm install recyclarr oci://ghcr.io/recyclarr/charts-dev/recyclarr \
--version 0.0.0-master -f values.yaml

The image tag moves with each build, but the chart's default image.pullPolicy is IfNotPresent, so a node keeps using the image it already pulled. Set image.pullPolicy: Always and restart the pod to get the latest build. Dev chart versions follow the same retention as dev images.