Files
home-network-k3s-impl/decisions/2026-10-30-pin-pihole-jackett-plex.md
T
jakman85andClaude Opus 5.5 183bca6897
gate / gate (pull_request) Successful in 2m57s
gate / conformance (pull_request) Has been skipped
feat(images): pin pihole, jackett and plex to the digests already running; Renovate follows them
pihole/pihole (no tag)               -> 2026.10.0               sha256:d3413471...
lscr.io/linuxserver/jackett:latest   -> v0.24.2865-ls7          sha256:4fcf3cc2...
plexinc/pms-docker:latest            -> 1.43.4.10903-e5521bd8c  sha256:e0ab2739...

Each tag was resolved against its registry and matched the pods' imageID, so the image is
unchanged (the pod template string does change, so Flux rolls the three workloads).

renovate.json5: regex versioning for jackett (-lsN) and plex (build-hex); jackett is looked
up on ghcr.io via overridePackageName, because lscr.io is capped at dockerMaxPages=20 pages
and jackett's 32k tags put the running one at #31,980 (dry run proposed nothing without it);
jackett weekly (13 builds in 12 days); pihole deliberately unheld, year rollover = major.
Stale "publishes only latest" prose fixed in renovate.json5 and three runbooks.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-31 10:38:07 -05:00

7.0 KiB

date, branch, title
date branch title
2026-10-30 feat/pin-pihole-jackett-plex Pin pihole, jackett and plex to the digests already running, and make Renovate able to follow them

