Container runtimes: clarity

As a maintainer of the CRI-O container runtime for kubernetes I often get asked the following questions at conferences and meetups:

Is CRI-O a replacement for Docker?

Is containerd a replacement for CRI-O?

I decided to write this blog to try to answer these questions. In the future, when I get asked these questions I’ll will point to this blog and they can read more about the topic.

What is a container runtime?

Most people when referring to a container runtime think of Docker. Even if tools for making containers (lxc) predate Docker, Docker brought containers to the mainstream because of its simplicity. Docker became the de facto standard way people run containers for the past 5 years now.

Dan Walsh also dives deeper into container runtimes here:

While that’s still great, it has led to misunderstandings that the only way to run containers was through this one tool.

In the context of Kubernetes, we have more choices when it comes to container runtimes.

Kubernetes originally leveraged Docker for running containers, it is still the default container runtime today. However, a few years ago CoreOS wanted to use kubernetes on Rkt. CoreOS offered a bunch of patches to kubernetes to use Rkt as an alternative to Docker.

Upstream Kubernetes saw this as a problem, since they did not want to have to modify the kubernetes code base for each new container runtime. Upstream kubernetes decided to create an API to define calls that it would make into container runtimes, thus the Container Runtime Interface (CRI) was born. This interface reverses the responsibility from the core Kubernetes of talking to a container runtime like Docker or Rkt. Interaction between kubernetes and a given runtime is performed through the CRI API.

This means anyone can create his own container runtime and simply have it speak the CRI interface in order to run containers under kubernetes.

We decided to create CRI-O, which was the first container runtime created for the kubernetes CRI interface. Others CRI based container runtimes have popped up over the past year, fratki for example.

CRI-O leverages all of the OCI standards:

  • Runs containers using the OCI Runtime tools defaulting to runc.
  • Managing container images following the OCI image specification.
  • Uses the OCI-Runtime-tools for generating the OCI Runtime Specification
  • CNI for setting up the container networking.
  • containers/image for pulling container images from container registries like

CRI-O defaults to running containers with runc, exactly the same as Docker does today: running containers with runc. In addition to that CRI-O has support for running containers using virtualization technologies like Clear Containers, and soon Kata Containers.

At the time of this writing, there are mainly 4 containers runtimes implementing the CRI interface: CRI-O, fratki, cri-containerd, dockershim.

Wait, why haven’t I listed containerd?

Let’s get this straight, CRI-O serves Kubernetes by implementing the CRI interface, it’s meant to be used only by Kubernetes, it’s a kubernetes incubator project and you won’t see us implementing something not strictly needed by Kubernetes which could possibly mine kubernetes stability.

Containerd isn’t implementing the CRI interface, it does so with another daemon called cri-containerd which acts as a shim between containerd itself and the kubelet.

Containerd on the other hand has multiple masters. It services the needs of the Docker daemon for running traditional Docker containers. It services docker swarm for running Docker container orchestration. It services Mesosphere orchestration for running containers, and finally it also can be used for running kubernetes container workloads. Containerd however does not implement the CRI.

So, is Containerd a replacement for CRI-O? Nope, cri-containerd could be. Cri-containerd is yet another daemon that implements the CRI and then translates it and calls out to the containerd daemon to launch containers. You end up with something like the kublet daemon talking to the cri-containerd daemon , which calls into the containerd daemon, which finally launches runc and then pid1 of the container.

We believe that CRI-O has a big advantage over cri-containerd in stability, by not having to serve many different masters in the container orchestration world, we can concentrate on stability and performance for kubernetes and kubernetes only workloads.

Is CRI-O going to replace Docker? Nope, or well, it’s meant as a kubernetes focused runtime, so it replaces Docker in the context of Kubernetes, it won’t replace Docker as the developer tool we’re all used to. CRI-O does not implement the Docker Engine API or the Docker CLI. This means you can not use the Docker CLI to talk to a CRI-O daemon. You have to go through Kubernetes.

Note: Others are working on a Docker CLI replacement called Podman that you might want to check out.

Bottom Line:

CRI-O is a specific container runtime dedicated to Kubernetes work loads. It’s a Kubernetes incubator project and as such it’s also part of the CNCF. Like Docker and other container runtimes, it use the OCI specification for definition of container images and container runtimes. CRI-O is available now on RHEL, Fedora, Centos, Ubuntu.

Like what you read? Give Antonio Murdaca a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.