The differences between Docker, containerd, CRI-O and runc
Containers run using a complex stack of libraries, runtimes, APIs and standards.
The explosion in containers was kicked off by Docker. But soon afterwards, the landscape seemed to explode with tools, standards and acronyms. So what is ‘docker’ really, and what do terms like “CRI” and “OCI” mean? Should you even care? Read on to find out.
Since Docker started the container frenzy, there’s been a Cambrian explosion of new container tools, standards and APIs.
But unless you’re right at the coal-face of technology, it can be very hard to keep up. And the power-games between the big tech companies can add to the confusion for the rest of us.
In this article, we’ll look at all the main names you’ve heard in container-land, try to descramble the jargon for you, and explain how the container ecosystem works.
And if you think you’re the only one who doesn’t understand it all, don’t worry… you’re not. :)
🌍 You can also read this article inGerman(translation courtesy of Anatoli Kreyman)
How we got here
There’s a difference between Docker Inc (the company), Docker containers, Docker images, and the Docker developer tooling that we’re all familiar with.
Joe Beda, co-founder of the Kubernetes project, noticed this:
Fascinating how this docker/docker-shim deprecation has created mass confusion. Probably should have seen it coming.
— Joe Beda (@jbeda)December 3, 2020
So many things called "docker". The company, the dev experience, images, container instances.
(I told you that you’re not the only one who’s confused.)
This is a perfect opportunity to clear up some of the confusion and help you understand when it’s Docker, and when it’s not. Or perhaps when it’scontainerd, orCRI-O. This is especially useful if you’relearning Kubernetes.
The main thing to understand is this:
Containers aren’t tightly coupled to the name Docker. You can use other tools to run containers.
Docker isn’t the only container contender on the block.
You can be running containers with Docker, or a bunch of other tools whicharen’t Docker.docker
is just one of the many options, and Docker (the company) creates some of the awesometools in the ecosystem, but not all.
So if you were thinking that containers are just about Docker, then continue reading! We’ll look at the ecosystem around containers and what each part does. This is especially useful if you’re thinking of moving intoDevOps.
🪐 More Docker and Kubernetes guides...
- Learn Kubernetes: How to begin your Kubernetes journey
- Container networking: How containers talk to each other
- Why use containers?: What are containers used for?
A bird’s eye view
The container ecosystem is made up of lots of exciting tech, plenty of jargon, and big companies fighting each other.
Fortunately, these companies occasionally come together in a fragile truce 🤝 to agree somestandards. Standards help to make the ecosystem more interoperable. This means you can run software on different platforms and operating systems, and be less reliant on one single company or project.
There are two big standards around containers:
Open Container Initiative (OCI): a set of standards for containers, describing the image format, runtime, and distribution.
Container Runtime Interface (CRI) inKubernetes: An API that allows you to use different container runtimes in Kubernetes.
We’ll take a look at these below. But first, this illustration gives an overview of howDocker,Kubernetes,CRI,OCI,containerd andrunc fit together in this ecosystem:

The relationship between Docker, CRI-O, containerd and runc – in a nutshell
Source: Tutorial Works
Let’s look at each of these projects in turn.
Docker
In our rundown of container jargon, we’ve got to start with Docker. It’s the most popular developer tool for working with containers. And, for a lot of people, the name “Docker” is synonymous with the word “container”.
Docker kick-started the container space by creating a veryergonomic (nice-to-use) tool for creating and working with containers. The tool was calleddocker
. It’s now branded asDocker Engine and comes in two versions:
- Docker Desktop for your developer workstation, available for Windows, Mac and Linux
- Docker Engine for your server, available for Linux.
How the Docker stack works
Docker Engine comes with a bunch of tools to make it easy to build and run containers as a developer, or a systems administrator. It is basically a command-line interface (CLI) for working with containers.
But thedocker
command is just one piece of the puzzle. It actually calls down to some lower-level tools to do the heavy lifting:

