The differences between Docker, containerd, CRI-O and runc

The container ecosystem is full of terms you’re expected to know. So, we’ve decoded them for you.

Docker kicked off the explosion in containers, but soon afterwards, the landscape seemed to explode with tools, standards and acronyms. So what is ‘docker’ really, and what do the terms like “CRI” and “OCI” mean? Why should you even care? Read on to figure it all out.

Since Docker started the container frenzy, there’s been a Cambrian explosion of new container tools, standards and APIs.

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 just 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 in German (Anatoli Kreyman)

Understanding Docker

There is a difference between Docker the company, Docker containers, Docker images, and the Docker developer tooling that we’re all used to:

(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 or containerd, or Docker or CRI-O. This is especially crucial if you’re learning Kubernetes.

The main thing to understand is this:

Docker isn’t the only container contender on the block.

Containers are no longer tightly coupled with the name Docker. You can be running containers with Docker, or a bunch of other tools which aren’t Docker. docker is just one of the many options, and Docker (the company) backs some of the tools 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 into DevOps.

The container ecosystem, explained

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 some standards. Standards help to make the ecosystem more interoperable, so you can run software on different platforms and operating systems, and be less reliant on one single company or project.

The main standards around containers that you should be aware of (although you don’t need to know all the details) are:

  • The Open Container Initiative (OCI) which publishes specifications for containers and their images.

  • The Kubernetes Container Runtime Interface (CRI), which defines an API between Kubernetes and a container runtime underneath.

This illustration shows exactly how Docker, Kubernetes, CRI, OCI, containerd and runc fit together in this ecosystem:

Diagram showing the relationships and dependencies between docker, Kubernetes, CRI-O, containerd and runc

The relationship between Docker, CRI-O, containerd and runc – in a nutshell

Source: Tutorial Works


In our rundown of container jargon, we must start with Docker, because it’s the most popular developer tool for working with containers. And, for a lot of people, the name “Docker” itself is synonymous with the word “container”.

Docker kick-started this whole revolution. Docker created a very ergonomic (nice-to-use) tool for working with containers – which is also called docker.

Lots of people liked it, and it became very popular.

Diagram showing the connection between Docker, containerd and runc

The projects involved in running a container with Docker

Source: Tutorial Works

docker is designed to be installed on a workstation or server and comes with a bunch of tools to make it easy to build and run containers as a developer, or as a DevOps person.

The docker command line tool can build container images, pull them from registries, create, start and manage containers.

To make all of this happen, the experience you get when you type docker is now made up of these projects (there are others, but these are the main ones):

  • docker-cli: This is the command-line utility that you interact with using docker ... commands.

  • containerd: This is a daemon process which manages and runs containers. It pushes and pulls images, manages storage and networking, and supervises the running of containers.

  • runc: This is the low-level container runtime, or the thing that actually creates and runs containers). It includes libcontainer, a native Go-based implementation for creating containers.

In reality, when you run a container with docker, you’re actually running it through the Docker daemon, which calls containerd, which then uses runc.

Dockershim: Docker in Kubernetes

So how does Docker relate to Kubernetes?

Kubernetes includes a component called dockershim, which allows it to run containers with Docker.

But actually, Kubernetes prefers to run containers through any container runtime which supports its Container Runtime Interface (CRI).

Docker, being older than Kubernetes, doesn’t implement CRI. So that’s why the dockershim exists, to basically bolt Docker onto Kubernetes. Or Kubernetes onto Docker, whichever way round you prefer to think of it.

What is a shim?

In the real world (!), a shim is:

a washer or thin strip of material used to align parts, make them fit, or reduce wear.

In tech terms, a shim 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.

Going forward, Kubernetes will remove support for Docker directly, and prefer to use only container runtimes which implement its Container Runtime Interface. This probably means using containerd or CRI-O.

But this doesn’t mean that Kubernetes won’t be able to run Docker-formatted containers. Both containerd and CRI-O can run Docker-formatted (actually OCI-formatted) images; they just do it without having to use the docker command or the Docker daemon.

Phew. Hope that cleared that up.

What about ‘Docker images’?