What changed

  • catalog/{pihole,jackett,plex}.yaml source.image pinned to the tag whose digest was already running, so the image does not change:
    • pihole/pihole (no tag) -> pihole/pihole:2026.10.0
    • lscr.io/linuxserver/jackett:latest -> lscr.io/linuxserver/jackett:v0.24.2865-ls7
    • plexinc/pms-docker:latest -> plexinc/pms-docker:1.43.4.10903-e5521bd8c
  • apps/wave-0/{pihole,jackett,plex}.yaml re-rendered (render.py --all catalog -o apps --wave-layout --no-image-automation, in the toolbox). The diff is exactly the three app-container image: lines; nothing else moved.
  • catalog/jackett.yaml update.range comment: "stay on the Jackett 0.22.x stable line" was false (0.24 runs, and >=0.22.0 has no ceiling). Range unchanged; comment corrected.
  • renovate.json5, four packageRules plus a comment block:
    • jackett versioning: regex:^v(major).(minor).(patch)-ls(build)$ (Renovate's linuxserver example).
    • jackett overridePackageName: ghcr.io/linuxserver/jackett: not in the brief, and needed. Renovate's docker datasource reads at most dockerMaxPages (20, a global-only option) tag pages from any host except a short list that includes ghcr.io (1000 pages). lscr.io is not on that list. Jackett has 32,093 tags, oldest first, ~1000 per page; the running tag is #31,980. Before this rule the dry run extracted jackett at v0.24.2865-ls7 and proposed nothing, with no warning. The override changes only the lookup; the manifests keep lscr.io/.... Every jackett rule matches on depName, because the override rewrites packageName.
    • jackett schedule: after 3am and before 6am on sunday, i.e. weekly. Measured: 13 ls builds in 12 days (ls7 built 2026-10-17, ls20 built 2026-10-29). Each is a patch and auto-merges, so on the daily window it would mean a PR, a gate run and a jackett restart (Recreate) every day. Weekly picks the newest tag, so it skips nothing. catalog/jackett.yaml update.cadence still says daily. That field fed the retired Flux image-automation, and the rule's description says the rule is now the cadence that takes effect.
    • plex versioning: regex:^(major).(minor).(patch).(build)-[0-9a-f]+$.
    • pihole: no rule, as the operator decided. CalVer parses under default docker versioning. Patches and minors auto-merge, and a year rollover is a major (dashboard approval). This is written in a comment.
    • Corrected the "WHAT RENOVATE STILL CANNOT FIX" comment. It listed these three as floating; they publish immutable version tags.
    • No allowedVersions mirror was added. None of the three catalog ranges has a ceiling (>=2024.0.0, >=0.22.0, >=1.40.0), so #86's mirror has nothing to encode for them.
  • Runbooks: image-policy-stalled.md no longer says jackett and pms-docker are latest-only. In plex-quicksync.md, "the floating-image caveat" became "the image-version caveat", because the deployment no longer runs :latest with an implicit Always, and the symptom is now "after a pms-docker bump". plex-claim.md's two "running :latest" mentions are now in the past tense.

What I verified

  • Live digests (read-only kubectl --context k3s-prod, pod .status.containerStatuses[].imageID): pihole-0 and pihole-1 sha256:d34134716fc3…, jackett sha256:4fcf3cc22dd3…, plex sha256:e0ab27395614….
  • Each chosen tag resolves to the same digest (anonymous registry HEAD, OCI index + manifest-list Accept): pihole/pihole:2026.10.0 = sha256:d34134716fc3…; ghcr.io/linuxserver/jackett:v0.24.2865-ls7 = sha256:4fcf3cc22dd3…; plexinc/pms-docker:1.43.4.10903-e5521bd8c = sha256:e0ab27395614…. (For contrast, pms-docker:latest is now sha256:6d778d41… and jackett:latest sha256:ee6ae915…. The pods would have drifted on their next restart.)
  • renovate-config-validator (ghcr.io/renovatebot/renovate:44.167.0) reports "Config validated successfully". The only warning is the existing docker block migration.
  • Renovate dry run (RENOVATE_PLATFORM=local, --dry-run=full, 44.167.0, anonymous, includePaths limited to the six files). It extracted all three from both catalog/ (custom regex) and apps/wave-0/ (kubernetes) under the same depName, so each lands in one branch:
    • plex 1.43.4.10903-e5521bd8c -> 1.43.5.11079-b3b13e506 (patch, renovate/plexinc-pms-docker-1.x)
    • jackett v0.24.2865-ls7 -> v0.24.2961-ls20 (patch, renovate/lscr.io-linuxserver-jackett-0.x). This needs the ghcr override; without it there was no proposal.
    • pihole 2026.10.0 -> none. That is correct, because 2026.10.0 is the newest numbered tag on Docker Hub.
  • Automerge, schedule and dashboard flags come from Renovate's own applyPackageRules (datasource-merge, then update-type-merge, the same order as flatten.js), run on the resolved config. The local platform does not run the branch worker:
    • plex patch: automerge true, daily window.
    • jackett patch: automerge true, schedule sunday window.
    • pihole (synthetic updates) 2026.10.1 patch and 2026.11.0 minor: automerge true. 2027.01.0 major: automerge false, dependencyDashboardApproval true, +needs-review/breaking.
  • Versioning filters (Renovate's versioning module): the jackett regex rejects latest, bare 0.24.2961, amd64-… and development-…. The plex regex rejects latest, public, beta, plexpass and …-amd64/…-arm64. Docker versioning ranks 2026.09.0 < 2026.10.0.
  • Touched paths (catalog/, apps/, renovate.json5, runbooks/, decisions/) are not in infra/gitea/approval-policy.json sensitive_paths.

What I did NOT verify

  • That the merge is restart-free. It is not. The pod-template image string changes, so Flux rolls all three: plex and jackett are Recreate, so each has a brief outage, and pihole is a 2-replica StatefulSet that rolls one pod at a time. The digest is identical, so the image's behaviour should not change, but the kubelet resolves the new tag name and may pull it. The rollout itself was not observed.
  • The implicit imagePullPolicy moves from Always (:latest or no tag) to IfNotPresent. This is intended, and was not observed live.
  • A real (non-dry) Renovate run against Gitea, and whether the Sunday window actually opens a jackett PR. The schedule was only evaluated, not exercised.
  • Other lscr.io/linuxserver/* images (radarr, sonarr, qbittorrent) may hit the same 20-page truncation once their tag counts grow. Not measured here, and not changed.
  • Plex not self-updating on a version tag was checked only against the running pod (read-only kubectl exec cat). /etc/cont-init.d/50-plex-update does exit 0 when version from /version.txt equals the installed plexmediaserver package. Both are 1.43.4.10903-e5521bd8c. I did not boot a pod on a new tag to watch that short-circuit.