The projects involved in running a container with Docker
Source: Tutorial Works
Thedocker
command line tool can build container images, pull images from registries, create, start and manage containers. It does this by calling down to a bunch of lower-level tools.
What are the lower-level tools in the Docker stack?
From the bottom up, these are the tools thatdocker
uses to run containers:
Lowest-level 🔩The low-level container runtime.runc is a low-levelcontainer runtime. It uses the native features of Linux to create and run containers. It follows theOCI standard, and it includeslibcontainer, a Go library for creating containers.
🔧The high-level container runtime.containerd sits above the low-level runtime, and adds a bunch of features, like transferring images, storage, and networking. It also fully supports theOCI spec.
👺The Docker daemon.dockerd is a daemon process (a long-running process that stays running in the background) which provides a standard API, and talks to the container runtime1
Highest level 👩💻The Docker CLI tool. Finally,docker-cli gives you the power to interact with the Docker daemon using
docker ...
commands. This lets you control containers without needing to understand the lower levels.
So, in reality, when you run a container withdocker
, you’re actually running it through the Docker daemon, which calls containerd, which then uses runc.
If you want to learn more about the container ecosystem, you should check out Nigel Poulton’s book, which explains it in more detail:
Docker Deep Dive
by Nigel Poulton
A really excellent technical book about Docker, for beginners and experts alike.
Does Kubernetes use Docker?
A really common question is “how do containers run in Kubernetes?”. Does Kubernetes use Docker? Well, it doesn’t anymore – but it used to.
Originally, Kubernetes used Docker (Docker Engine) to run containers.
But, over time, Kubernetes evolved into a container-agnostic platform. TheContainer Runtime Interface (CRI) API was created in Kubernetes, which allows different container runtimes to be plugged into it.
Docker Engine, being a project older than Kubernetes, doesn’t implement CRI. So to help with the transition, the Kubernetes project included a component calleddockershim, which allowed Kubernetes to run containers with the Docker runtime.
It bridged the gap between the old world and the new.
What is a shim?
In the real world (!), a shim is:
a washer orthin strip of material used to align parts, make them fit, or reduce wear.
So in tech terms, ashim is a component in a software system, which acts as a bridge between different APIs, or as a compatibility layer. A shim is sometimes added when you want to use a third-party component, but you need a little bit of glue code to make it work.
Death of the shim
But, as of Kubernetes 1.24, the dockershim componentwas removed completely, and Kubernetes no longer supports Docker as a container runtime. Instead, you need to choose a container runtime that implements CRI.
The logical successor to Docker Engine in Kubernetes clusters is…containerd.(10 points if you got that correct!) Or you can use an alternative runtime, likeCRI-O.
This doesn’t mean that Kubernetes can’t run so-called Docker-formatted containers. Bothcontainerd andCRI-Ocan run Docker-formatted and OCI-formatted images in Kubernetes; they can do it without having to use thedocker
command or the Docker daemon.
Phew. Hope that cleared that up.
What about Docker Desktop?
Docker Desktop is a GUI application for Mac and Windows, which makes it easy to run Docker on your laptop. It includes a Linux virtual machine which runs the Docker daemon, and it also includes Kubernetes.
Docker Desktop is aimed mainly at developers. It provides a very nice UI for visualising your containers, and also includes an easy way to start a Kubernetes cluster.
You don’t need Docker Desktop to work with containers, but it’s a nice way to get started. If you’re running Linux already, you can install Docker Engine instead, and you’ll be good to go.
The standards and APIs: OCI and CRI
We saw earlier that some standards help to make it easier to run containers on different platforms. But what are these standards?
Open Container Initiative (OCI) specifications
TheOCI was one of the first efforts at creating some standards for the container world. It was established in 2015 by Docker and others.
The OCI is backed by a bunch of tech companies and maintains a specification for the container image format, and how containers should be run.
The idea behind the OCI specifications, is to standardise what a container is, and what it should be able to do. That means you’re free to choose between different runtimes which conform to the specification. And each of these runtimes might have a different lower-level implementation.
For example: you might use one OCI-compliant runtime for your Linux hosts, but a different runtime for your Windows hosts.
Kubernetes Container Runtime Interface
The other standard we need to talk about is theContainer Runtime Interface (CRI). This is an API that was created by the Kubernetes project.
CRI is an interface used by Kubernetes to control the different runtimes that create and manage containers.
Kubernetes tries not to care which container runtime you use. It just needs to be able to send instructions to it – to create containers for Pods, terminate them, and so on. And that’s where CRI comes in. CRI is an abstraction for any kind of container runtime that might exist now, or in the future. So CRI makes it easier for Kubernetes to use different container runtimes.
Instead of the Kubernetes project needing to add support for each runtime individually, the CRI API describes how Kubernetes will interact withany runtime. As long as a given container runtime implements the CRI API, the runtime can create and start containers however it likes.
Here’s a quick visualisation of how CRI fits into the container ecosystem:

