0052. Event-Driven Renovate Runs and Etcd Version Cap¶
- Status: accepted
- Date: 2026-07-25
- Deciders: lusoris
- Related: PR #3046
Context¶
Renovate runs as two 6h CronJobs (Gitea autodiscover at 4Gi, GitHub lusoris/k8s at 2Gi), both on the digest-pinned renovate/renovate:43 image, as the baseline dependency sweep. There was no way to force an immediate run: ticking a checkbox on the Dependency Dashboard meant waiting up to six hours for the next fire.
Renovate OSS is run-and-exit with no webhook listener (only Mend CE/EE ships one), so an immediate-apply path has to be an event-triggered CLI invocation scoped to the one repo that fired the event.
Separately, the etcd snapshot tooling image (registry.k8s.io/etcd, used by cluster/monitoring/etcd-snapshot-cronjob.yaml) must track the control-plane server minor — kubeadm runs etcd 3.6.x, and running etcdctl/etcdutl from a newer minor against an older server is unsupported skew — yet Renovate would otherwise propose 3.7.x bumps. Reference detail lives in apps/dev/renovate/README.md.
Decision¶
Add event-driven on-demand runs as an additive path (the 6h CronJobs stay the baseline sweep) and cap the etcd tooling minor:
- GitHub (
lusoris/k8s) — new.github/workflows/renovate-on-demand.ymlfires onissues: [edited]andworkflow_dispatch. The job guard passes for anyworkflow_dispatch, or for an issue edit only when the title is the Renovate Dependency Dashboard and the body contains a checked box ([x]). The run is scoped withRENOVATE_REPOSITORIES=${{ github.repository }}andRENOVATE_ONBOARDING=false, uses the PATRENOVATE_TOKEN(the built-inGITHUB_TOKENis rejected because its PRs would not trigger CI), pins the samerenovate/renovate:43digest as the CronJobs, setspermissions: contents: read, a 30-minute timeout, and arenovate-on-demandconcurrency group withcancel-in-progress: falseso queued runs coalesce. - Gitea (
git.dev.cauda.devorg repos) — Gitea Actions fires per-repo, so there is no central workflow; the on-demand path ships as a documented template in the README to commit opt-in as.gitea/workflows/renovate-on-demand.yamlper repo. It runs on the in-cluster capacity-1act_runner(runs-on: cauda-k8s), setsRENOVATE_AUTODISCOVER=false+RENOVATE_REPOSITORIES=${{ gitea.repository }}, forces IPv4-only DNS viaNODE_OPTIONS(pods have no routable IPv6), and needs org-level Actions secretsRENOVATE_TOKEN(Gitea PAT) andRENOVATE_GITHUB_COM_TOKEN(GitHub PAT for release-notes lookups). Gitea 1.27 supports theissues: editedtrigger,workflow_dispatch, andconcurrency. - Etcd minor cap — add a
renovate.jsonpackageRule cappingregistry.k8s.io/etcd(datasourcedocker) to<3.7, because kubeadm's etcd server is 3.6.x and snapshot tooling from a newer minor against it is unsupported skew (consistent with declined PR #2481). Lift the cap only after the control-plane etcd itself moves to 3.7.
Alternatives considered¶
- Webhook-driven immediate runs (as in Mend CE/EE): unavailable — Renovate OSS ships no webhook listener; an event-triggered CLI invocation through the existing CI schedulers is the OSS-compatible equivalent.
- Filter Renovate's own dashboard rewrites by actor: impossible — the bot and the operator share the same PAT account and are indistinguishable by actor. The
[x]-in-body guard is used instead: Renovate rewrites the dashboard all-unchecked after acting, so its own edits fail the guard and skip the job (0 billable minutes, no loop). - Use
GITHUB_TOKENfor the GitHub on-demand job: rejected — PRs opened byGITHUB_TOKENdo not trigger downstream CI; the run uses a PAT (same account as the CronJob). - A single central Gitea on-demand workflow: not possible — Gitea Actions triggers per-repo, so the path is an opt-in per-repo template rather than one shared workflow.
- Add a cross-process lock or shared cache to prevent races: unnecessary — Renovate OSS has no cross-process lock, an empty
baseDirgives each run its own private temp dir, and no cache volume is persisted, so there is no shared state to corrupt. Serialization comes from theconcurrencygroup (GitHub) and the capacity-1act_runner(Gitea). - Let Renovate bump etcd to 3.7: rejected — unsupported
etcdctl/etcdutl-vs-server minor skew against kubeadm's 3.6.x etcd, matching the earlier declined PR #2481.
Consequences¶
- Ticking a Dependency Dashboard checkbox now triggers an immediate repo-scoped run instead of waiting up to six hours; the 6h CronJobs remain the baseline sweep, and the on-demand path is purely additive.
- The GitHub path is live as a central workflow; the Gitea path is opt-in per repo via the committed template. Both require their respective Actions secret(s), and the GitHub workflow's image pin must stay in sync with the CronJobs (its github-actions manager keeps
jobs.<id>.containermanaged). - The
[x]-guard breaks the bot loop: Renovate's all-unchecked dashboard rewrites do not fire the job, so no-op dashboard edits cost 0 billable minutes. - One residual race is accepted and documented: an event run versus the 6h sweep on the same repo is not lockable across the two schedulers; it is platform-level only (racing branch pushes / PR edits) and self-corrects on the next run.
- The etcd snapshot tooling stays pinned
<3.7; the cap must be lifted when the control-plane etcd moves to 3.7, otherwise snapshot/restore tooling would drift ahead of the server minor.
References¶
- PR #3046 — feat(dev): event-driven renovate runs + etcd minor cap