Utility to detect stale resources in Kubernetes clusters based on local manifests
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
renovate[bot] 4e4b2aa78b module: update rope to ~1.5 4 days ago
.github ci: update Python, Ubuntu, K8s and kind versions 3 weeks ago
e2e ci: ignore kube-dns events in default namespace 1 year ago
.editorconfig module: add editorconfig 2 years ago
.gitignore module: adopt Poetry dependency manager 2 years ago
.pylintrc module: add formatting and linting configuration 3 years ago
LICENSE Fiat lux 3 years ago
Makefile ci: add e2e tests using kind + k8s 2 years ago
README.md ci: use github actions for simply CI 3 years ago
kube-stale-resources.py module: add request timeouts to fix lint warning 3 months ago
mypy.ini module: use type hints and validate with mypy 3 years ago
pyproject.toml module: update rope to ~1.5 4 days ago



Build Status

This is a utility to detect stale resources in Kubernetes clusters between resources from YAML manifests supplied via local file or stdin (target state) and a Kubernetes cluster (live state). All resources that exist in the live state but not in the target state are considered stale as they deviate from the intended state of the Kubernetes cluster (closed world assumption). It is intended as a complement to kubectl diff.

Using a blacklist you can ignore resources from the live state from the comparison so they are not considered stale even though they do not exist in the given target state. This is useful when those resources are created by Kubernetes itself (e.g. the kubernetes service in the default namespace), managed by the Kubernetes cluster provider or another tool outside the scope.

A use case for kube-stale-resources is using it alongside kubectl diff on locally present YAML manifests so kubectl diff can detect newly created Kubernetes resources and changes to those resources and kube-stale-resources can alert the user on stale resources that should be deleted from the cluster.


  • currently only works on namespaced resources
  • currently requires explicit metadata.namespace field even for resources in default namespace
  • requires unauthenticated HTTP(S) access to Kubernetes apiserver, e.g. via kubectl proxy
  • only accounts for apiVersion deprecations up until Kubernetes 1.16


You need Python 3.8 or higher.

Assuming you have a properly setup .kube/config (e.g. using minikube after a successful minikube start) running:

kubectl proxy &

# ignore minikube resources
cat <<EOF > blacklist.txt

# orderly created resource using YAML manifest in e.g. git
cat <<EOF > version-controlled-resources.yml
apiVersion: v1
kind: Service
  name: foo
  namespace: default
  type: ClusterIP
    - port: 80
      name: http
      targetPort: 80
    app: foo
kubectl apply -f version-controlled-resources.yml

# on-the-fly created resource using imperative command
kubectl create service clusterip bar --tcp='8080:8080'

cat version-controlled-resources.yml | python kube-stale-resources.py -f - --blacklist blacklist.txt

This should yield a similar output to as we ignored what minikube sets up by default (e.g. the whole kubernetes-dashboard namespace):

Reading blacklist file blacklist.txt...
Retrieving target state...
Retrieving live state from http://localhost:8001...
Live dynamic configmaps that are not in target (stale):
.. 0 entries

Live resources w/o dynamic configmaps that are not in target (stale):
.. 1 entries

Run python kube-stale-resources.py -h for full list of options.


Example blacklist file for a cluster on GKE that also uses cert-manager:



In general a blacklist file contains one regular expression per line that are matched against a string of format <namespace-name>:<apiVersion>:<kind>:<resource-name> for each resource.


kube-stale-resources is licensed under the Apache License, Version 2.0. See LICENSE for more information