You can choose your own container runtime for Kubernetes
Source: Tutorial Works
So if you prefer to usecontainerd to run your containers in Kubernetes, you can! Or, if you prefer to useCRI-O, then you can. This is because both of these runtimes implement the CRI specification.
If you’re an end user (like a developer), the implementation mostly shouldn’t matter. There are subtle differences between different CRI implementations, but they are intended to be pluggable and seamlessly changeable.
But, if you pay to get support (security, bug fixes etc) from a vendor, your choice of container runtime might be made for you. For example, Red Hat’sOpenShift usesCRI-O, and offers support for it. Docker provides support for their owncontainerd.
How to find out your container runtime in Kubernetes
InKubernetes architecture, thekubelet (the agent that runs on each node) is responsible for sending instructions to the container runtime to start and run containers.
You can check which container runtime you’re using by looking at thekubelet parameters on each node. There’s an option--container-runtime
and--container-runtime-endpoint
which are used to configure which runtime to use.
containerd and CRI-O
We’ve seen that Docker Engine calls down to a bunch of lower-level tools. But what are these tools? And how do they fit together?
The first layer is the high-level runtimes:containerd, created by Docker, andCRI-O, created by Red Hat.
containerd
containerd is a high-level container runtime that came from Docker. It implements the CRI spec. It pulls images from registries, manages them and then hands over to a lower-level runtime, which uses the features of the Linux kernel to create processes we call ‘containers’.
containerd was born from parts of the original Docker project. But why was it separated it out in this way? Well, it basically made Docker more modular. And this allowed Docker’s particular ‘flavour’ of containers to run in more places (like on Kubernetes), without needing the Docker daemon and the Docker CLI tool.
So internally, Docker Engine usescontainerd. When you install Docker, it will also installcontainerd.
containerd can be used as the container runtime for Kubernetes, because it implements the Kubernetes Container Runtime Interface (CRI), via itscri plugin.
CRI-O
CRI-O is another high-level container runtime which implements the Kubernetes Container Runtime Interface (CRI). It’s an alternative tocontainerd. It pulls container images from registries, manages them on disk, and launches a lower-level runtime to run container processes.
Yes, CRI-O is another container runtime. It was born out of Red Hat, IBM, Intel,SUSE and others.See here for the backstory on why CRI-O was created.
CRI-O was created to be a container runtime for Kubernetes. It provides the ability to start, stop and restart containers, just likecontainerd.
Just like containerd, CRI-O implements the CRI API, so it can be used as a container runtime on Kubernetes.
runc and other low-level runtimes
runc is an OCI-compatible container runtime. It implements the OCI specification and runs the container processes.
runc is sometimes called the “reference implementation” of OCI.
What is a reference implementation?
A reference implementation is a piece of software that has implemented all the requirements of a specification or standard.
It’s usually the first piece of software which is developed from the specification.
In the case of OCI,runc provides all the features expected of an OCI-compliant runtime, although anyone can implement their own OCI runtime if they like.
runc provides all of the low-level functionality for containers, interacting with existing low-level Linux features, like namespaces and control groups. It uses these features to create and run container processes.
Other low-level runtimes
But, runc isn’t the only low-level runtime. The OCI specification is allowing other tools to implement the same functionality in a different way:
- crun a container runtime written inC (by contrast, runc is written in Go.)
firecracker-containerd from AWS, which implements the OCI specification as individual lightweight VMs (and it is also the same technology which powers AWS Lambda)
gVisor from Google, which creates containers that have their own kernel. It implements OCI in its runtime called
runsc
.
What's the equivalent of runc on Windows?
runc is a tool for running containers on Linux. So that means it runs on Linux, on bare metal or inside a VM.
On Windows, it’s slightly different. The equivalent ofrunc is Microsoft’s Host Compute Service (HCS). It includesa tool calledrunhcs, which itself is a fork ofrunc, and also implements the Open Container Initiative specification.
Summary
Well, we’ve come to the end of this journey. But what have we learned?
Docker is just one part in the ecosystem of containers.
There is a set of open standards which, theoretically, make it easier to swap out different implementations. Projects likecontainerd,runc andCRI-O implement parts of those standards.
In Kubernetes, you can choose which container runtime you want to use, as long as it supports the CRI API. You can usecontainerd orCRI-O.
With everyoneworking hard on all this new tech, expect this to change rapidly, as things progress. We’ll try and keep this article updated where we can.
So now you know everything there is to know about the fun (and slightly over-complicated) world of containers.
But the next time you strike up a conversation at a party 🎈, maybe it’s best not to talk about containers, or you’ll end up with a room full of people who are bored to tears. 😴
Poulton, Nigel.Docker Deep Dive. Nigel Poulton, 2020. ↩