What many people refer to as Docker images, are actually images packaged in the Open Container Initiative (OCI) format.

So if you pull an image from Docker Hub, or another registry, you should be able to use it with the docker command, or on a Kubernetes cluster, or with the podman utility, or any other tool that supports the OCI image format spec.

This is the benefit of having an open standard – anybody can write software that supports the standard.

Container Runtime Interface (CRI)

CRI is the protocol that Kubernetes uses to control the different runtimes that create and manage containers.

CRI is an abstraction for any kind of container runtime you might want to use. So CRI makes it easier for Kubernetes to use different container runtimes.

Instead of the Kubernetes project needing to manually add support for each runtime, the CRI API describes how Kubernetes interacts with each runtime. So then, it’s down to the runtime to actually manage containers. As long as it obeys the CRI API, it can do whatever it likes.

Diagram showing Kubernetes and the implementations of its Container Runtime Interface

You can choose your own container runtime for Kubernetes

Source: Tutorial Works

So if you prefer to use containerd to run your containers, you can. Or, if you prefer to use CRI-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.

Your choice of runtime might be important if you pay to get support (security, bug fixes etc) from a vendor. For example, Red Hat’s OpenShift uses CRI-O, and offers support for it. Docker provides support for their own containerd.

How to check your container runtime in Kubernetes

In Kubernetes architecture, the kubelet (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 the kubelet parameters on each node. There’s an option --container-runtime and --container-runtime-endpoint which are used to configure which runtime to use.


containerd is a high-level container runtime that came from Docker, and implements the CRI spec. It pulls images from registries, manages them and then hands over to a lower-level runtime, which actually creates and runs the container processes.

containerd was separated out of the Docker project, to make Docker more modular.

So Docker uses containerd internally itself. When you install Docker, it will also install containerd.

containerd implements the Kubernetes Container Runtime Interface (CRI), via its cri plugin.


CRI-O is another high-level container runtime which implements the Container Runtime Interface (CRI). It’s an alternative to containerd. 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.

It was specifically created from the ground up as a container runtime for Kubernetes. It provides the ability to start, stop and restart containers, just like containerd.

Open Container Initiative (OCI)

The OCI is a group of tech companies who maintain a specification for the container image format, and how containers should be run.

The idea behind the OCI is that you can choose between different runtimes which conform to the spec. Each of these runtimes have different lower-level implementations.

For example, you might have one OCI-compliant runtime for your Linux hosts, and one for your Windows hosts.

This is the benefit of having one standard that can be implemented by many different projects. This same “one standard, many implementations” approach is in use everywhere, from Bluetooth devices to Java APIs.


runc is an OCI-compatible container runtime. It implements the OCI specification and runs the container processes.

runc is 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.

A couple of alternatives to runc are:

  • crun a container runtime written in C (by contrast, runc is written in Go.)

  • kata-runtime from the Katacontainers project, which implements the OCI specification as individual lightweight VMs (hardware virtualisation)

  • 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 of runc is Microsoft’s Host Compute Service (HCS). It includes a tool called runhcs, which itself is a fork of runc, and also implements the Open Container Initiative specification.


And that’s it. In this article we’ve seen that Docker is just one small part of the ecosystem of containers.

There is a bunch of open standards which make it easier to swap out different implementations. This is where we get the standards CRI and OCI, and projects like containerd, runc and CRI-O.

With everyone busy working on all this new tech, expect this to change rapidly, as things progress.

Now you know everything there is to know about the fun and slightly over-complicated world of containers.

But the next time you’re at a party 🎈, just don’t tell the host you’re using “Docker containers”….

Tom Donohue

By Tom Donohue, Editor | Twitter | LinkedIn

Tom is the founder of Tutorial Works. He’s an engineer and open source advocate. He uses the blog as a vehicle for sharing tutorials, writing about technology and talking about himself in the third person. His very first computer was an Acorn Electron.

Join the discussion

Got some thoughts on what you've just read? Want to know what other people think? Or is there anything technically wrong with the article? (We'd love to know so that we can correct it!) Join the conversation and leave a comment.

Comments are moderated.