Cleanup

Scan a Kubernetes cluster for idle resources — pods, PVCs, ConfigMaps, and namespaces.

annave cleanup scan connects to your Kubernetes cluster and lists resources that are idle, failed, or unused. It is read-only — it never deletes or modifies anything.

Usage

bash
annave cleanup scan [flags]

Flags

FlagShortDefaultDescription
--namespace-nLimit scan to a specific namespace. Omit to scan all namespaces.
--contextkubeconfig context to use
--kubeconfigPath to kubeconfig file
--dry-runtruePreview only — always true, the flag is for output labelling
--formatplainOutput format: plain, json, table

Kubeconfig resolution order: --kubeconfig flag → $KUBECONFIG environment variable → ~/.kube/config.

What it finds

ResourceCondition flagged
PodStatus `Succeeded` (completed job pod left behind)
PodStatus `Failed`
PodStatus `Running` with a container in `CrashLoopBackOff`
PodStatus `Pending` for longer than 10 minutes
PVCPhase `Lost`
PVCPhase `Pending` for longer than 1 hour
PVCPhase `Bound` but not mounted by any running pod for over 24 hours
ConfigMapNo owner references and older than 30 days
NamespaceNo pods, Deployments, StatefulSets, or Services

Examples

Scan all namespaces

bash
annave cleanup scan

Scan a specific namespace

bash
annave cleanup scan --namespace staging

Non-default kubeconfig context

bash
annave cleanup scan --context production-cluster

JSON output for scripting

bash
annave cleanup scan --format json | jq '[.resources[] | select(.reason == "CrashLoopBackOff")]'

Plain output

text
  Cleanup scan [DRY RUN] — 2026-05-16 10:42:07
  context         docker-desktop
  namespace       all namespaces
  findings        5 idle resource(s)

  Pod (3):
    production/worker-job-4x9mt          Completed          finished 3d ago
    staging/api-6b8f9d-abcde             CrashLoopBackOff   14 restarts
    staging/migration-job-1a2b3          Failed             exit code 1

  PVC (2):
    production/data-postgres-0           BoundUnmounted     unmounted 48h
    staging/logs-collector-pvc           Pending            pending 2h15m

JSON output shape

json
{
  "context": "docker-desktop",
  "namespace": "",
  "dry_run": true,
  "scanned_at": "2026-05-16T10:42:07Z",
  "resources": [
    {
      "resource": {
        "kind": "Pod",
        "name": "worker-job-4x9mt",
        "namespace": "production",
        "age_hours": 72
      },
      "reason": "Completed",
      "detail": "finished 3d ago"
    }
  ]
}

Required permissions

The kubeconfig user needs list and get on the following resources:

  • pods (all namespaces)
  • persistentvolumeclaims (all namespaces)
  • configmaps (all namespaces)
  • namespaces
  • deployments (for empty namespace detection)
  • statefulsets (for empty namespace detection)
  • services (for empty namespace detection)

What to watch

  • The scan is always read-only. The --dry-run flag exists only to label the output clearly — it does not change behaviour.
  • For large clusters, the default 30-second context deadline may be too short. Increase cleanup.timeout_seconds in limits.yaml and rebuild.
  • Bound-but-unmounted PVC detection compares the PVC list against all pods in the namespace. If pod listing is slow or returns partial results, some PVCs may be incorrectly flagged. Verify before deleting.
  • Empty namespace detection does not consider Custom Resource Definitions. A namespace with only CRD instances will be reported as empty.