How to make microk8s ctr image prune
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
MicroK8s uses containerd under the hood, and ctr is the low-level client for inspecting that runtime. The important detail is that ctr is not Docker, so you usually do not get a single friendly image prune command that safely cleans everything up for you.
Why ctr cleanup works differently
In a MicroK8s setup, images are commonly stored in the k8s.io namespace because Kubernetes workloads live there. If you run ctr without the right namespace, you may think the image store is empty or accidentally inspect the wrong data.
The second difference is conceptual. Containerd tracks content, snapshots, containers, and image references separately. Deleting an image reference is not the same thing as blindly deleting every blob on disk. That is why a safe cleanup flow starts by identifying what Kubernetes is still using, then removing only images you no longer want cached.
A practical prune workflow
The following sequence is a safe manual equivalent of "prune unused images." It lists stored images, lists images referenced by running workloads, and removes an image explicitly.
The first command shows what containerd currently knows about. The second command shows what your cluster is actively configured to use. Compare the two lists before deleting anything. If an image still appears in a Deployment, DaemonSet, Job, or CronJob, the cluster may need it again even if no pod is running at this moment.
What "prune" should mean in MicroK8s
A good prune policy in MicroK8s is conservative:
- Remove images that are clearly old tags, failed experiments, or one-off test pulls.
- Keep images for workloads you expect to restart soon.
- Prefer explicit deletion over mass removal unless the node is disposable.
This matters because Kubernetes is constantly reconciling state. If you remove an image that a controller still expects, the next pod start will trigger a new pull. That may be acceptable, but it should be a deliberate choice, not an accident caused by treating ctr like Docker.
Checking what is safe to delete
Beyond running pods, review your manifests and controllers. A stopped Job, a scaled-to-zero Deployment, or a Helm release you plan to re-enable can still depend on an image that no current pod references. On small developer machines, a useful rule is to delete only images whose tag you recognize as obsolete and whose workload has been removed from the cluster configuration.
If you are doing frequent local experiments, it is often better to pin fewer tags and rebuild or import consistently than to let many near-identical images accumulate.
When to use a higher-level tool
ctr is powerful, but it is intentionally low level. If your goal is everyday cluster administration rather than containerd internals, a Kubernetes-aware or CRI-aware tool may be easier to reason about. Even then, the same principle applies: inspect first, delete second, and remember that the runtime cache and the declarative cluster state are related but not identical.
Common Pitfalls
- Forgetting the
k8s.ionamespace and concluding that MicroK8s has no images. - Expecting a Docker-style one-command prune workflow from
ctr. - Deleting an image still referenced by a Deployment or Job and being surprised when it is pulled again.
- Confusing image references with all runtime data on disk. Removing one does not mean every related artifact disappears instantly.
- Running cleanup on a node that is short-lived only during development, then spending more time re-pulling images than you saved.
Summary
- In MicroK8s, image cleanup with
ctris usually an explicit delete workflow, not a single prune command. - Always inspect the
k8s.ionamespace because that is where Kubernetes images normally live. - Compare stored images with the images referenced by cluster workloads before removing anything.
- Delete obsolete tags deliberately rather than trying to wipe the cache blindly.
- Treat
ctras a low-level containerd tool, not as a drop-in replacement for Docker CLI behavior.
Related reading
- How to make nested variables optional in Helm
- How to make use of Kubernetes port names?
- How to manage page cache resources when running Kafka in Kubernetes
- How to manage persistent connections in kubernetes
- How to mimic '--volumes-from' in Kubernetes
- How to monitor disk usage of kubernetes persistent volumes?
- How to manage pod scheduling in aws EKS?
- How to merge kubectl config file with /.kube/config?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.