- Pluto is an open-source CLI from FairwindsOps that scans YAML manifests, Helm charts, and live Helm releases for deprecated or removed Kubernetes apiVersions — so your next minor upgrade doesn't turn into an outage.
TL;DR
Pluto is a tiny Go CLI from FairwindsOps that answers one question every SRE dreads before a Kubernetes upgrade: "where are my deprecated apiVersions hiding?" It scans three surfaces in one binary — static manifests in git, un-deployed Helm charts, and live Helm releases running in a cluster — and returns non-zero when it finds DEPRECATED or REMOVED GVKs. Apache-2.0, ~2.5k stars, and the canonical answer on learnk8s's upgrade checklist.

The problem Pluto solves
Kubernetes deprecates apiVersions on a rolling schedule. 1.16 killed a swathe of extensions/v1beta1 resources, 1.22 removed the old Ingress, 1.25 retired PodSecurityPolicy and policy/v1beta1 PodDisruptionBudget, and the cycle keeps going. The obvious move — ask the API server which versions your workloads use — is a trap. If you deployed a deployments.v1beta1.extensions, the server silently converts it and hands you back apps/v1. You'll never see the deprecated version until the upgrade strips it out and your rollout stalls.
The definitive record lives in Helm release objects, which store the exact apiVersion at deploy time. That's the insight Pluto is built around.
What Pluto scans
- Static manifests — flat YAML in IaC repos.
- Un-deployed Helm charts — piped through
helm template. - Live Helm 2 / Helm 3 releases — reads the release objects directly from the cluster.
- Live API resources — for GVKs you pushed with raw
kubectl apply.
It also ships coverage for non-Kubernetes GVKs — Istio, Cert Manager, and friends — via a bundled versions.yaml you can extend with your own entries (OpenShift DeploymentConfig, for example).
Commands cheatsheet
| Command | What it does |
|---|---|
pluto detect-files -d ./k8s | Scan a directory of static YAML. |
helm template ./chart | pluto detect - | Scan a rendered Helm chart from stdin. |
pluto detect-helm -owide | Scan live Helm releases in the current cluster. |
pluto detect-api-resources | Scan live API resources (for kubectl apply drift). |
pluto detect-all-in-cluster | Combine Helm + API resources in one pass. |
The -owide flag is the one worth memorising — it adds namespace, replacement, deprecated-in, and removed-in columns so you know exactly which k8s version will break you.
When teams actually reach for Pluto
- Pre-upgrade gate. Before jumping a minor (1.16, 1.22, 1.25, 1.29+ were all notorious for bulk removals), run
pluto detect-all-in-cluster -owideagainst staging and prod — you get a sorted punch list of objects to patch. - PR policy. Wire
detect-filesinto CI so any new manifest introducing a deprecated GVK fails the check before merge. Cheap drift prevention. - Third-party chart audits. Platform teams promoting vendor Helm charts across environments can scan them once, centrally, instead of hoping the maintainer kept up.
- Cluster drift reports. Schedule a weekly scan; track remediation progress by namespace. Works especially well for orgs migrating off managed k8s versions on a ticking deadline.
How it compares to the alternatives
The closest open-source sibling is kubent (kube-no-trouble), which also reads Helm releases and live API resources. Where Pluto pulls ahead: it scans un-deployed charts and raw manifests in the same binary, and ships coverage for non-k8s GVKs (Istio, Cert Manager) via an extensible versions.yaml. In practice most teams end up running both — kubent for the live cluster, Pluto for the git repo and CI gates.
What the output looks like
Point Pluto at a chart still using policy/v1beta1 for a PodDisruptionBudget:
NAME KIND VERSION REPLACEMENT DEPRECATED IN REMOVED IN
api-pdb PodDisruptionBudget policy/v1beta1 policy/v1 v1.21.0 v1.25.0Exit code is non-zero, which is the whole point: you can wire that into any CI gate.
CI/CD integration
Pluto is a single static binary, so plugging it in is usually a one-line step:
- GitHub Actions — official
fairwindsops/plutoaction downloads the binary; you runpluto detect-filesdirectly in the workflow. - Jenkins — add a stage that curls the release tarball and runs
pluto detect-files -d .. - CircleCI — a first-party orb is published.
- Azure DevOps — no native extension, but a ~30-line bash script (download + iterate repos + call
detect-files/detect) is all you need.
Flags like --ignore-deprecations and --ignore-removals let you ratchet enforcement — warn now, fail later.
Limitations & pricing
Free, Apache-2.0, no paid tier on the CLI. FairwindsOps sells a SaaS (Insights) that wraps Pluto with a dashboard, but you never need it to run Pluto itself.
Things to know before you drop it in:
- In-cluster historical detection is Helm-only. Raw
kubectl applydeployments leave no definitive record — you'll needdetect-api-resourcesor source-of-truth scans in git. - Detection is GVK-based, so Pluto can't catch field-level deprecations (a valid apiVersion with a removed spec field still passes).
- Coverage for bleeding-edge k8s releases lags until
versions.yamlis updated — the latest entries cover k8s 1.33 / 1.34 / 1.35.
What's next
Recent commits bumped Pluto to Go 1.26, exported versions.yaml to library consumers, and extended coverage across the 1.33–1.35 release band. Community PRs keep widening non-k8s GVK coverage (Istio, Cert Manager, Linkerd, Prometheus Operator). If your cluster upgrade checklist still lives in a Notion page full of grep incantations, a 30-second pluto detect-helm -owide is the cheapest upgrade you'll ship this quarter.
Nguồn: FairwindsOps/pluto, Pluto docs, Red Hat blog, Kris the Coding Unicorn.



