Deprecation of Docker as a Container Runtime in Kubernetes 1.20 — Implications
By: Yaniv Tzur
Tags: Containers, Cri, Kubernetes, Oci, Docker

Recently, the Kubernetes development team has announced that Docker has been deprecated as a container runtime, and that it plans to remove support for it entirely in late 2021.

To begin with, I will describe how Docker fits into the complex distributed system that is Kubernetes. Generally speaking, the smallest atomic workload that can be run on a Kubernetes cluster is a pod. Each pod is scheduled by the Kubernetes scheduler to a particular worker node (physical or virtual machine).

On each worker node, a process called the kubelet is running. The kubelet receives a set of PodSpec resources through one of several mechanisms, mainly through the API server. For each of these, the kubelet makes sure that the containers corresponding to each PodSpec are running.

As for the pod itself, each pod consists of one or more containers. Each container is executed by a container runtime installed on the node. Common container runtimes used on Kubernetes nodes include Docker (still), containerd and CRI-O.

Container Execution Flow on Kubernetes Using Docker

In an earlier stage of Kubernetes, communication between the kubelet and container runtimes officially supported by Kubernetes was deeply integrated into the kubelet’s source code, making the integration of new container runtimes into Kubernetes difficult. In 2016, in Kubernetes 1.5, the Kubernetes development team released the Container Runtime Interface (CRI). The CRI is a clearly defined, gRPC API which a container runtime must provide if it is to be used by the kubelet to run containers. This allows to develop container runtimes without requiring a deep knowledge of the kubelet’s internals.

Now, we come to the part where we describe the considerations as to why Docker has been deprecated as a container runtime for Kubernetes. The CRI has standardized expectations of a compatible runtime. The three most fundamental of these are that the runtime can both start and stop pods, can start, stop, kill and delete containers, and that it provides container image management.

With respect to these expectations, Docker has two main drawbacks. To begin with, Docker is much more than a container runtime. Docker is an entire technological stack, which consists of additional functionalities such as image building, and human-friendly UX features (e.g. a CLI), which are useful for a human user of Docker, but are entirely redundant for the kubelet’s needs. The main two components in Docker that are actually required by the kubelet are containerd, which is a “high-level” container runtime that is CRI-compliant, and runc, which is a “low-level” container runtime solely used to actually run containers. This brings us to the second drawback. In practice, the kubelet only needs containerd and the accompanying low-level container runtime runc. However, Docker itself is not CRI-compliant, and therefore, in order to eventually get at what the kubelet actually needs, which is to interact with containerd, an additional tool called dockershim is maintained by the Kubernetes development team.

The need to maintain an additional tool, dockershim, places an additional burden on the Kubernetes development team which is mostly unnecessary, since it contrasts the whole reason the CRI was created. This prompted the Kubernetes development team to announce the deprecation of dockershim, in favor of a CRI-compliant runtime, such as containerd or CRI-O.

Next, I discuss the implications of this change. For users of a Kubernetes cluster, the change is transparent, and therefore users shouldn’t worry about it. That’s of course assuming each node already has a CRI-compliant container runtime, but that’s something that should be handled by the administrator of the cluster. By “users”, I refer to people who deploy containers in pods on a Kubernetes cluster from ready-made images. As for developers who are used to building Docker images, pushing them to a registry, and then using those to deploy containers in pods, the change is also transparent. The reason is that “Docker images” are in fact not Docker specific but rather comply with a well established container image specification, called the OCI image specification.

Therefore, there are mainly two kinds of people who should make preparations following the deprecation of dockershim and its future planned removal. The first kind is the administrators of a Kubernetes cluster, e.g. DevOps, who need to make sure that each node is already running a CRI compliant runtime. The second type is the one which relies for some reason on the container runtime running on a node being specifically Docker. In these cases, failing to prepare properly in time, and then for example upgrading to Kubernetes 1.23 (when dockershim support is currently slated to first be removed), should prevent new containers from being run and possibly disrupt the operation of existing containers. If you belong to one of these two groups, I strongly suggest you make the necessary preparations as soon as possible, to prevent any disruption of your workloads.

As a last note, I will make a small reservation on what I wrote so far. Shortly after the announcement about the deprecation of dockershim, Mirantis announced that it would take over the maintenance of dockershim in cooperation with Docker Inc., only that it would be maintained as a separate component outside the kubelet process. For clusters currently using Docker as a container runtime, this will still require some configuration change to ensure a smooth transition, but according to Mirantis it should be relatively small and easy.