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
| Removed | NOT Removed |
|---|---|
| dockershim (K8s component) | Docker itself |
| Ability to use dockerd as K8s runtime | Docker CLI on your laptop |
| Docker for building images | |
| Docker Compose | |
| containerd (Docker’s core) |
Timeline
| Date | Event |
|---|---|
| Dec 2020 | Kubernetes 1.20 - Dockershim deprecation announced |
| Apr 2022 | Kubernetes 1.24 - Dockershim removed |
| Today | Docker 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 buildstill worksdocker-composestill 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
- Kubernetes removed dockershim (translation layer), not Docker itself
- Docker Desktop unchanged - Still perfect for local development
- Images remain compatible - OCI standard ensures portability
- Production uses containerd - Simpler, more direct
- No workflow changes - Build with Docker, deploy to K8s as before
- This was a Kubernetes change - Docker the product is unchanged
- Happened in K8s 1.24 (April 2022) - Clusters already migrated
Comments