The missing pre-flight + watch + verify layer that wraps any Kubernetes upgrade.
kubectl-upgrade tells you what will break before you start, generates provider-specific upgrade commands for you to review and run, watches the upgrade in progress for known stuck states, tells you how to unstick common failures, and verifies success after.
It does not run cloud CLIs itself; it emits the provider command or runbook step for an operator to review and execute.
$ kubectl upgrade preflight --target v1.34
$ kubectl upgrade run plan --target v1.34 # emits the eksctl/gcloud/az command for YOU to run
$ kubectl upgrade run watch --target v1.34 # monitors the in-flight upgrade
$ kubectl upgrade run verify --target v1.34 # post-upgrade smoke
$ kubectl upgrade fleet --host-target v1.34 --plan # vCluster Tenant Cluster wave
Most Kubernetes upgrade prechecks focus on API removals found in live cluster state, provider telemetry, or audit-log windows. That is necessary, but it misses important evidence that lives in Helm release history, local manifest files, CRDs, PDBs, PVCs, addon versions, and in-flight upgrade state.
kubectl-upgrade currently scans four workload source families:
- live cluster objects from the Kubernetes API
- Helm v3 release secrets stored in the cluster
- local YAML/JSON manifest files or directories passed with
scan --source manifests --path ... - local Git/GitOps desired-state inputs passed with
scan --source git|argocd|flux
GitOps discovery is local and read-only today: it scans local Git paths, ArgoCD Application/ApplicationSet manifests, and Flux Kustomization/HelmRelease manifests that reference local paths. It does not yet clone remote repositories or call live ArgoCD/Flux APIs.
kubectl-upgrade is an evidence collector and finding normalizer. Each command reads one or more
sources, turns matching risks into findings, and keeps those findings tied to the source an
operator can change.
Evidence sources include:
- Kubernetes API reads for live objects, server-discovered resources, CRDs, webhooks, storage, pods, PDBs, owners, and server version
- Helm v3 release secrets, including older release manifests that may still contain removed APIs
- local YAML/JSON manifests and local Git/GitOps paths for Git, Argo CD, and Flux workflows
- operator-supplied EKS, GKE, and AKS JSON exports
- operator-supplied Prometheus API server metrics and Kubernetes audit logs
- addon controller Deployments and image tags compared with the embedded addon compatibility matrix
- vCluster Helm release secrets on the Control Plane Cluster, used to identify Tenant Clusters and evaluate vCluster product gates plus host Kubernetes compatibility
The default behavior is read-only. The tool reads the Kubernetes API and local files, imports
evidence you provide, and prints provider upgrade commands for human review. It does not run
aws, gcloud, az, drain nodes, evict pods, edit webhooks, upgrade addons, mutate vCluster
tenants, clone remote repositories, or call live Argo CD/Flux APIs during normal checks.
A finding is intended to move through a lifecycle: discover, triage, assign an owner, fix the source, then rerun the command to confirm the evidence changed. Reports preserve attribution where the detector has it: namespace/name for live objects, Helm release and revision for release history, local file paths for manifests and GitOps inputs, controller Deployment/image for addons, provider export or runtime evidence source for imports, and tenant release/namespace for vCluster.
Validation follows the same model. Use the demo lab, smoke commands, JSON/Markdown/SARIF output,
relationship graph output, and --fail-on gates to make checks repeatable in CI and release
reviews. Passing output means the current evidence did not trigger configured blockers; it does not
replace provider prechecks, addon-specific upgrade guides, vCluster snapshot/backup discipline, or
upstream release-note review for the exact versions you run.
kubectl-upgrade covers the whole flow:
| Stage | What it does | Other tools |
|---|---|---|
| Source scan | Deprecated API scan for live objects, Helm release secrets, local manifest files/directories, and local GitOps source trees | API-only tools usually stop at live or audit-observed objects |
| Pre-flight | Live+Helm scan plus CRDs, conversion webhooks, PV/PVCs, addons, PDBs, drain simulation, and vCluster gates | provider checks vary by platform |
| Evidence imports | Offline EKS/GKE/AKS insight JSON plus Prometheus metrics and audit-log evidence | usually split across provider portals and observability systems |
| Plan | Detect provider, emit provider command/runbook step | none |
| Watch | Monitor in-flight upgrade for stuck patterns | none |
| Unstick | Detect common stuck states such as PDB-blocked evictions, NotReady nodes, pending Helm releases, webhook failure policies, and namespace finalizers | none |
| Verify | Post-upgrade rescan, server version check, smoke | none |
| Fleet | vCluster Tenant Cluster wave orchestration | none |
Downloads the latest release archive and drops kubectl-upgrade on your $PATH. Once it's there, kubectl upgrade works automatically — kubectl auto-discovers kubectl-* binaries; no krew required.
curl -sSL https://raw.githubusercontent.com/saiyam1814/upgrade/main/install.sh | sh
kubectl upgrade --helpgo install github.com/saiyam1814/upgrade@latest
mv $(go env GOBIN)/upgrade $(go env GOBIN)/kubectl-upgradeGrab a tarball/zip from Releases and place kubectl-upgrade on $PATH.
- krew — manifest at
.krew/upgrade.yamlis ready; PR tokubernetes-sigs/krew-indexnot yet submitted. - Homebrew — formula scaffolded; needs the tap repo + token before re-enabling in GoReleaser.
# 1. Find every workload-side time bomb
kubectl upgrade preflight --target v1.34
# 2. Get the provider command/runbook step for review
kubectl upgrade run plan --target v1.34
# 3. (You manually run the emitted commands.)
# In a separate terminal, watch for stuck states:
kubectl upgrade run watch --target v1.34
# 4. After the upgrade finishes, verify
kubectl upgrade run verify --target v1.34
# Got stuck? This is the recovery toolkit:
kubectl upgrade unstick
# Have vClusters? Check which tenants are compatible with the
# upcoming host K8s bump BEFORE you bump the host:
kubectl upgrade fleet --host-target v1.34 --planWhen you bump a Control Plane Cluster's K8s minor (e.g. EKS 1.32→1.34),
not every vCluster version on it will tolerate the new host. fleet
runs a per-tenant check and tells you which tenants need to be bumped
before the host upgrade and which are safe.
kubectl upgrade fleet --host-target v1.34 --planOutput for each tenant — three states:
- ✓ INFO — current vCluster supports the new host K8s. Safe.
- ⚠ MEDIUM — at the upper edge of the support window. Plan a tenant bump after the host.
- ✗ BLOCKER — tenant's vCluster version does NOT support the new host. Bump the tenant first; the runbook tells you the minimum vCluster version to bump to.
The compat table is hand-curated from upstream vCluster release notes; PRs welcome to extend it as new releases land.
kubectl upgrade tui --target v1.34A bubbletea dashboard with steps on the left and findings/commands on the right. Like k9s for upgrades.
| Command | Purpose |
|---|---|
preflight |
Aggregate live pre-flight: scan (live + Helm) + simulate + addons + pdb + drain + volumes + crds + vcluster |
run plan |
Emit cloud-CLI commands for control plane + nodes |
run watch |
Monitor in-flight upgrade for stuck states |
run verify |
Post-upgrade verification |
fleet |
vCluster Tenant Cluster wave plus fleet drift/risk scoring |
scan |
Deprecated APIs in live cluster / Helm releases / local manifest files / local GitOps sources |
simulate |
Forward sim: feature gates, default flips, kubelet, kernel |
pdb |
Drain-deadlock detector |
drain |
Read-only node drain simulator |
addons |
Controller compatibility matrix for cert-manager, Istio, Karpenter, ArgoCD, Cilium, Calico, CoreDNS, and more |
volumes |
PV / PVC / CSI / StorageClass safety |
crds |
CRD versions / webhook certs / storedVersions / orphan CRDs |
provider-insights |
Import EKS / GKE / AKS upgrade insight JSON |
runtime-evidence |
Import deprecated API metrics / audit-log evidence |
vcluster |
Per-Tenant-Cluster decision tree |
unstick |
Stuck-state recovery toolkit |
plan |
Chained one-minor-at-a-time path |
report |
Combined report (Markdown / JSON / SARIF / graph JSON) |
tui |
Interactive visual upgrade dashboard |
Run kubectl upgrade <cmd> --help for examples and full options.
kubectl-upgrade is designed for production prechecks with read-only behavior by default. Mutating actions (currently only unstick --auto-fix) require both --execute AND a per-action [y/N] confirmation.
We never:
- Run cloud CLIs (
aws,gcloud,az) for you. We emit the command; you run it. - Force-delete stuck Pods, modify webhook
failurePolicy, or remove namespace finalizers. - Take backups, drain nodes, or pause GitOps reconciliation.
- Phone home. The binary makes no network calls beyond the Kubernetes API server you point it at.
See SAFETY.md for the full safety contract.
run plan knows how to talk about (no execution, just emits commands):
| Provider | Control plane | Node pools |
|---|---|---|
| AWS EKS / EKS Auto | aws eks update-cluster-version |
aws eks update-nodegroup-version |
| GKE / GKE Autopilot | gcloud container clusters upgrade |
gcloud container clusters upgrade --node-pool |
| AKS | az aks upgrade |
az aks nodepool upgrade |
| OpenShift / ROSA | oc adm upgrade |
(auto via Machine Config Operator) |
| RKE2 / k3s | system-upgrade-controller Plan | system-upgrade-controller Plan |
| Talos | talosctl upgrade-k8s |
(separate talosctl upgrade) |
| kubeadm | kubeadm upgrade plan + apply |
kubectl drain + apt + restart kubelet |
| Cluster API | (provider-specific) | (provider-specific) |
| vCluster | kubectl upgrade vcluster (per-tenant) |
(n/a) |
| Rule type | Source | Coverage |
|---|---|---|
| Deprecated APIs | Vendored snapshot of FairwindsOps/pluto versions.yaml (Apache 2.0) |
k8s, cert-manager, istio, prom-operator, several others |
| Feature gates / defaults / kubelet / kernel | Hand-curated from upstream Kubernetes release notes | 1.25 → 1.36 |
| Addon ↔ K8s compat | internal/addons/addons.yaml, hand-curated from upstream docs with confidence and review-date metadata |
cert-manager, Karpenter, Istio, ArgoCD, Flux, prom-operator, Kyverno, ingress-nginx, Cilium, Calico, CoreDNS, external-secrets, Crossplane, Gatekeeper, KEDA, Linkerd, Velero, AWS EBS CSI, AWS Load Balancer Controller, Envoy Gateway |
| vCluster decision tree | upstream vCluster docs + release notes | v0.20 → v0.34 |
PRs to extend coverage are welcome.
Detailed addon docs: https://saiyam1814.github.io/upgrade/addons.html
Full project guide: https://saiyam1814.github.io/upgrade/guide.html
vCluster guide: https://saiyam1814.github.io/upgrade/vcluster.html
kubectl upgrade preflight --target v1.34 --format human # default, colorized
kubectl upgrade preflight --target v1.34 --format md # Markdown for PRs
kubectl upgrade preflight --target v1.34 --format json # CI / scripts
kubectl upgrade preflight --target v1.34 --format sarif # GitHub code scanning
kubectl upgrade preflight --target v1.34 --format graph # source/object/owner relationship graph JSONThe docs site includes a browser-based 3D viewer for graph output: https://saiyam1814.github.io/upgrade/graph.html
CI gate:
kubectl upgrade preflight --target v1.34 --fail-on blocker # exit 2 on any BLOCKERmake build # ./bin/kubectl-upgrade
make test
make smoke # all the headless-safe commands
make kind-validate DELETE_CLUSTER=1 # disposable kind demo-lab validation
make addon-docs # regenerate docs/addons.html coverage table
make refresh-rules # bump pluto's versions.yamlApache 2.0. The bundled versions.yaml snapshot from FairwindsOps/pluto is also Apache 2.0.
