Kubernetes kubectl plugin for cluster health: find unhealthy pods, container issues, nodes, namespaces, storage, batch workloads, Services with no backing Pods, Deployments scaled to zero or under desired ready replicas, and Warning events.
kubectl-audit is a kubectl plugin (Krew) that surfaces resources failing common checks—pods that are not fully healthy (including high restart counts and bad phases such as CrashLoopBackOff or ImagePullBackOff), containers as individual rows (init and app, derived from pods), nodes that are NotReady or cordoned (SchedulingDisabled), namespaces that are Terminating or contain no workloads (Pods, Deployments, StatefulSets, DaemonSets, ReplicaSets, Jobs, or CronJobs), PersistentVolumes (PV) and PersistentVolumeClaims (PVC) not Bound, failed Jobs, suspended CronJobs, Services whose pod selector matches no Pods in the same namespace (skipping ExternalName and empty selectors), and Deployments with spec.replicas set to 0 or status.readyReplicas below desired (desired is spec.replicas, or 1 when replicas is unset, matching the API default), and Warning events (type=Warning; Normal events are treated as benign). For most kinds, output matches kubectl get printers (default table, -o wide, JSON, YAML, custom columns, Go templates). The containers subcommand uses a dedicated table and supports -o json, -o yaml, -o name, default table, and -o wide (see Output formats).
Use it for Kubernetes troubleshooting, SRE / platform triage, and pre-deploy smoke checks without leaving the CLI.
- What it checks
- Install
- Usage
- Resources and filters
- Output formats
- Examples
- Development
- Contributing
- Acknowledgments
| Area | Plain-language intent |
|---|---|
| Pods | Pods that are not in a good steady state or have risky restart behavior (see Resources and filters). |
| Containers | Per-container problems (waits, pull errors, readiness, high restarts) with optional filter by pod name. |
| Nodes | Nodes you cannot schedule to or that are not ready. |
| Namespaces | Namespaces stuck in Terminating, or with no workloads (no Pods, Deployments, StatefulSets, DaemonSets, ReplicaSets, Jobs, or CronJobs). |
| Storage (PV / PVC) | Volumes and claims stuck outside Bound. |
| Jobs / CronJobs | Failed jobs and cron jobs that are suspended. |
| Services | Services with a non-empty pod selector and no matching Pods in that namespace (ExternalName and empty selectors are skipped). |
| Deployments | spec.replicas explicitly 0 (scaled to zero), or desired > 0 with status.readyReplicas < desired (desired 1 when spec.replicas is nil). |
| Events | Warning events (type=Warning); Normal events are benign. |
Published through codenio-krew-index:
kubectl krew index add codenio https://github.com/codenio/codenio-krew-index.git
kubectl krew install codenio/auditUpgrade when the index is updated (Krew accepts only the short plugin name here — not codenio/audit):
kubectl krew upgrade auditIf the local index name codenio is already taken, pick another name for kubectl krew index add and use it in install only (for example kubectl krew install codenio-krew/audit). Upgrade stays kubectl krew upgrade audit regardless of which index you installed from. Maintainer notes for bumping versions live in the index repository.
If the plugin is listed in Krew’s default index:
kubectl krew install auditRequires Go 1.21+ and make:
git clone https://github.com/codenio/kubectl-audit.git
cd kubectl-audit
make installThis builds bin/audit and copies it to ~/.krew/bin/kubectl-audit. Put ~/.krew/bin on your PATH (or adjust the install path) so kubectl audit resolves.
The plugin is a single binary with subcommands per audit target (see Resources and filters):
kubectl audit --help
kubectl audit --version
kubectl audit pods
kubectl audit containersStandard kubectl config applies: current context, KUBECONFIG, -n / --namespace, --context, and so on.
| Subcommand | Aliases | What is listed |
|---|---|---|
containers |
container |
Init and app container rows that need attention (image pull / crash-style waiting reasons, high restarts, not ready when the pod is not in a terminal phase, failed init, etc.). Rows include POD (pod name) and NAME (container name). Use -p / --pod with an exact pod metadata.name to scope to one pod (see kubectl audit containers --help Usage line). |
pods |
pod, po |
Pods that need attention: phase is not Running, any regular container is not Ready, or any regular or init container has RestartCount ≥ 5 (threshold is fixed in code). Succeeded / Completed job pods are included because they are not in a running steady state. |
nodes |
node, no |
Nodes that are NotReady or have SchedulingDisabled. |
namespace |
namespaces, ns |
Namespaces in Terminating phase, or with no workloads (Pods, Deployments, StatefulSets, DaemonSets, ReplicaSets, Jobs, or CronJobs). ConfigMaps, Secrets, and Services alone do not count. |
pvc |
pvcs, persistentvolumeclaim, persistentvolumeclaims |
PVCs not in Bound phase. |
pv |
pvs, persistentvolume, persistentvolumes |
PVs not in Bound phase. |
jobs |
job |
Failed jobs (including backoff / deadline failures). |
cronjobs |
cronjob, cj |
Suspended cron jobs. |
service |
services, svc |
Services whose selector matches no Pods in the namespace (ExternalName and empty selector are out of scope for this check). The audit -l / --selector filters Services only; Pod matching uses all Pods in each namespace. |
deploy |
deployment, deployments |
Deployments with spec.replicas: 0 (scaled to zero), or status.readyReplicas < desired when desired > 0 (desired from spec.replicas, default 1 if unset). |
events |
event, ev |
Events with type=Warning (for example image pull failures, backoff limits). Normal events are out of scope. |
Common flags
- All namespaces:
-Aor--all-namespacesfor namespaced targets (containers,pods,pvc,jobs,cronjobs,service,deploy,events). - Labels:
-l/--selector(same semantics askubectl get; applies to the underlying pod list forcontainers, to the Service list forkubectl audit service, and to the Deployment list forkubectl audit deploy).
There are no --pending / --failed style switches: one kubectl audit pods run applies all pod rules above; kubectl audit containers applies per-container rules.
Further notes live in the full documentation.
For pods, nodes, namespace, pv, pvc, jobs, cronjobs, service, deploy, and events, kubectl get-style -o flags work as usual, for example:
kubectl audit pods -o wide
kubectl audit nodes -o json
kubectl audit ns -o json
kubectl audit pvc -o yaml
kubectl audit jobs -o custom-columns=NAME:.metadata.name
kubectl audit service -o json
kubectl audit events -o wideFor containers, printing is custom: default and -o wide use a fixed column layout. Default columns are NAMESPACE (with -A), POD, NAME, READY, STATUS, RESTARTS, AGE, TYPE (container vs init-container). -o wide adds PORTS, IMAGE, and PULLPOLICY. Machine output: -o json, -o yaml, -o name only (other -o values are rejected with a clear error).
# Containers: per-container rows (pod name first column; use -o wide for image, ports, pull policy)
kubectl audit containers
kubectl audit containers -A
kubectl audit containers -o wide
kubectl audit containers -p my-pod-0
kubectl audit containers --pod my-pod-0 -n my-namespace
# Pods: current context default namespace
kubectl audit pods
# Pods: single explicit namespace (no NAMESPACE column in the default table, same as kubectl get pods)
kubectl audit pods -n ns-prod
# Pods: all namespaces (adds a NAMESPACE column; same idea as kubectl get pods -A)
kubectl audit pods -A
kubectl audit po --all-namespaces
# Pods: label filter with all namespaces
kubectl audit pods -A -l app=web
# Nodes and namespaces (cluster-scoped; -n / -A do not apply)
kubectl audit nodes
kubectl audit ns
kubectl audit namespace -l team=platform
# PVC / PV
kubectl audit pvc -A
kubectl audit pv
# Jobs and CronJobs
kubectl audit job -A
kubectl audit cj -A
# Services: selectors with no matching Pods (see also Service audit demo below)
kubectl audit service
kubectl audit svc -A
kubectl audit service -n my-namespace -l app=myapp
# Deployments: scaled to zero or ready count below desired
kubectl audit deploy
kubectl audit deploy -A
# Events: Warning type only
kubectl audit events
kubectl audit events -A
# Portable demo YAML per audit: see examples/README.md and examples/audit-*/
Each subfolder under examples/ has a demo.yaml plus a README with apply / audit / delete steps.
| Folder | kubectl audit target |
|---|---|
examples/audit-pods/ |
pods (healthy, bad image, crash loop, completed Job) |
examples/audit-containers/ |
containers (init failure, bad sidecar, crash loop) |
examples/audit-job/ |
jobs |
examples/audit-cronjob/ |
cronjobs |
examples/audit-svc/ |
service |
examples/audit-deploy/ |
deploy |
examples/audit-events/ |
events (image pull, BackOff, init failure warnings) |
examples/audit-pvc/ |
pvc |
examples/audit-pv/ |
pv |
examples/audit-namespace/ |
namespace (empty Active namespace, stuck Terminating) |
Nodes are not included in demo folders (cluster-specific). There is no audit-nodes example folder.
Pods — single namespace
$ kubectl audit pods # kubectl audit pods -n ns-prod
-------------------------------------------------------
Pod Audit summary: total = 9 benign = 3 attention = 6
-------------------------------------------------------
Pod that requires attention
NAME READY STATUS RESTARTS AGE
workload-a-dep-54b6948c9c-pqx12 0/1 ImagePullBackOff 0 8h
workload-a-dep-785b496f5d-rst34 0/1 ContainerCreating 0 11h
svc-b-dep-6c87c74674-uvw56 2/3 ErrImagePull 0 3h5m
svc-b-dep-9f6d7b5cc-xyz99 0/3 ContainerStatusUnknown 0 12h
sidecar-c-dep-9c5c948dd-abccd 0/1 CrashLoopBackOff 0 18h
sidecar-c-dep-c45d7c6c5-efghi 0/1 InvalidImageName 0 8hPods — all namespaces
$ kubectl audit pods -A
-------------------------------------------------------
Pod Audit summary: total = 120 benign = 114 attention = 6
-------------------------------------------------------
Pod that requires attention
NAMESPACE NAME READY STATUS RESTARTS AGE
ns-team-a workload-dep-5f7677d8c-pqx12 0/1 ImagePullBackOff 0 8h
ns-team-a workload-dep-6a8b9c0d-rst34 0/1 ImagePullBackOff 0 11h
ns-team-b indexer-dep-7c8d9e0f-uvw56 0/1 ImagePullBackOff 0 3h55m
ns-shared sidecar-dep-8b9c0d1e-xyz78 0/1 ErrImagePull 0 45m
ns-shared batch-harness-dep-9c0d1e2f-ab901 1/1 Running 6 4h
ns-monitoring obs-collector-dep-0d1e2f3g-cd234 1/1 Running 18 2d(The Running rows are listed when RestartCount reaches the attention threshold; other rows are not in a healthy steady state.)
Containers (illustrative columns; default omits image / ports / pull policy unless -o wide)
$ kubectl audit containers -n demo
-------------------------------------------------------
Container Audit summary: total = 12 benign = 9 attention = 3
-------------------------------------------------------
Container that requires attention
POD NAME READY STATUS RESTARTS AGE TYPE
workload-dep-abc-xyz sidecar 0 ImagePullBackOff 0 - containerNodes
$ kubectl audit nodes
-------------------------------------------------------
Node Audit summary: total = 66 benign = 46 attention = 20
-------------------------------------------------------
Node that requires attention
NAME STATUS ROLES AGE VERSION
default-0 Ready,SchedulingDisabled <none> 459d v1.30.3
default-1 Ready,SchedulingDisabled <none> 35d v1.30.3
default-2 Ready,SchedulingDisabled <none> 35d v1.30.3
worker-0 NotReady,SchedulingDisabled <none> 2d21h v1.33.3
worker-1 NotReady,SchedulingDisabled <none> 23h v1.33.3
worker-2 NotReady,SchedulingDisabled <none> 2d19h v1.33.3
worker-3 NotReady <none> 24h v1.33.3
worker-4 NotReady,SchedulingDisabled <none> 45h v1.33.3
...
...Namespaces
$ kubectl audit ns
-------------------------------------------------------
Namespace Audit summary: total = 42 benign = 38 attention = 4
-------------------------------------------------------
Namespace that requires attention
NAME STATUS AGE
kube-public Active 400d
old-team-a Active 90d
stuck-delete Terminating 2d
unused-staging Active 14d( Terminating — deletion is stuck. Active with no workloads — namespace has no Pods, Deployments, StatefulSets, DaemonSets, ReplicaSets, Jobs, or CronJobs; ConfigMaps and Services alone do not count.)
Persistent volumes
$ kubectl audit pv
-------------------------------------------------------
PersistentVolume Audit summary: total = 12 benign = 11 attention = 1
-------------------------------------------------------
PersistentVolume that requires attention
NAME CAPACITY ACCESS MODES STATUS CLAIM
pv-archive-001 500Gi RWO Released demo-ns/pvc-old-claimPersistent volume claims
$ kubectl audit pvc -A
-------------------------------------------------------
PersistentVolumeClaim Audit summary: total = 45 benign = 43 attention = 2
-------------------------------------------------------
PersistentVolumeClaim that requires attention
NAMESPACE NAME STATUS VOLUME
app-demo logs-claim-01 Pending
data-demo backup-claim-02 LostJobs
$ kubectl audit jobs -A
-------------------------------------------------------
Job Audit summary: total = 28 benign = 26 attention = 2
-------------------------------------------------------
Job that requires attention
NAMESPACE NAME COMPLETIONS DURATION AGE
batch-demo daily-import 0/1 5m 5m
batch-demo retry-migrate 0/1 1h 1hCronJobs
$ kubectl audit cronjobs -A
-------------------------------------------------------
CronJob Audit summary: total = 15 benign = 13 attention = 2
-------------------------------------------------------
CronJob that requires attention
NAMESPACE NAME SCHEDULE SUSPEND ACTIVE
ops-demo pause-backup 0 2 * * * True 0
ops-demo hold-reports 15 * * * * True 0For machine-oriented -o (including containers json / yaml / name and kubectl get–style output for the other subcommands), the audit summary line is written to stderr so you can pipe stdout to jq or other tools unchanged.
Prerequisites: Go 1.21+, make, and a working cluster context if you want to run the plugin end to end.
git clone https://github.com/codenio/kubectl-audit.git
cd kubectl-audit
make bin # writes bin/audit
make test # tests + coverage profile
make fmt && make vet
make install # installs the plugin to ~/.krew/kubectl-audit for ad-hoc/cluster testingRun without installing (same flags as under kubectl audit):
go run ./cmd/plugin --help
go run ./cmd/plugin pods
go run ./cmd/plugin containers --helpRepository layout
cmd/plugin/— entrypoint and CLI (cobra, config flags, printing).pkg/plugin/— audit logic, container list/table data (containers.go), and server-side table handling.deploy/krew/plugin.yaml— Krew manifest template for releases.
To bump pinned Kubernetes dependencies, use the kubernetes-deps target in the Makefile.
Issues and pull requests are welcome: github.com/codenio/kubectl-audit/issues.
Before you open a PR:
make testpasses.make binsucceeds andmake fmt/make vetare clean (or runmake bin, which runsfmtandvetfirst).
Validate changes against a cluster with make install and kubectl audit … as needed.
This plugin was created using replicatedhq/krew-plugin-template.

