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]>
97 lines
7.0 KiB
Markdown
97 lines
7.0 KiB
Markdown
---
|
|
date: 2026-10-30
|
|
branch: feat/pin-pihole-jackett-plex
|
|
title: 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.
|