Docker Demystified - Part 6: Kubernetes and Docker — The Dockershim Story

The “Kubernetes Dropped Docker” Story

In 2020, Kubernetes announced they were removing “Docker support.” Panic ensued. Headlines declared Docker dead. It was mostly a misunderstanding. What actually happened is Kubernetes removed dockershim — a translation layer that let kubelet talk to Docker’s API.


The Old Architecture (Before Kubernetes 1.24)

kubelet → dockershim → dockerd → containerd → runc
             ↑
     Extra translation layer (maintenance burden)

Kubernetes had to maintain code that translated CRI (Container Runtime Interface) calls into Docker API calls. It was technical debt.

Why dockershim existed

In early Kubernetes (2014-2016):

  • Docker was the only container runtime
  • Kubernetes was built specifically on top of Docker
  • Direct integration made sense

By 2017-2020:

  • CRI interface was created for runtime pluggability
  • containerd and CRI-O emerged as CRI-native runtimes
  • Docker didn’t natively support CRI
  • Kubernetes had to maintain dockershim as a compatibility shim

The New Architecture (Kubernetes 1.24+)

kubelet → containerd → runc

Direct communication. No translation layer. Less code to maintain. AKS, EKS, and GKE all use containerd as the high-level runtime and runc as the low-level OCI runtime; Kubernetes “removed Docker” only by removing dockershim, not Docker images or workflows.


What Was NOT Removed

RemovedNOT Removed
dockershim (K8s component)Docker itself
Ability to use dockerd as K8s runtimeDocker CLI on your laptop
Docker for building images
Docker Compose
containerd (Docker’s core)

Timeline

DateEvent
Dec 2020Kubernetes 1.20 - Dockershim deprecation announced
Apr 2022Kubernetes 1.24 - Dockershim removed
TodayDocker still works for development, just not as K8s runtime

Why Your Images Still Work Everywhere

docker build -t myapp .
docker push registry.example.com/myapp

# This image runs on:
# - Kubernetes with containerd  ✅
# - Kubernetes with CRI-O       ✅
# - Docker Desktop              ✅
# - Podman                      ✅

# Because they all implement the OCI Image Specification

The image format is standardized. How you build it doesn’t matter. Where you run it doesn’t matter. OCI compliance guarantees interoperability.


What Changed for Users

For Developers (Local Development)

Nothing changed:

  • Docker Desktop still works
  • docker build still works
  • docker-compose still works
  • Local development workflow unchanged

For Kubernetes Operators

Minor changes:

  • Switch kubelet to use containerd directly
  • Update node configuration
  • No changes to workloads or images
  • Slightly simpler stack

For CI/CD Pipelines

Nothing changed:

  • Keep using Docker to build images
  • Push to any OCI registry
  • Deploy to Kubernetes as before

Why Kubernetes Made This Change

Maintenance Burden

Kubernetes had to maintain:
├── CRI interface (for all runtimes)
└── dockershim (just for Docker)
    ↑
    Duplicate effort, technical debt

Complexity

Docker's architecture:
kubelet → dockershim → dockerd → containerd → runc

containerd's architecture:
kubelet → containerd → runc

Removing dockershim:
- Fewer components
- Fewer failure points
- Faster pod startup

Industry Moved On

By 2020:

  • All major cloud providers used containerd
  • Docker itself used containerd internally
  • CRI-O was mature for OpenShift
  • Docker was the only runtime that needed special handling

Why Kubernetes Uses containerd (Not runc Directly)

Kubernetes needs:

  • A daemon
  • Lifecycle management
  • Image handling
  • Restart policies
  • Observability

runc cannot do any of that. It just creates containers and exits.

So Kubernetes uses:

kubelet → containerd → runc

Exactly the same pattern as Docker.


Why Docker Exists at All Then?

Docker adds:

  • Developer UX
  • Build system (Dockerfile)
  • Networking defaults
  • Volumes
  • Compose
  • Swarm

But at runtime, Docker and Kubernetes converge on the same stack. Both ultimately use containerd → runc to run containers. The difference is in the layers above.


Migration Guide

If you were using Docker as your Kubernetes runtime:

Option 1: Switch to containerd

# Install containerd
apt-get install containerd

# Configure kubelet
cat <<EOF > /etc/systemd/system/kubelet.service.d/0-containerd.conf
[Service]
Environment="KUBELET_EXTRA_ARGS=--container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock"
EOF

# Restart kubelet
systemctl daemon-reload
systemctl restart kubelet

Option 2: Switch to CRI-O (OpenShift)

# Install CRI-O
dnf install cri-o

# Start CRI-O
systemctl enable --now crio

# Configure kubelet
Environment="KUBELET_EXTRA_ARGS=--container-runtime=remote --container-runtime-endpoint=unix:///var/run/crio/crio.sock"

No changes needed for:

  • Your images
  • Your Dockerfiles
  • Your image registry
  • Your CI/CD pipelines
  • Your local development

The Real Impact

What Kubernetes Actually Removed

┌─────────────────────────────────────────┐
│           KUBERNETES                    │
│  ┌─────────────────────────────────┐    │
│  │      kubelet                    │    │
│  │  ┌──────────────────────────┐   │    │
│  │  │   dockershim (REMOVED)   │   │    │  ← This was removed
│  │  └──────────────────────────┘   │    │
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘

What Stayed

┌─────────────────────────────────────────┐
│      Your Development Machine           │
│  ┌─────────────────────────────────┐    │
│  │  Docker Desktop                 │    │  ← Still works perfectly
│  │  • docker CLI                   │    │
│  │  • docker build                 │    │
│  │  • docker-compose               │    │
│  │  • docker push                  │    │
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘

Common Misconceptions

Myth 1: “Docker is dead”

Reality: Docker is alive and well. Only dockershim in Kubernetes was removed.

Myth 2: “I can’t use Docker anymore”

Reality: Docker works perfectly for local development. Just not as a K8s runtime.

Myth 3: “My images won’t work”

Reality: OCI standard ensures images work everywhere.

Myth 4: “I need to rewrite my Dockerfiles”

Reality: Dockerfiles work identically. No changes needed.

Myth 5: “Docker Desktop stopped working”

Reality: Docker Desktop is unchanged. This only affected Kubernetes clusters.


Key Takeaways

  1. Kubernetes removed dockershim (translation layer), not Docker itself
  2. Docker Desktop unchanged - Still perfect for local development
  3. Images remain compatible - OCI standard ensures portability
  4. Production uses containerd - Simpler, more direct
  5. No workflow changes - Build with Docker, deploy to K8s as before
  6. This was a Kubernetes change - Docker the product is unchanged
  7. Happened in K8s 1.24 (April 2022) - Clusters already migrated

Comments