Retrofits the repo-wide groundwork that #59 deliberately left out to keep the reviewed scope. Chart 2.0.0+up1.0.0 - a major, because seccompProfile changes runtime behaviour; appVersion stays the freely chosen marker 1.0.0. values.schema.json (#68). The largest schema in the repo: nine app blocks with probes, resources, security contexts, env and image. additionalProperties is false on every chart-owned level; the objects that go verbatim into the pod spec stay open. It rejects a mistyped app name, a mistyped key at any depth and ingress.domain - the key #59 removed, which until now would have been accepted in silence. Null safety (#99), both halves, because they cover different cases. The defaultedDict helper catches a key WITH a chart default, where Helm's coalescing deletes the null before the schema ever sees it; the widened ["object","null"] types catch a key WITHOUT one, where the null survives into validation. Measured on the old chart: radarr.securityContext: null rendered "securityContext: null" - the whole hardening gone - and securityContext.capabilities: null dropped the capability block entirely, so the container kept every default capability instead of dropping ALL. Both render green. The fallback table reproduces THIS chart's defaults including its deviations: the five linuxserver.io containers keep runAsNonRoot unset and a writable root filesystem so their s6 init can drop to PUID/PGID, flaresolverr keeps its numerically pinned uid, gluetun keeps NET_ADMIN, and recyclarr keeps its exec probes. Restoring the "clean" standard there would put the linuxserver containers back on the image's uid 911 - the failure calibre-web-automated hit. The sync between table and values.yaml is not left to discipline: rendering with every block of the silent class explicitly set to null is byte-identical to rendering the defaults, which is how a drift shows up. seccompProfile RuntimeDefault (#84) in the pod context, so it covers the init container too. Trivy's KSV-0104 drops from ten findings to none. NOTES.txt (#43) covering what actually bites: the pod is not Ready until the tunnel is up, the two fields the 1Password item needs, the warning when firewallOutboundSubnets is unset, the immutable volumeClaimTemplates, and the measured fact that imports do not hardlink across the media categories. Also, from point 5 of the plan: checksum/config does not apply - the chart has no ConfigMap - but checksum/secret-ref does, and was missing. Helm never sees the secret's contents, yet it does see which op:// item the OnePasswordItem points at, so repointing secrets.gluetunSecretRef now restarts the pod instead of leaving the old credentials running. README: the #43 status line was stale (it still claimed only homeassistant ships NOTES.txt), and the mandatory-icon rule now records freesailarr as a documented exception - #59 dropped the icon and did not amend the rule.
725 lines
23 KiB
YAML
725 lines
23 KiB
YAML
# freesailarr runs gluetun plus the whole media automation stack in a single
|
|
# StatefulSet pod: every app container shares gluetun's network namespace, the
|
|
# containers talk to each other over localhost and all traffic leaves through
|
|
# the Wireguard tunnel.
|
|
#
|
|
# Image pinning (documented deviation from the Chart.AppVersion standard):
|
|
# NO image tag comes from appVersion. All nine images, gluetun included, are
|
|
# pinned here via <app>.image.repository / <app>.image.tag, because the stack
|
|
# combines nine independently versioned upstream projects and none of them is
|
|
# "the" one app version.
|
|
#
|
|
# That is also what puts every image under Renovate: the built-in helm-values
|
|
# manager reads image.repository/image.tag pairs out of this file and proposes
|
|
# one update per image, and ci/renovate-bump-chart.sh bumps the chart version
|
|
# along with it. A chart whose main image came from appVersion would instead
|
|
# need a hard-coded block in renovate.json5 - freesailarr deliberately has none.
|
|
#
|
|
# Chart.yaml's appVersion is therefore the chart's own version marker, freely
|
|
# chosen and tied to no upstream - not the source of any tag here. Nothing
|
|
# rewrites it automatically; raise it by hand when you want to mark a new
|
|
# edition of the chart as a whole.
|
|
|
|
# Scale the whole chart down without uninstalling it: scaleDown: true renders
|
|
# every Deployment/StatefulSet with replicas: 0 (and suspends CronJobs) and
|
|
# takes precedence over any per-workload replicas value. PVCs, Secrets and
|
|
# Services stay in place; scaleDown: false brings the workloads back up.
|
|
scaleDown: false
|
|
|
|
# Replica count for the whole stack (one pod contains all containers); 0 is
|
|
# allowed and scales it down. The chart-global scaleDown flag takes precedence.
|
|
# More than 1 replica is not meaningful: every replica would run its own
|
|
# isolated stack on its own config volumes.
|
|
replicas: 1
|
|
|
|
secrets:
|
|
# op:// item path for the gluetun VPN credentials. The 1Password item must
|
|
# contain the fields "wireguard-private-key" (the Wireguard private key) and
|
|
# "wireguard-addresses" (the Wireguard interface address, e.g. 10.x.y.z/32).
|
|
gluetunSecretRef: null
|
|
|
|
# User/group the linuxserver.io containers drop to after init (their PUID/PGID
|
|
# mechanism) and the runAsUser/runAsGroup for the seerr and recyclarr
|
|
# containers. Media and config volumes must be writable for this user.
|
|
puid: 1000
|
|
pgid: 1000
|
|
# Timezone for all containers.
|
|
timezone: Europe/Zurich
|
|
|
|
securityContext:
|
|
# Pod-level security context. No pod-level runAsNonRoot/runAsUser: the pod
|
|
# mixes root containers (gluetun, linuxserver.io images) with non-root ones
|
|
# (seerr, recyclarr, flaresolverr); users are set per container instead.
|
|
# fsGroup (keep in sync with pgid) makes freshly provisioned config volumes
|
|
# group-writable for the non-root containers; fsGroupChangePolicy
|
|
# OnRootMismatch avoids recursively re-chowning the (large, shared) media
|
|
# claims on every pod start.
|
|
# seccompProfile RuntimeDefault applies the container runtime's default
|
|
# syscall filter to every container in the pod, init containers included, and
|
|
# is set at pod level so a container added later inherits it without the
|
|
# value being repeated. It is worth naming what it has to survive here:
|
|
# gluetun runs as root with NET_ADMIN, creates a tun device and programs
|
|
# iptables, and the s6-overlay init of the five linuxserver.io images starts
|
|
# as root and drops to PUID/PGID via CHOWN/SETUID/SETGID. Both were verified
|
|
# against a real tunnel under this filter - see the chart's PR.
|
|
# A container that genuinely needs a different filter can still override it
|
|
# under <app>.securityContext, which wins over the pod value.
|
|
pod:
|
|
fsGroup: 1000
|
|
fsGroupChangePolicy: OnRootMismatch
|
|
seccompProfile:
|
|
type: RuntimeDefault
|
|
|
|
storage:
|
|
# StorageClass for all config volumeClaimTemplates (null = cluster default).
|
|
storageClass: null
|
|
|
|
# Media libraries as pre-existing PVCs (shared with the separately deployed
|
|
# Jellyfin) - the chart mounts but never creates them. Each claim is required
|
|
# as soon as an app that mounts it is enabled:
|
|
# downloads: qbittorrent, radarr, sonarr
|
|
# movies: radarr, bazarr
|
|
# tv: sonarr, bazarr
|
|
#
|
|
# subPath mounts a sub-directory of the claim instead of its root (null = the
|
|
# claim root, i.e. one claim per category). The same existingClaim may back all
|
|
# three categories with different subPaths - one library volume, one
|
|
# sub-directory per category, e.g. downloads / movies / tv-shows.
|
|
#
|
|
# What this buys and what it does NOT buy - measured in a k3d cluster against
|
|
# this chart, because the usual argument for a shared volume is hardlinking:
|
|
# - It buys the layout: one claim to provision, back up and share with
|
|
# Jellyfin, with the categories as sibling directories instead of three
|
|
# separate volumes.
|
|
# - It does NOT buy hardlinked imports. Radarr and Sonarr import by moving,
|
|
# and a move within one filesystem can be a hardlink or a rename instead of
|
|
# a copy - but Kubernetes turns every volumeMount into its own bind mount,
|
|
# and link()/rename() across two mount points fails with EXDEV even when
|
|
# both sides are the same claim on the same device. Measured: /downloads and
|
|
# /movies in the radarr container both report device 65025 and resolve to
|
|
# the same PV directory, yet `ln /downloads/f /movies/f` fails with
|
|
# "Cross-device link", while the identical link succeeds when the claim root
|
|
# is mounted once and both categories are sub-directories under it.
|
|
# This is not a property of subPath: two plain mounts of the same claim
|
|
# without any subPath fail exactly the same way, so the chart has never
|
|
# supported cross-category hardlinks.
|
|
# - Consequence today: an import still copies, so download and library each
|
|
# hold a full copy until the torrent is removed.
|
|
# Getting hardlinks would mean giving the apps a single mount that contains all
|
|
# categories (the "one /data mount" layout the *arr guides recommend) instead of
|
|
# one mount per category - a separate change to the chart's mount layout, not a
|
|
# values setting.
|
|
media:
|
|
downloads:
|
|
existingClaim: null
|
|
subPath: null
|
|
movies:
|
|
existingClaim: null
|
|
subPath: null
|
|
tv:
|
|
existingClaim: null
|
|
subPath: null
|
|
|
|
# Ingress defaults. There is deliberately no global domain: every app carries
|
|
# its own <app>.ingress.host, so the hosts are independent of each other and
|
|
# may live in completely different domains. clusterIssuer, className and
|
|
# annotations are the defaults for all apps and can be overridden per app in
|
|
# the <app>.ingress block (an explicitly set per-app value always wins).
|
|
ingress:
|
|
# Master switch: false suppresses every app ingress regardless of the
|
|
# per-app toggles.
|
|
enabled: true
|
|
clusterIssuer: null
|
|
className: nginx
|
|
# Extra annotations for the Ingress objects; merged with the cert-manager
|
|
# cluster-issuer annotation the chart always sets.
|
|
annotations: {}
|
|
|
|
gluetun:
|
|
# Pinned here like every other image in this chart, so Renovate's helm-values
|
|
# manager proposes gluetun updates too. Docker Hub tags carry a v prefix.
|
|
image:
|
|
repository: docker.io/qmcgaw/gluetun
|
|
tag: v3.41.1
|
|
vpn:
|
|
serviceProvider: mullvad
|
|
type: wireguard
|
|
serverCities: Zurich
|
|
serverCountries: Switzerland
|
|
dnsUpstreamResolvers: quad9
|
|
# Comma-separated CIDRs the gluetun firewall allows outbound traffic to
|
|
# outside the VPN tunnel. Set this to the cluster pod and service CIDRs
|
|
# (e.g. "10.42.0.0/16,10.43.0.0/16" on k3s) - without it the firewall
|
|
# blocks cluster-internal egress such as DNS lookups against cluster DNS
|
|
# and seerr talking to the in-cluster Jellyfin.
|
|
firewallOutboundSubnets: null
|
|
storage:
|
|
# Size of the gluetun config volume (server list cache under /gluetun).
|
|
size: 1Gi
|
|
# Extra environment variables, appended to the ones the chart always sets.
|
|
# Values are rendered through tpl; value, secretKeyRef and configMapKeyRef
|
|
# forms are supported. (Same for every <app>.env block below.)
|
|
env: []
|
|
# gluetun's built-in HTTP health server; the chart binds it to :9999 (env
|
|
# HEALTH_SERVER_ADDRESS) so the kubelet probes, which connect to the pod IP,
|
|
# can reach it. It returns 200 only while the VPN tunnel is up and working.
|
|
# Liveness is more tolerant (60s) than readiness (30s): during a short
|
|
# tunnel re-negotiation gluetun recovers on its own and a kubelet restart
|
|
# would only prolong the outage; the kill switch keeps all egress blocked
|
|
# the whole time, so nothing runs unprotected.
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /
|
|
port: 9999
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 6
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /
|
|
port: 9999
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
# The startup probe gates liveness/readiness. Budget for image start plus
|
|
# Wireguard handshake: 5s * 30 = 150s.
|
|
startupProbe:
|
|
httpGet:
|
|
path: /
|
|
port: 9999
|
|
periodSeconds: 5
|
|
timeoutSeconds: 5
|
|
failureThreshold: 30
|
|
resources:
|
|
# Limits are optional: memory and ephemeral-storage limits default to
|
|
# limitFactor x the request, an explicitly set limit always wins, and a
|
|
# CPU limit is only set when configured explicitly under "limits".
|
|
# (Same for every <app>.resources block below.)
|
|
limitFactor: 3
|
|
requests:
|
|
cpu: 0.1
|
|
memory: 128Mi
|
|
ephemeralStorage: 50Mi
|
|
# Deviations from the hardening baseline, forced by gluetun's role as VPN
|
|
# gateway:
|
|
# - runs as root (no runAsNonRoot): required to create the tun device and
|
|
# program the firewall.
|
|
# - NET_ADMIN capability: creates the Wireguard tunnel and the iptables
|
|
# rules (firewall, kill switch).
|
|
# - readOnlyRootFilesystem: false: gluetun rewrites /etc/resolv.conf and
|
|
# other files on its root filesystem at runtime.
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: false
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
add:
|
|
- NET_ADMIN
|
|
|
|
qbittorrent:
|
|
enabled: true
|
|
image:
|
|
repository: docker.io/linuxserver/qbittorrent
|
|
tag: 5.2.1
|
|
# Every app gets its own Ingress object (named <release>-<chart>-<app>-ingress)
|
|
# with its own TLS secret tls-<release>-<chart>-<app>-ingress, so the apps can
|
|
# be exposed independently and under unrelated hosts.
|
|
# host is required while enabled is true and has no default - an app whose
|
|
# ingress is switched off never demands one. clusterIssuer, className and
|
|
# annotations may be set here to override the global ingress block.
|
|
# (Same block for prowlarr, radarr, sonarr, seerr and bazarr below.)
|
|
ingress:
|
|
enabled: true
|
|
host: null
|
|
# clusterIssuer: null
|
|
# className: null
|
|
# annotations: {}
|
|
storage:
|
|
size: 1Gi
|
|
# Network interface qBittorrent binds its BitTorrent session to - gluetun's
|
|
# Wireguard device. Without this binding libtorrent listens and announces on
|
|
# every interface in the shared pod network namespace, including eth0 (the
|
|
# pod IP) and loopback. Those announces bypass the tunnel, so gluetun's kill
|
|
# switch (OUTPUT DROP except tun0 and the allowed cluster subnets) drops
|
|
# them: trackers report "skipping tracker announce (unreachable)", no peers
|
|
# are found and torrents stall at 0 bytes in stalledDL. Binding to tun0 is
|
|
# therefore both the functional fix and a leak fix - it stops qBittorrent
|
|
# from listening on the pod IP past the tunnel. The value is written into
|
|
# /config/qBittorrent/qBittorrent.conf by the config-interface init
|
|
# container below; setting it to null or "" removes that init container and
|
|
# leaves the binding to the user (not recommended).
|
|
networkInterface: tun0
|
|
# The init container that seeds qbittorrent.networkInterface into the
|
|
# persisted qBittorrent config before the app starts. Runs as puid/pgid so
|
|
# the config file keeps the ownership the app expects.
|
|
configInit:
|
|
# Auxiliary busybox image for the init container, pinned here like every
|
|
# other image in this chart and proposed by Renovate the same way.
|
|
image:
|
|
repository: docker.io/busybox
|
|
tag: "1.38.0"
|
|
resources:
|
|
limitFactor: 3
|
|
requests:
|
|
cpu: 10m
|
|
memory: 16Mi
|
|
ephemeralStorage: 1Mi
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: true
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
env: []
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /
|
|
port: 8080
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /
|
|
port: 8080
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
# The startup probe gates liveness/readiness. Startup budget = 5s * 30 = 150s.
|
|
startupProbe:
|
|
httpGet:
|
|
path: /
|
|
port: 8080
|
|
periodSeconds: 5
|
|
timeoutSeconds: 5
|
|
failureThreshold: 30
|
|
resources:
|
|
limitFactor: 3
|
|
requests:
|
|
cpu: 0.2
|
|
memory: 512Mi
|
|
ephemeralStorage: 100Mi
|
|
# Deviations from the hardening baseline, forced by the linuxserver.io
|
|
# images (s6-overlay init that starts as root and drops to PUID/PGID):
|
|
# - no runAsNonRoot: s6-overlay must start as root to apply PUID/PGID and
|
|
# chown /config.
|
|
# - readOnlyRootFilesystem: false: the s6 init applies PUID/PGID by
|
|
# rewriting /etc/passwd and /etc/group and stages runtime state on the
|
|
# root filesystem. With a read-only root filesystem the containers still
|
|
# start, but silently keep the image's built-in uid/gid (911) instead of
|
|
# PUID/PGID (verified at runtime) - unacceptable for the shared media
|
|
# volumes.
|
|
# - capabilities: ALL dropped except what the s6-overlay init needs:
|
|
# CHOWN/FOWNER/DAC_OVERRIDE (taking ownership of /config and /run) and
|
|
# SETUID/SETGID (dropping from root to the PUID/PGID user).
|
|
# (Same block for all linuxserver.io containers: qbittorrent, prowlarr,
|
|
# radarr, sonarr, bazarr.)
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: false
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
add:
|
|
- CHOWN
|
|
- DAC_OVERRIDE
|
|
- FOWNER
|
|
- SETGID
|
|
- SETUID
|
|
|
|
prowlarr:
|
|
enabled: true
|
|
image:
|
|
repository: docker.io/linuxserver/prowlarr
|
|
tag: 2.3.5
|
|
# See the qbittorrent ingress comment.
|
|
ingress:
|
|
enabled: true
|
|
host: null
|
|
# clusterIssuer: null
|
|
# className: null
|
|
# annotations: {}
|
|
storage:
|
|
size: 1Gi
|
|
env: []
|
|
# The *arr apps expose /ping as an unauthenticated health endpoint.
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /ping
|
|
port: 9696
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /ping
|
|
port: 9696
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
# The startup probe gates liveness/readiness. Startup budget = 5s * 30 = 150s.
|
|
startupProbe:
|
|
httpGet:
|
|
path: /ping
|
|
port: 9696
|
|
periodSeconds: 5
|
|
timeoutSeconds: 5
|
|
failureThreshold: 30
|
|
resources:
|
|
limitFactor: 3
|
|
requests:
|
|
cpu: 0.1
|
|
memory: 256Mi
|
|
ephemeralStorage: 100Mi
|
|
# linuxserver.io image - see the qbittorrent securityContext comment.
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: false
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
add:
|
|
- CHOWN
|
|
- DAC_OVERRIDE
|
|
- FOWNER
|
|
- SETGID
|
|
- SETUID
|
|
|
|
flaresolverr:
|
|
enabled: true
|
|
image:
|
|
repository: ghcr.io/flaresolverr/flaresolverr
|
|
tag: v3.5.0
|
|
# No ingress and no config volume: flaresolverr is stateless and only
|
|
# consumed by prowlarr over localhost.
|
|
env: []
|
|
# /health is flaresolverr's dedicated lightweight health endpoint.
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /health
|
|
port: 8191
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /health
|
|
port: 8191
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
# The startup probe gates liveness/readiness. Startup budget = 5s * 30 = 150s.
|
|
startupProbe:
|
|
httpGet:
|
|
path: /health
|
|
port: 8191
|
|
periodSeconds: 5
|
|
timeoutSeconds: 5
|
|
failureThreshold: 30
|
|
resources:
|
|
limitFactor: 3
|
|
requests:
|
|
cpu: 0.2
|
|
memory: 512Mi
|
|
ephemeralStorage: 200Mi
|
|
# Deviations from the hardening baseline, forced by the flaresolverr image:
|
|
# - readOnlyRootFilesystem: false: on startup flaresolverr copies and
|
|
# patches the chromedriver binary to the hardcoded path /app/chromedriver
|
|
# and writes chromedriver caches under /app (its home directory).
|
|
# - runAsUser/runAsGroup pin the image's "flaresolverr" user numerically
|
|
# (uid/gid 1000; the image declares it by name only, which the kubelet's
|
|
# runAsNonRoot check cannot verify).
|
|
# Chromium's scratch paths (/tmp, /dev/shm) are emptyDirs.
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: false
|
|
runAsNonRoot: true
|
|
runAsUser: 1000
|
|
runAsGroup: 1000
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
|
|
radarr:
|
|
enabled: true
|
|
image:
|
|
repository: docker.io/linuxserver/radarr
|
|
tag: 6.1.1
|
|
# See the qbittorrent ingress comment.
|
|
ingress:
|
|
enabled: true
|
|
host: null
|
|
# clusterIssuer: null
|
|
# className: null
|
|
# annotations: {}
|
|
storage:
|
|
size: 1Gi
|
|
env: []
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /ping
|
|
port: 7878
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /ping
|
|
port: 7878
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
# The startup probe gates liveness/readiness. Startup budget = 5s * 30 = 150s.
|
|
startupProbe:
|
|
httpGet:
|
|
path: /ping
|
|
port: 7878
|
|
periodSeconds: 5
|
|
timeoutSeconds: 5
|
|
failureThreshold: 30
|
|
resources:
|
|
limitFactor: 3
|
|
requests:
|
|
cpu: 0.1
|
|
memory: 256Mi
|
|
ephemeralStorage: 100Mi
|
|
# linuxserver.io image - see the qbittorrent securityContext comment.
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: false
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
add:
|
|
- CHOWN
|
|
- DAC_OVERRIDE
|
|
- FOWNER
|
|
- SETGID
|
|
- SETUID
|
|
|
|
recyclarr:
|
|
enabled: true
|
|
image:
|
|
repository: ghcr.io/recyclarr/recyclarr
|
|
tag: 8.6.0
|
|
# No ingress: recyclarr has no web UI, it syncs TRaSH guides to radarr and
|
|
# sonarr on a schedule (daemon mode).
|
|
storage:
|
|
size: 1Gi
|
|
env: []
|
|
# recyclarr serves no HTTP port in daemon mode, so all probes exec the CLI.
|
|
livenessProbe:
|
|
exec:
|
|
command:
|
|
- recyclarr
|
|
- --version
|
|
periodSeconds: 30
|
|
timeoutSeconds: 10
|
|
failureThreshold: 3
|
|
readinessProbe:
|
|
exec:
|
|
command:
|
|
- recyclarr
|
|
- --version
|
|
periodSeconds: 30
|
|
timeoutSeconds: 10
|
|
failureThreshold: 3
|
|
# The startup probe gates liveness/readiness. Startup budget = 5s * 30 = 150s.
|
|
startupProbe:
|
|
exec:
|
|
command:
|
|
- recyclarr
|
|
- --version
|
|
periodSeconds: 5
|
|
timeoutSeconds: 10
|
|
failureThreshold: 30
|
|
resources:
|
|
limitFactor: 3
|
|
requests:
|
|
cpu: 0.05
|
|
memory: 128Mi
|
|
ephemeralStorage: 50Mi
|
|
# The image supports running as an arbitrary non-root user; runAsUser and
|
|
# runAsGroup are set from the global puid/pgid values in the template - do
|
|
# not set them here.
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: true
|
|
runAsNonRoot: true
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
|
|
sonarr:
|
|
enabled: true
|
|
image:
|
|
repository: docker.io/linuxserver/sonarr
|
|
tag: 4.0.17
|
|
# See the qbittorrent ingress comment.
|
|
ingress:
|
|
enabled: true
|
|
host: null
|
|
# clusterIssuer: null
|
|
# className: null
|
|
# annotations: {}
|
|
storage:
|
|
size: 1Gi
|
|
env: []
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /ping
|
|
port: 8989
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /ping
|
|
port: 8989
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
# The startup probe gates liveness/readiness. Startup budget = 5s * 30 = 150s.
|
|
startupProbe:
|
|
httpGet:
|
|
path: /ping
|
|
port: 8989
|
|
periodSeconds: 5
|
|
timeoutSeconds: 5
|
|
failureThreshold: 30
|
|
resources:
|
|
limitFactor: 3
|
|
requests:
|
|
cpu: 0.1
|
|
memory: 256Mi
|
|
ephemeralStorage: 100Mi
|
|
# linuxserver.io image - see the qbittorrent securityContext comment.
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: false
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
add:
|
|
- CHOWN
|
|
- DAC_OVERRIDE
|
|
- FOWNER
|
|
- SETGID
|
|
- SETUID
|
|
|
|
seerr:
|
|
enabled: true
|
|
image:
|
|
repository: ghcr.io/seerr-team/seerr
|
|
tag: v3.3.0
|
|
# See the qbittorrent ingress comment.
|
|
ingress:
|
|
enabled: true
|
|
host: null
|
|
# clusterIssuer: null
|
|
# className: null
|
|
# annotations: {}
|
|
storage:
|
|
size: 1Gi
|
|
env: []
|
|
# /api/v1/settings/public answers unauthenticated once the app is up.
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /api/v1/settings/public
|
|
port: 5055
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /api/v1/settings/public
|
|
port: 5055
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
# The startup probe gates liveness/readiness. First boot runs database
|
|
# migrations: budget 10s * 30 = 300s.
|
|
startupProbe:
|
|
httpGet:
|
|
path: /api/v1/settings/public
|
|
port: 5055
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 30
|
|
resources:
|
|
limitFactor: 3
|
|
requests:
|
|
cpu: 0.1
|
|
memory: 256Mi
|
|
ephemeralStorage: 100Mi
|
|
# The image runs fine as an arbitrary non-root user; runAsUser and
|
|
# runAsGroup are set from the global puid/pgid values in the template - do
|
|
# not set them here.
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: true
|
|
runAsNonRoot: true
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
|
|
bazarr:
|
|
enabled: true
|
|
image:
|
|
repository: docker.io/linuxserver/bazarr
|
|
tag: 1.5.6
|
|
# See the qbittorrent ingress comment.
|
|
ingress:
|
|
enabled: true
|
|
host: null
|
|
# clusterIssuer: null
|
|
# className: null
|
|
# annotations: {}
|
|
storage:
|
|
size: 1Gi
|
|
env: []
|
|
# bazarr has no unauthenticated health endpoint; / serves the UI with 200.
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /
|
|
port: 6767
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /
|
|
port: 6767
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
# The startup probe gates liveness/readiness. Startup budget = 5s * 30 = 150s.
|
|
startupProbe:
|
|
httpGet:
|
|
path: /
|
|
port: 6767
|
|
periodSeconds: 5
|
|
timeoutSeconds: 5
|
|
failureThreshold: 30
|
|
resources:
|
|
limitFactor: 3
|
|
requests:
|
|
cpu: 0.1
|
|
memory: 256Mi
|
|
ephemeralStorage: 100Mi
|
|
# linuxserver.io image - see the qbittorrent securityContext comment.
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: false
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
add:
|
|
- CHOWN
|
|
- DAC_OVERRIDE
|
|
- FOWNER
|
|
- SETGID
|
|
- SETUID
|