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.

Pluto by Fairwinds — Kubernetes deprecated API scanner

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

CommandWhat it does
pluto detect-files -d ./k8sScan a directory of static YAML.
helm template ./chart | pluto detect -Scan a rendered Helm chart from stdin.
pluto detect-helm -owideScan live Helm releases in the current cluster.
pluto detect-api-resourcesScan live API resources (for kubectl apply drift).
pluto detect-all-in-clusterCombine 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 -owide against staging and prod — you get a sorted punch list of objects to patch.
  • PR policy. Wire detect-files into 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.0

Exit 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/pluto action downloads the binary; you run pluto detect-files directly 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 apply deployments leave no definitive record — you'll need detect-api-resources or 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.yaml is 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.