Files
helm-charts/freesailarr/templates/freesailarr.service.yaml
T
jklein 78d7020dab freesailarr: MediathekArr as the tenth container, off by default (3.1.0+up1.0.0)
MediathekArr fakes a Usenet indexer towards Prowlarr and a SABnzbd downloader
towards Sonarr/Radarr and fetches from the ARD and ZDF media libraries. Both
consumers already share gluetun's network namespace, so they reach it over
127.0.0.1 - no service, no DNS, no ingress detour. Purely additive: the flag
defaults to false and a default render is byte-identical to 3.0.5 (verified
against the previous chart for both the default values and the CI values).

The four things that fail silently without them:

- A START GATE on gluetun. MediathekArr fetches its ruleset once at start and
  never retries; started before the tunnel it answers every Newznab search with
  0 results while the container is up, Ready and quiet. Kubernetes cannot order
  two regular containers and an initContainer would deadlock, so the wait sits
  in front of the image entrypoint: poll gluetun's health server on
  127.0.0.1:9999 and exec the entrypoint afterwards; on timeout the container
  exits rather than starting blind, because a crash loop is visible and an empty
  indexer is not. The startup probe budget (300s) deliberately outlasts the gate
  (180s).
- incomplete/ AND complete/ ON THE SHARED DOWNLOADS CLAIM, not in an emptyDir.
  An emptyDir counts against the container's ephemeral-storage limit, and one
  large download would have the kubelet evict the whole pod with all ten
  containers - the trap ytdlp-web-player documents.
- THE COMPLETE PATH SONARR SEES. The claim is mounted at /downloads exactly as
  sonarr/radarr mount it, and the chart sets DOWNLOAD_COMPLETE_PATH itself, so
  the SABnzbd complete_dir it reports is the same absolute path on both sides.
- TWO PORTS: 5007 (SABnzbd role and UI, primary) and 5008 (Newznab role for
  Prowlarr), both declared to gluetun's firewall and both on one Service. The
  SABnzbd API is at /download/api - /api on 5007 answers with a misleading
  Newznab validation error.

Further details:

- Image pinned by digest (tag + digest): "latest" is a 2024 build, "beta"
  moves. Single-arch linux/amd64. The built-in helm-values manager cannot
  follow that pair, so renovate.json5 gets the chart's first customManagers
  block; verified by dry-run with two fixtures, since a matching and a broken
  rule look identical while the pin is current.
- Hardened as measured: non-root, uid/gid from puid/pgid,
  readOnlyRootFilesystem: true, all capabilities dropped, no PUID/PGID.
- Probes on measured 200 endpoints (there is no health endpoint): readiness and
  startup on /download/, liveness as an exec covering BOTH ports, because one
  container runs two processes and a wedged Newznab half is exactly what makes
  searches come back empty.
- No ingress by default: the UI links its assets with root-absolute paths, so it
  can only be served at the root of a host; on the shared domain that root
  belongs to seerr. A sub-path fails the render instead of producing a broken
  UI.
- values.yaml and NOTES.txt document the geo MARKER PROCEDURE (not a table of
  series), the escape route of a German exit and its price for the whole stack,
  the fail_message: null trap, and the HLS question as an open question.
- CI: mediathekarr enabled in ci/freesailarr/test-values.yaml, install timeout
  raised to 1200s for the extra image and the gate.

Fixes #245
2026-09-08 23:20:16 +02:00

37 lines
1.4 KiB
YAML

{{/*
One ClusterIP service per enabled app container that listens on a port
(recyclarr has none in daemon mode, so it gets no service).
All containers share gluetun's network namespace, so every one of these
services resolves to the same pod IP and they differ only in their port. Their
purpose is a stable, per-app cluster-internal DNS name - each ingress points at
its own app's service - not network separation between the apps.
*/}}
{{- range $app := include "freesailarr.portApps" $ | fromJsonArray }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ $.Release.Name }}-{{ $.Chart.Name }}-{{ $app.name }}-service
spec:
selector:
app: {{ $.Release.Name }}-{{ $.Chart.Name }}-sfs
ports:
- protocol: TCP
port: {{ int $app.port }}
targetPort: {{ $app.name }}
name: {{ $app.name }}
{{- /* An app with more than one port keeps them in ONE service rather than
getting a second object: they belong to the same container and the
same pod IP, and only the primary port is ever addressed by an
ingress. mediathekarr is the only such app today - 5007 (SABnzbd
role, primary) and 5008 (Newznab role). */}}
{{- range $extra := $app.extraPorts | default list }}
- protocol: TCP
port: {{ int $extra.port }}
targetPort: {{ $extra.name }}
name: {{ $extra.name }}
{{- end }}
type: ClusterIP
{{- end }}