containerd vs Docker vs CRI-O: how to choose
These three sit at different layers, which is why comparing them directly confuses people. containerd and CRI-O are container runtimes that Kubernetes talks to. Docker is a complete developer platform — CLI, build system, image management and daemon — that happens to contain a runtime, and in fact uses containerd underneath.
For Kubernetes the practical choice is containerd or CRI-O. Docker as a Kubernetes runtime ended with the removal of dockershim in Kubernetes 1.24; clusters now speak CRI directly. This changed nothing about images, which remain OCI-standard and identical regardless of which builds or runs them.
For local development, Docker Desktop and the Docker CLI remain the most common choice and there is nothing wrong with that. Building images with Docker and running them under containerd in production is the normal arrangement, not a mismatch.
Which layer is which
| Docker | containerd | CRI-O | |
|---|---|---|---|
| Layer | Full platform: CLI, build, runtime | Container runtime with a broad API | Container runtime, CRI only |
| Kubernetes runtime today | No — dockershim removed in 1.24 | Yes, the most common default | Yes, the default in OpenShift |
| Builds images | Yes | No — use BuildKit, Buildah or similar | No |
| Scope | Deliberately broad | General purpose beyond Kubernetes | Deliberately minimal, Kubernetes-only |
| Typical use | Local development | Managed and self-managed clusters | OpenShift and Red Hat estates |
containerd or CRI-O
For most clusters this is not a decision you need to make — your distribution or managed provider has chosen, and their choice is well-supported. containerd is the default on most managed offerings; CRI-O is the default on OpenShift and tracks Kubernetes releases closely by design.
CRI-O's argument is minimalism: it implements CRI and nothing else, so the surface to secure and upgrade is smaller. containerd's argument is breadth — it is used outside Kubernetes too, has a larger ecosystem of plugins and tooling, and is what most documentation assumes. Neither is a mistake, and changing an already-working runtime is rarely worth the disruption.
Frequently asked questions
Do I need to rebuild images after moving off Docker as the runtime?
No. Images are OCI-standard and portable across all three — an image built by Docker runs unchanged under containerd or CRI-O. This is the most common misconception about the dockershim removal, and it caused a lot of unnecessary alarm.
Can I still use the Docker CLI locally?
Yes, and most developers do. What changed is how Kubernetes nodes run containers, not how you build images on your laptop. Build with Docker, push to a registry, run under containerd in the cluster — that is the standard workflow and nothing about it is inconsistent.
What replaced docker exec and docker ps on nodes?
crictl for CRI-level operations against either runtime, and nerdctl if you want a Docker-compatible CLI over containerd specifically. Day to day you should be reaching for kubectl rather than logging into nodes; crictl is for node-level debugging when kubectl cannot tell you what you need.
Which is more secure?
They are close enough that the runtime is rarely your weakest link. CRI-O's smaller scope means less code and a smaller attack surface, which is a genuine if modest advantage. Both support running with gVisor or Kata Containers for stronger isolation. Your image contents, RBAC and network policy will matter far more than this choice.
Need this managed for you, not just automated?
We're also a hands-on DevOps consultancy — Kubernetes, CI/CD, and cloud infrastructure.