skip to content

Kubernetes 1.24 removed dockershim - do images built with `docker build` still run?

level: juniorimportance: must knowfreq 68%

answer

  1. Only one component was actually deleted
  2. The image format is an open standard
  3. A translator inside the node agent
  4. Deprecated in 1.20, removed in 1.24

basics

~20 s

Yes. Dockershim was the Kubernetes node agent's built-in adapter for talking to Docker Engine, and only that adapter was removed. An image is a standard OCI artefact, so containerd and CRI-O pull and run exactly the same images.

solid answer

~40 s

Yes - nothing about the image changes. Dockershim was code inside the Kubernetes node agent that translated Container Runtime Interface (CRI) gRPC calls into Docker Engine API calls; Kubernetes deprecated it in 1.20 and deleted it in 1.24. A node loses that adapter, not the ability to run your images: containerd and CRI-O implement CRI directly and run the same standard image format that `docker build` and `docker push` produce. Dockerfiles, registries, tags and the container's runtime behaviour are untouched, because behaviour comes from the image config and the OCI runtime spec. What does change is node-level tooling: on a containerd node the `docker` CLI no longer lists the cluster's containers, so node debugging moves to `crictl`, and anything that bind-mounted `/var/run/docker.sock` or shelled out to `docker` on the node has to be replaced.

code

dockerfile · 8 lines
dockerfile
FROM golang:1.22 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /out/fanout ./cmd/fanout

FROM scratch
COPY --from=build /out/fanout /fanout
ENTRYPOINT ["/fanout"]

go deeper

for a junior

Be ready to answer the panic version of this in one sentence: an adapter was removed, not your images. Recall that dockershim lived inside the Kubernetes node agent and that containerd and CRI-O run the same images your docker build produces.

for a middle

Explain what the adapter translated - CRI gRPC calls into Docker Engine API calls - and name the two CRI services. Expect a follow-up on what concretely changes on a node once it is gone, starting with docker ps no longer showing anything useful.

for a senior

Show you have run the migration: an inventory of workloads mounting the Docker socket, node agents that shell out to docker, log-shipping assumptions, and a node-by-node rollout with a way back. The interesting risk is never the image; it is the tooling around the node.

for a principal

Own the framing: an in-tree special case for one vendor's engine became a maintenance liability, and a published contract is what made the swap survivable. Argue how you keep your own platform's runtime layer replaceable so the next such change is a configuration change.

