How to clean-up old unused Kubernetes images/tags?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Cleaning up old Kubernetes images is really two different tasks: removing unused image data from cluster nodes and deleting stale tags from the container registry. Treating them as the same problem leads to risky cleanup steps and, in many cases, deletes the wrong thing.
Understand Where the Images Live
Kubernetes itself schedules pods, but image storage lives underneath it. Nodes keep local copies of pulled images, and your registry keeps the pushed tags and manifests. A cleanup plan should decide which layer you are targeting.
For node-level cleanup, the kubelet already performs image garbage collection when disk pressure crosses configured thresholds. Even so, operators often inspect nodes when disk usage grows unexpectedly:
Once you are on the node, the exact command depends on the runtime. For CRI-compatible environments, crictl is usually the right tool:
crictl rmi --prune removes images not currently used by any container runtime workload on that node. It should be run carefully and ideally during a maintenance window for busy clusters.
Registry Cleanup Is Usually the Bigger Win
If CI keeps publishing new tags, your registry often grows faster than node caches. The safer long-term fix is a retention policy in the registry itself. Most registries can delete untagged manifests, keep only the latest n versions, or expire tags older than a chosen age.
Examples of places to configure this include:
- Amazon ECR lifecycle policies
- Google Artifact Registry or Google Container Registry cleanup policies
- Harbor retention rules
- GitHub Container Registry retention settings through repository automation
This is preferable to manual deletion because it is predictable and repeatable. It also keeps nodes from re-pulling ancient images that should have been retired long ago.
A Safe Operational Workflow
A good cleanup routine separates inspection from deletion:
- List which images are referenced by running workloads.
- Confirm which tags in the registry are still used by active deployments.
- Apply retention policies for old build tags, feature-branch tags, or untagged layers.
- Let kubelet or the runtime prune node-local caches that are no longer referenced.
You can inspect image references currently used in the cluster with kubectl:
That output gives you a baseline before deleting anything from the registry.
Avoid Deleting by Guesswork
Teams sometimes SSH into nodes and delete images manually with Docker commands they found in an old blog post. That is risky for two reasons. First, many Kubernetes clusters no longer use Docker as the runtime. Second, deleting images from a node does not clean up the registry, so the same image may return immediately on the next pull.
A better pattern is to cordon and drain a node before aggressive manual cleanup:
After the node is drained, runtime cleanup is much safer because no regular workloads should be using those cached layers.
Common Pitfalls
- Assuming
kubectlalone can delete node-local images ignores the underlying container runtime. - Deleting registry tags without checking live workloads can break rollbacks or delayed deployments.
- Cleaning nodes manually without draining them can force immediate re-pulls or disrupt running containers.
- Treating registry cleanup and node-cache cleanup as the same operation leads to incomplete results.
- Ignoring retention policies in CI allows stale tags to accumulate again right after cleanup.
Summary
- Separate node-local image cleanup from registry tag cleanup because they solve different problems.
- Use runtime-aware tools such as
crictlfor node inspection and pruning. - Prefer automated registry retention policies over one-off manual deletion.
- Check which images are actually referenced by running workloads before removing tags.
- Drain nodes before aggressive manual cleanup if you need to prune runtime caches directly.

