k8s-components-checker
Survey an RKE2 community cluster, cross-reference against the embedded
compatibility registry, produce a verdict. Community editions only. Air-gapped
at use time — references/ carries everything needed and the survey runs fully
offline. Air-gap-complete is a floor, not a ceiling: when the workstation has
internet + gh, grounding every specific version the verdict cites is mandatory
(House Rule #8 · references/version-verification.md) — the registry's sifted
patch numbers are methodology, not trusted release facts.
Surveys, never upgrades. This skill produces a verdict; it does not move a
cluster. When the verdict says a component must move, hand off to the skill that
owns that ladder: rancher-upgrade (Rancher + the downstream RKE2/K3s
fleet, same k8s plugin), harvester-upgrade (Harvester HCI, harvester
plugin), mimir-upgrade (Grafana Mimir, observability plugin). Those
skills read this one's compatibility registry as input and treat it as the
matrix authority — that split is deliberate, so keep upgrade procedure out of
here and compatibility claims out of them.
Two registry components have no upgrade ladder because the answer is migration,
not a version bump: a Zalando postgres-operator verdict hands off to
postgres-operator-cloudnative-pg-migration (k8s plugin), and a
rancher-logging verdict to rancher-logging-exit (observability).
The registry is methodology, not inventory. It encodes which versions of
which components are compatible with which Kubernetes minors. It does not — and
must not — record what's actually running where.
Quick decision guide
| Task |
Go to |
| Run a survey + answer an upgrade-readiness question |
§ Survey workflow below |
| Look up one component's k8s support window |
references/components.md |
| Read what changed for compat in a specific component minor |
references/compat/<comp>.md |
| Which kubectl/helm/pluto commands to run, and how to parse output |
references/cluster-survey.md |
| Which deprecated-API tools to trust and how |
references/tooling.md |
| Verify a version exists / find the real latest patch (online) |
references/version-verification.md |
Source URLs + last-verified timestamps (read-only — freshen writes here) |
references/sources.md |
Survey workflow
The operator runs the skill against a kubeconfig pointing at one cluster at a
time. Network access to the target cluster is assumed (direct or via
VPN/bastion). The cluster survey itself makes no internet calls; the one
sanctioned outbound path is version grounding — when internet + gh are
available the verdict's specific version numbers MUST be confirmed against real
releases (House Rule #8 · references/version-verification.md).
First identify the change set — what's being upgraded and from what to
what. Five shapes the skill answers:
- anchor bump —
k8s <current> → <target> (e.g. RKE2 1.32 → 1.34)
- single leaf —
<component> <current> → <target> (e.g. Cilium 1.18 → 1.19)
- combined — multiple bumps in one upgrade window
(e.g.
k8s 1.32 → 1.34 + Argo CD 3.0 → 3.2)
- drift review — no specific target; report what's stale / EOL'd / unpatched
- feasibility — find the highest tolerable bump on one axis given the
others are pinned (e.g. "highest Argo CD that supports our k8s 1.32")
Then run the survey and verdict per references/cluster-survey.md (Phases 1–5:
cluster identity → component detection → deprecated-API liability via the
apiserver metric + pluto → cross-reference against references/components.md
and references/compat/<comp>.md → assemble the verdict per § Verdict format,
ordering the action plan by the compat files' upgrade-ordering rules).
For a drift review (no target), the survey still runs; the verdict reports
against the current k8s minor only, flagging components whose installed version
is approaching or past upstream EOL.
Verdict format
The header carries the change set (see § Survey workflow) — anchor bump,
single leaf, combined, drift review, or feasibility. The per-row reason at the
end of each ✓ ready / ⚠ needs bump line is composed from the compat data
and is change-set-specific (supports k8s 1.32..1.34 for an anchor bump,
compat with target Cilium 1.19 for a leaf bump, current version EOL'd 2025-10-07 for drift, etc.).
<cluster name or kubeconfig context> — <change set>
✓ ready
- <component> <version> <change-set-specific reason>
⚠ needs bump
- <component> <version> → ≥ <target> <reason — what blocks the change set>
source: references/compat/<comp>.md § <version>
# <target> is the furthest-coverage version (House Rule #9) — covers this hop
# AND the operator's next known hop, not the bare immediate-hop minimum.
# A row that satisfies the current target but sits at its own support ceiling
# belongs HERE (with the forward-covering target named), not under ✓ ready.
⚠ ordering
- <component A> must reach <version> BEFORE <component B> reaches <version>
reason: <one-liner>
source: references/compat/<a>.md § <version>
✗ blockers
- <deprecated API>: still served (<N requests/day>) — source: <namespace/workload>
- <component> <version>: <reason — current-state issue or change-set blocker>
source: references/compat/<comp>.md § <version>
✗ out of registry scope
- <component> <version>: below registry's min_tracked_version (<floor>);
verdict abstained. Bump to a tracked version, or add an override in
references/components.md.
action plan
1. <ordered step>
2. <ordered step>
...
✓ ready rows are noise after the first survey — collapse them by default in
follow-up surveys unless the operator asks for the full list. ⚠ and ✗ rows
always show.
Verdict vs report. The verdict above is the technical core, suitable for
in-conversation use and runbook PRs. When the operator asks for a pre-upgrade
report (for JIRA, change management, audit, mgmt review), wrap the verdict in
the layout from references/report-format.md — same content, recognizable
section skeleton across runs so prior reports compare cleanly.
House rules
These are non-negotiable; encode them into every verdict.
- Community editions only. Any Prime / EE / paid-tier feature, version, or
support window is out of scope. Ignore SUSE Prime backports. Ignore GitLab
EE-only features (the operator runs the EE binary as CE; treat as CE).
- Axis discipline. A component's
axis_type is multi only when the
operator picks two or more dimensions independently. Container runtime,
driver version, GPU architecture — all derived from other choices and
therefore NOT axes. RKE2 → containerd is fixed; don't treat it as a variable.
- Min-tracked-version is overridable per component. Default floor is
"current + prior 2 minors" (~18 months). Operator overrides set per-component
min_tracked_version: in references/components.md; skill-improver freshen respects overrides and trims unset rows.
- Apiserver metric is the truth source for deprecated APIs. It reports
what the cluster has actually served. Pluto's bundled rule set goes stale;
use it for manifest-side static scans, never as primary. Kubent is dead
(rulesets stop at k8s 1.32); do not use.
- Harvester ordering: any survey involving Harvester + RKE2 must check the
Harvester compat file for ordering rules before emitting an action
plan. Some Harvester↔RKE2 combinations require Harvester to upgrade first;
missing this turns the upgrade plan into a cluster-rebuild.
- Cite sources. Every
⚠ and ✗ row carries a source: line pointing at
the exact references/compat/<comp>.md § <version> block that
produced the finding. No unsourced verdicts.
- Abstain when the registry is silent. If the registry doesn't carry
enough signal to verdict a row, abstain on that component and recommend
running
skill-improver freshen <skill> from an internet-accessible
client.
- Never invent versions; ground or abstain. k8s support windows are
registry methodology (cite the compat file). Specific version numbers —
latest patch, newest minor, "CVE fixed in vX.Y.Z", a recommended target patch
— are volatile and the #1 fabrication risk (a past verdict cited an Argo CD
v3.2.10 that never existed; the 3.2 line ended at v3.2.6). State a
specific release only if it is (a) cluster-reported, (b) grounded against a
freshly fetched release listing, or (c) explicitly marked UNVERIFIED. When
internet + gh are available, grounding is mandatory and uses the
anti-confirmation method — enumerate the real tag list (naming no candidate)
and derive the latest patch per minor line, and never ask "does vX
exist?" (a named guess biases you toward confirming it). releases/latest
is recency, not rank — it's the most-recently-published / maintainer-pinned
release, NOT the highest version, so never reject a higher enumerated minor
because it exceeds releases/latest (that misfire struck the real Harbor
2.15.x while releases/latest was 2.14.4 — a back-ported patch to an old
line outranks a newer minor by date). Existence is not edition:
for a vendor with a community/Prime (or OSS/EE) split that ships both to one feed
(Rancher), a real, older patch can be Prime-only and will rubber-stamp as
community — sort -V | tail -1 returns a Prime patch for any non-current minor.
Apply the release-notes edition discriminator, don't trust version order. Full
protocol + component→repo map + edition discrimination:
references/version-verification.md.
- Target furthest coverage, not the immediate-hop minimum. When a row needs
a bump, recommend the lowest version whose support window also covers every
known or queued next hop — never the bare minimum that only clears the current
change set. If a newer minor already exists, is stable, and covers both the
current target and the next planned minor, recommend it directly. A version
that satisfies the current target but lands on its own support ceiling is a
⚠, not a ✓ — say so and name the forward-covering target, because shipping
it forces an avoidable second bump one hop later. Step minor-by-minor ONLY when
(a) mandatory sequential stops exist (GitLab app stops, Rancher CAPI conversion)
or (b) skipping stacks breaking changes too aggressively — and even then, name
the end-state target version, not just the next step. Always ask "what is
the operator's next hop after this one, and does my recommended version
already cover it?" before emitting a → ≥ <target>. (Encoded after a real
miss: a k8s 1.32 → 1.33 handoff recommended KEDA 2.18.3 — CVE-patched and
1.33-valid but at the 2.18 ceiling, even though the handoff itself noted "1.34
would need ≥ 2.19 later" — while KEDA 2.19.0 (k8s 1.32–1.34, same CVE fix)
already existed and would have covered the very next 1.33 → 1.34 hop in one
bump. The look-ahead was known and not acted on.)
Truth-source-type — branch the lookup
Each component in the registry carries a truth_source_type field that says
where the compat truth lives. The skill branches on it when reading
references/compat/<comp>.md:
| Type |
What the file contains |
published_matrix |
Distilled rows extracted from the vendor's k8s support matrix, per-version. |
release_notes |
Sifted highlights from GitHub release notes — breaking, CRD, k8s floor, ordering. |
chart_metadata |
Helm Chart.yaml's kubeVersion: constraint per chart-release tag, plus chart→app mapping. |
The branching matters at maintenance time (freshen probes different sources)
and at use time (the verdict cites a different kind of evidence per row).
References
references/components.md — the 19-entry registry (table for single-axis, stanzas for multi-axis). Carries axis_type, truth_source_type, source URL, min_tracked_version. The lookup table the survey reads.
references/cluster-survey.md — the canonical command set: kubectl/helm/pluto/apiserver-metric. Detection patterns for mapping running workloads onto registry entries.
references/tooling.md — apiserver apiserver_requested_deprecated_apis metric (primary), pluto (static manifest scan), kubent dead.
references/compat/README.md — file-format spec for per-component compat files.
references/compat/<comp>.md — one per component. The load-bearing per-version compatibility signal. Air-gap-complete.
references/version-verification.md — anti-fabrication protocol (House Rule #8): how to ground every cited version against real releases via gh (the anti-confirmation method + component→repo map). Read whenever the workstation is online.
references/sources.md — URL index with Last verified: timestamps. Maintained by skill-improver freshen; read at use time only to surface staleness in the verdict if a row is past 90 days.
references/report-format.md — pre-upgrade report layout: fixed section skeleton (header table, exec summary, survey, verdict, diff vs prior, action plan, methodology) with dynamic content. Used when the operator asks for a report rather than a verdict.
1---2name: k8s-components-checker3description: Survey an RKE2 community cluster against an embedded compatibility registry of 19 stack components and produce a verdict for upgrade-readiness, drift-review, and version-skew questions. Components: RKE2, Rancher, Harvester, Cilium, Tetragon, cert-manager, Kyverno, KEDA, Argo CD, Harbor, Traefik, Rook, Ceph, OpenEBS, GitLab, ECK, Zalando postgres-operator, Grafana Mimir, NVIDIA GPU Operator. Works air-gapped — compatibility data lives in `references/compat/`. Surveys run via `kubectl` + `helm` + `pluto` + the apiserver `apiserver_requested_deprecated_apis` metric from the operator's workstation. Community editions only — Prime/EE-gated content is ignored. NOT for installing components, NOT for executing upgrades, NOT for tracking per-cluster running state (the registry is methodology, not inventory).4---56# k8s-components-checker78Survey an RKE2 community cluster, cross-reference against the embedded9compatibility registry, produce a verdict. Community editions only. Air-gapped10at use time — `references/` carries everything needed and the survey runs fully11offline. Air-gap-complete is a **floor, not a ceiling**: when the workstation has12internet + `gh`, grounding every specific version the verdict cites is mandatory13(House Rule #8 · `references/version-verification.md`) — the registry's sifted14patch numbers are methodology, not trusted release facts.1516**Surveys, never upgrades.** This skill produces a verdict; it does not move a17cluster. When the verdict says a component must move, hand off to the skill that18owns that ladder: **`rancher-upgrade`** (Rancher + the downstream RKE2/K3s19fleet, same `k8s` plugin), **`harvester-upgrade`** (Harvester HCI, `harvester`20plugin), **`mimir-upgrade`** (Grafana Mimir, `observability` plugin). Those21skills read this one's compatibility registry as input and treat it as the22matrix authority — that split is deliberate, so keep upgrade procedure out of23here and compatibility claims out of them.2425Two registry components have no upgrade ladder because the answer is migration,26not a version bump: a Zalando postgres-operator verdict hands off to27**`postgres-operator-cloudnative-pg-migration`** (`k8s` plugin), and a28`rancher-logging` verdict to **`rancher-logging-exit`** (`observability`).2930The registry is **methodology**, not inventory. It encodes which versions of31which components are compatible with which Kubernetes minors. It does not — and32must not — record what's actually running where.3334## Quick decision guide3536| Task | Go to |37|------|-------|38| Run a survey + answer an upgrade-readiness question | § Survey workflow below |39| Look up one component's k8s support window | `references/components.md` |40| Read what changed for compat in a specific component minor | `references/compat/<comp>.md` |41| Which kubectl/helm/pluto commands to run, and how to parse output | `references/cluster-survey.md` |42| Which deprecated-API tools to trust and how | `references/tooling.md` |43| Verify a version exists / find the real latest patch (online) | `references/version-verification.md` |44| Source URLs + last-verified timestamps (read-only — `freshen` writes here) | `references/sources.md` |4546## Survey workflow4748The operator runs the skill against a kubeconfig pointing at one cluster at a49time. Network access to the target cluster is assumed (direct or via50VPN/bastion). The cluster survey itself makes no internet calls; the one51sanctioned outbound path is **version grounding** — when internet + `gh` are52available the verdict's specific version numbers MUST be confirmed against real53releases (House Rule #8 · `references/version-verification.md`).5455First **identify the change set** — what's being upgraded and from what to56what. Five shapes the skill answers:5758- **anchor bump** — `k8s <current> → <target>` (e.g. RKE2 1.32 → 1.34)59- **single leaf** — `<component> <current> → <target>` (e.g. Cilium 1.18 → 1.19)60- **combined** — multiple bumps in one upgrade window61 (e.g. `k8s 1.32 → 1.34 + Argo CD 3.0 → 3.2`)62- **drift review** — no specific target; report what's stale / EOL'd / unpatched63- **feasibility** — find the highest tolerable bump on one axis given the64 others are pinned (e.g. "highest Argo CD that supports our k8s 1.32")6566Then run the survey and verdict per `references/cluster-survey.md` (Phases 1–5:67cluster identity → component detection → deprecated-API liability via the68apiserver metric + pluto → cross-reference against `references/components.md`69and `references/compat/<comp>.md` → assemble the verdict per § Verdict format,70ordering the action plan by the compat files' upgrade-ordering rules).7172For a *drift review* (no target), the survey still runs; the verdict reports73against the current k8s minor only, flagging components whose installed version74is approaching or past upstream EOL.7576## Verdict format7778The header carries the **change set** (see § Survey workflow) — anchor bump,79single leaf, combined, drift review, or feasibility. The per-row reason at the80end of each `✓ ready` / `⚠ needs bump` line is composed from the compat data81and is change-set-specific (`supports k8s 1.32..1.34` for an anchor bump,82`compat with target Cilium 1.19` for a leaf bump, `current version EOL'd832025-10-07` for drift, etc.).8485```86<cluster name or kubeconfig context> — <change set>8788✓ ready89 - <component> <version> <change-set-specific reason>9091⚠ needs bump92 - <component> <version> → ≥ <target> <reason — what blocks the change set>93 source: references/compat/<comp>.md § <version>94 # <target> is the furthest-coverage version (House Rule #9) — covers this hop95 # AND the operator's next known hop, not the bare immediate-hop minimum.96 # A row that satisfies the current target but sits at its own support ceiling97 # belongs HERE (with the forward-covering target named), not under ✓ ready.9899⚠ ordering100 - <component A> must reach <version> BEFORE <component B> reaches <version>101 reason: <one-liner>102 source: references/compat/<a>.md § <version>103104✗ blockers105 - <deprecated API>: still served (<N requests/day>) — source: <namespace/workload>106 - <component> <version>: <reason — current-state issue or change-set blocker>107 source: references/compat/<comp>.md § <version>108109✗ out of registry scope110 - <component> <version>: below registry's min_tracked_version (<floor>);111 verdict abstained. Bump to a tracked version, or add an override in112 references/components.md.113114action plan115 1. <ordered step>116 2. <ordered step>117 ...118```119120`✓ ready` rows are noise after the first survey — collapse them by default in121follow-up surveys unless the operator asks for the full list. `⚠` and `✗` rows122always show.123124**Verdict vs report.** The verdict above is the technical core, suitable for125in-conversation use and runbook PRs. When the operator asks for a *pre-upgrade126report* (for JIRA, change management, audit, mgmt review), wrap the verdict in127the layout from `references/report-format.md` — same content, recognizable128section skeleton across runs so prior reports compare cleanly.129130## House rules131132These are non-negotiable; encode them into every verdict.1331341. **Community editions only.** Any Prime / EE / paid-tier feature, version, or135 support window is out of scope. Ignore SUSE Prime backports. Ignore GitLab136 EE-only features (the operator runs the EE binary as CE; treat as CE).1372. **Axis discipline.** A component's `axis_type` is `multi` only when the138 operator picks two or more dimensions independently. Container runtime,139 driver version, GPU architecture — all derived from other choices and140 therefore NOT axes. RKE2 → containerd is fixed; don't treat it as a variable.1413. **Min-tracked-version is overridable per component.** Default floor is142 "current + prior 2 minors" (~18 months). Operator overrides set per-component143 `min_tracked_version:` in `references/components.md`; `skill-improver144 freshen` respects overrides and trims unset rows.1454. **Apiserver metric is the truth source for deprecated APIs.** It reports146 what the cluster has actually served. Pluto's bundled rule set goes stale;147 use it for manifest-side static scans, never as primary. Kubent is dead148 (rulesets stop at k8s 1.32); do not use.1495. **Harvester ordering**: any survey involving Harvester + RKE2 must check the150 Harvester compat file for ordering rules before emitting an action151 plan. Some Harvester↔RKE2 combinations require Harvester to upgrade first;152 missing this turns the upgrade plan into a cluster-rebuild.1536. **Cite sources.** Every `⚠` and `✗` row carries a `source:` line pointing at154 the exact `references/compat/<comp>.md § <version>` block that155 produced the finding. No unsourced verdicts.1567. **Abstain when the registry is silent.** If the registry doesn't carry157 enough signal to verdict a row, abstain on that component and recommend158 running `skill-improver freshen <skill>` from an internet-accessible159 client.1608. **Never invent versions; ground or abstain.** k8s support *windows* are161 registry methodology (cite the compat file). Specific version *numbers* —162 latest patch, newest minor, "CVE fixed in vX.Y.Z", a recommended target patch163 — are volatile and the #1 fabrication risk (a past verdict cited an Argo CD164 `v3.2.10` that never existed; the 3.2 line ended at `v3.2.6`). State a165 specific release only if it is (a) cluster-reported, (b) grounded against a166 freshly fetched release listing, or (c) explicitly marked `UNVERIFIED`. When167 internet + `gh` are available, grounding is **mandatory** and uses the168 *anti-confirmation* method — enumerate the real tag list (naming no candidate)169 and derive the latest patch **per minor line**, and **never ask "does vX170 exist?"** (a named guess biases you toward confirming it). **`releases/latest`171 is recency, not rank** — it's the most-recently-published / maintainer-pinned172 release, NOT the highest version, so **never reject a higher enumerated minor173 because it exceeds `releases/latest`** (that misfire struck the real Harbor174 `2.15.x` while `releases/latest` was `2.14.4` — a back-ported patch to an old175 line outranks a newer minor by date). **Existence is not edition:**176 for a vendor with a community/Prime (or OSS/EE) split that ships both to one feed177 (Rancher), a *real, older* patch can be **Prime-only** and will rubber-stamp as178 community — `sort -V | tail -1` returns a Prime patch for any non-current minor.179 Apply the release-notes edition discriminator, don't trust version order. Full180 protocol + component→repo map + edition discrimination:181 `references/version-verification.md`.1829. **Target furthest coverage, not the immediate-hop minimum.** When a row needs183 a bump, recommend the *lowest version whose support window also covers every184 known or queued next hop* — never the bare minimum that only clears the current185 change set. If a newer minor already exists, is stable, and covers both the186 current target and the next planned minor, recommend **it** directly. A version187 that satisfies the current target but lands on its **own support ceiling** is a188 `⚠`, not a `✓` — say so and name the forward-covering target, because shipping189 it forces an avoidable second bump one hop later. Step minor-by-minor ONLY when190 (a) mandatory sequential stops exist (GitLab app stops, Rancher CAPI conversion)191 or (b) skipping stacks breaking changes too aggressively — and even then, name192 the **end-state** target version, not just the next step. Always ask "what is193 the operator's *next* hop after this one, and does my recommended version194 already cover it?" before emitting a `→ ≥ <target>`. *(Encoded after a real195 miss: a k8s 1.32 → 1.33 handoff recommended KEDA 2.18.3 — CVE-patched and196 1.33-valid but at the 2.18 ceiling, even though the handoff itself noted "1.34197 would need ≥ 2.19 later" — while KEDA 2.19.0 (k8s 1.32–1.34, same CVE fix)198 already existed and would have covered the very next 1.33 → 1.34 hop in one199 bump. The look-ahead was known and not acted on.)*200201## Truth-source-type — branch the lookup202203Each component in the registry carries a `truth_source_type` field that says204*where the compat truth lives*. The skill branches on it when reading205`references/compat/<comp>.md`:206207| Type | What the file contains |208|------|------------------------|209| `published_matrix` | Distilled rows extracted from the vendor's k8s support matrix, per-version. |210| `release_notes` | Sifted highlights from GitHub release notes — breaking, CRD, k8s floor, ordering. |211| `chart_metadata` | Helm `Chart.yaml`'s `kubeVersion:` constraint per chart-release tag, plus chart→app mapping. |212213The branching matters at maintenance time (freshen probes different sources)214and at use time (the verdict cites a different kind of evidence per row).215216## References217218- `references/components.md` — the 19-entry registry (table for single-axis, stanzas for multi-axis). Carries `axis_type`, `truth_source_type`, source URL, `min_tracked_version`. The lookup table the survey reads.219- `references/cluster-survey.md` — the canonical command set: kubectl/helm/pluto/apiserver-metric. Detection patterns for mapping running workloads onto registry entries.220- `references/tooling.md` — apiserver `apiserver_requested_deprecated_apis` metric (primary), pluto (static manifest scan), kubent dead.221- `references/compat/README.md` — file-format spec for per-component compat files.222- `references/compat/<comp>.md` — one per component. The load-bearing per-version compatibility signal. Air-gap-complete.223- `references/version-verification.md` — anti-fabrication protocol (House Rule #8): how to ground every cited version against real releases via `gh` (the anti-confirmation method + component→repo map). Read whenever the workstation is online.224- `references/sources.md` — URL index with `Last verified:` timestamps. Maintained by `skill-improver freshen`; read at use time only to surface staleness in the verdict if a row is past 90 days.225- `references/report-format.md` — pre-upgrade report layout: fixed section skeleton (header table, exec summary, survey, verdict, diff vs prior, action plan, methodology) with dynamic content. Used when the operator asks for a *report* rather than a verdict.