## The headline, and what it actually said In December 2020 the Kubernetes 1.20 release notes deprecated a component called *dockershim*. That was compressed online into 'Kubernetes is dropping Docker', and it has been an interview question ever since. The accurate statement is far narrower: one adapter inside one Kubernetes node component was deprecated, and in Kubernetes 1.24 (May 2022) its code was deleted. Nothing about how images are built, stored or shaped changed. ## What dockershim was The node agent that starts and stops containers does not link against any particular container engine. It speaks the **Container Runtime Interface (CRI)**, a gRPC contract with two services: - **RuntimeService** - pod sandbox and container lifecycle: `RunPodSandbox`, `CreateContainer`, `StartContainer`, `StopContainer`, `RemoveContainer`, `ListContainers`, plus `Exec`, `Attach`, `PortForward` and status calls. - **ImageService** - `PullImage`, `ListImages`, `ImageStatus`, `RemoveImage`, `ImageFsInfo`. Any runtime implementing those two services over a unix socket can be driven by the node agent. containerd does, through a built-in CRI plugin; CRI-O was written for nothing else. Docker Engine does not. It exposes its own HTTP API on `/var/run/docker.sock`, designed years before CRI existed. So Kubernetes shipped **dockershim**: a CRI implementation compiled into the node agent that accepted CRI gRPC calls and re-issued them as Docker Engine API calls. It also had to invent the concepts Docker Engine has no notion of - a CRI *pod sandbox* became a small `pause` container whose namespaces the pod's real containers joined. That made Docker Engine the one runtime with special, in-tree support maintained by the Kubernetes project itself, while every other runtime lived out of tree and was maintained by its own community. Add the fact that Docker Engine is itself a layer above containerd - so a Docker node meant node agent to dockershim to dockerd to containerd, where a containerd node meant node agent straight to containerd - and the shim was carrying maintenance cost for hops nobody needed. ## Why your images are untouched Building an image and running one are two different contracts, and only the running side changed. `docker build` produces an image - a manifest, a config and a set of layer blobs - in a format standardised under the Open Container Initiative and pushed over a standardised registry protocol. containerd and CRI-O consume exactly that. (Docker's own manifest media types predate the OCI ones; both are accepted.) A Dockerfile is an input to a *builder*, not a runtime instruction set, and once the image exists nothing in it records which engine built it. Concretely, all of this keeps working after the removal: - `docker build`, `docker buildx build`, your Dockerfiles and multi-stage builds - `docker push` / `docker pull`, Docker Hub, any private registry - Docker Desktop on developer laptops - the container's runtime behaviour - ENTRYPOINT/CMD, ENV, USER, WORKDIR, exposed ports, signal delivery - because that comes from the image config and the OCI runtime spec, and `runc` is the same `runc` on either path The one-line answer is: the image is a standard artefact, dockershim was a translator for one engine's API, and deleting the translator does not invalidate the artefact. ## What genuinely changed, on the node The disruption was operational, and it was real: 1. **A runtime migration.** Every node had to be provisioned with, or switched to, containerd or CRI-O, with the node agent pointed at that runtime's socket via `--container-runtime-endpoint`. 2. **`docker ps` stops being the node debugging tool.** On a containerd node there is no dockerd holding those containers. Even where Docker Engine is still installed for other reasons, its containers live in containerd's `moby` namespace while the cluster's live in `k8s.io`, so neither client lists the other's. Node debugging moves to `crictl`. 3. **Nothing can bind-mount `/var/run/docker.sock` any more.** Workloads that built images in-cluster, or agents that inspected containers through the Docker Engine API, lost the socket they mounted. Those builds move to a builder that does not need the engine, or out of the cluster entirely. 4. **Log and metric assumptions.** Tooling that read Docker's `json-file` log layout on the node, or scraped Docker's own stats endpoint, has to read what the CRI runtime and node agent produce instead. 5. **If you genuinely need Docker Engine as the runtime**, `cri-dockerd` is the out-of-tree adapter that puts the shim's logic back in front of it as a separate daemon. ## How to answer it Lead with 'no, the images are fine', give the reason in one clause - the image format is a standard the other runtimes implement - then show you know where the pain actually was: a node-by-node runtime migration, `docker ps` giving way to `crictl`, and every workload or agent that assumed a Docker socket on the node. A candidate who says 'we had to rebuild our images' or 'Dockerfiles are dead' has swallowed the headline instead of reading it.

  • If the images are unaffected, why was the removal disruptive at all?
    Because the disruption was on the node, not in the image. Every node needed a runtime migration to containerd or CRI-O; `docker ps` stopped showing the cluster's containers; workloads that bind-mounted `/var/run/docker.sock` for in-cluster builds lost their socket; and node agents that shelled out to `docker` or parsed Docker's json-file log layout had to be rewritten against CRI-native equivalents.
  • Does this mean Docker Engine cannot be installed on a Kubernetes node any more?
    No. You can install Docker Engine on a node for builds or legacy tooling; the node agent simply will not drive it unless cri-dockerd sits in front. The two coexist without seeing each other: Docker Engine's containers live in containerd's `moby` namespace, while the cluster's live in `k8s.io`, so neither `docker ps` nor `crictl ps` lists the other's containers.
  • Which services does the CRI contract define, and why does that matter here?
    Two gRPC services: RuntimeService, which covers pod sandbox and container lifecycle plus exec, attach and status, and ImageService, which covers pulling, listing, inspecting and removing images. It matters because dockershim's whole job was implementing those two services on top of Docker Engine's own API - and containerd and CRI-O implement them natively, so the adapter had nothing left to add.

Dockershim was a translator hired so one guest could speak to the host in his own language. Firing the translator does not change the letters everyone had already written - it just means the host now talks directly to guests who speak the standard tongue.

saying these in an interview costs you the question

  • Says Docker-built images must be rebuilt for containerd
  • Claims Dockerfiles are no longer supported by Kubernetes
  • Thinks Kubernetes uninstalled Docker Engine from nodes
  • Believes containerd and CRI-O use a different image format
  • Assumes `docker ps` still lists pod containers on a containerd node
  • Says the removal happened in 1.20 rather than the deprecation

context