Previous tutorial: Kubernetes Architecture →
The main question of this tutorial:
In older Kubernetes tutorials, we often see:
Kubernetes + Docker
But in modern Kubernetes tutorials, we more often see:
Kubernetes + containerd
So the questions are:
- Has Docker been removed from Kubernetes?
- Do Docker images no longer run on Kubernetes?
Answer:
What changed is mainly the container runtime architecture.
1. In the beginning, Kubernetes used Docker
Docker became very popular because it made using containers much easier.
Example commands:
docker run nginx
docker ps
docker logs <container-id>
Docker was developer-friendly.
So when Kubernetes started, it orchestrated Docker containers.
Concept:
Kubernetes
↓
Docker
↓
Containers
In other words:
2. The problem: Kubernetes didn’t want to support only Docker
Later, more container runtimes started to appear.
For example:
- rkt / Rocket
- containerd
- CRI-O
Then the problem became:
Like this:
Kubernetes
├── Docker integration
├── containerd integration
├── CRI-O integration
└── rkt integration
That is hard to maintain.
So Kubernetes introduced a standard interface.
Its name:
3. What is the CRI?
CRI = Container Runtime Interface
It is the standard communication interface between Kubernetes and a container runtime.
Simple definition:
Concept:
Kubernetes
↓
CRI
↓
Container Runtime
The runtime can be:
- containerd
- CRI-O
- other compatible runtimes
Because of this, Kubernetes doesn’t have to worry so much about runtime-specific implementations.
If a runtime is CRI-compatible, Kubernetes can communicate with it.
4. Why is the CRI useful?
Imagine Kubernetes talked to every runtime directly, in a different way for each.
Then the architecture would be:
Kubernetes
/ | \
↓ ↓ ↓
Docker CRI-O containerd
And every integration would have to be maintained separately.
After the CRI:
Kubernetes
↓
CRI
┌──────┼──────┐
↓ ↓ ↓
containerd CRI-O Others
In other words:
5. What is OCI?
Another important term: OCI
OCI stands for:
OCI defines industry standards for containers.
The tutorial covers two important OCI specifications:
OCI Image Specification
Defines: what format a container image has.
OCI Runtime Specification
Defines: how a container runtime runs a container.
Simple idea:
This standardization is very important.
Because:
An image built with Docker can also be run with containerd.
6. Why does OCI matter so much?
Say you build an image with Docker:
docker build -t myapp .
Result:
Docker-built Image
Now, the Kubernetes node doesn’t have Docker Engine.
What it has is:
containerd
It can still run the image.
Because:
Docker Image
↓
OCI Image Standard
↓
containerd understands it
That is the key point.
7. What is Docker, really?
Many beginners think:
But Docker is not just a runtime.
Docker is a full container platform.
It includes many components and features:
- Docker CLI
- Docker API
- Image build tools
- Networking
- Volumes
- Security features
- containerd
- runc
Conceptually:
Docker Platform
│
├── Docker CLI
├── Docker API
├── Build Tools
├── Networking
├── Volumes
├── containerd
└── runc
So:
8. What is containerd?
containerd is a lower-level container runtime component.
It was originally part of the Docker ecosystem, and later evolved into an independent project.
Simple definition:
Concept:
Docker
↓
containerd
↓
runc
↓
Container
Modern Kubernetes can communicate with containerd directly, through the CRI.
Kubernetes
↓
CRI
↓
containerd
So a Kubernetes node doesn’t need the full Docker platform just to run containers.
9. What is runc?
The tutorial’s Docker architecture also includes runc.
Simplified hierarchy:
Docker
↓
containerd
↓
runc
↓
Linux Container
runc is an even lower-level OCI runtime.
As a beginner, this mental model is enough:
Docker = high level
containerd = runtime manager
runc = very low-level container execution
10. The relationship between Docker and containerd
This is very important.
Docker and containerd are not completely unrelated competitors.
Actually:
Concept:
Docker CLI
↓
Docker Engine
↓
containerd
↓
runc
↓
Container
In other words, containerd is an important part of the runtime pieces underneath the Docker platform.
11. So how did Kubernetes use Docker before?
This is where dockershim comes in.
Docker was created before Kubernetes had the CRI.
So Docker Engine didn’t fit Kubernetes’s CRI model directly.
Kubernetes therefore built a compatibility layer: dockershim
Simple definition:
Architecture:
Kubernetes
↓
dockershim
↓
Docker
↓
containerd
↓
runc
It worked.
But it added an extra layer to the architecture.
12. Why was dockershim needed?
Kubernetes wanted:
Kubernetes
↓
CRI
↓
Runtime
But Docker didn’t follow that CRI structure directly at the time.
So:
Kubernetes
↓
dockershim
↓
Docker
dockershim acted as a translation/compatibility bridge.
13. Why did Kubernetes remove Docker support?
dockershim was removed in Kubernetes version 1.24.
Meaning:
But once again:
Docker images still work.
Important distinction:
Docker Runtime Integration ❌
Docker Images ✅
14. What did the architecture look like before?
Before:
Kubernetes
↓
dockershim
↓
Docker Engine
↓
containerd
↓
runc
↓
Container
Lots of layers.
15. Modern Architecture
Now:
Kubernetes
↓
CRI
↓
containerd
↓
runc
↓
Container
In other words, the unnecessary middle layer has been removed.
Very simple:
BEFORE
Kubernetes
↓
dockershim
↓
Docker
↓
containerd
NOW
Kubernetes
↓
CRI
↓
containerd
This is one of the main concepts of the whole tutorial.
16. Docker vs containerd
| Feature | Docker | containerd |
|---|---|---|
| Type | Full container platform | Container runtime |
| User-friendly CLI | Yes | Limited / lower-level |
| Build images | Yes | Not its main focus |
| Run containers | Yes | Yes |
| Networking tools | Yes | Runtime-focused |
| Volume support | Yes | Lower-level |
| Developer friendly | Very | Comparatively low-level |
| Kubernetes runtime | Not Docker Engine directly | Commonly used |
| Best for | Development/local workflows | Kubernetes runtime |
Simple summary:
And:
17. Car Analogy
An easy analogy:
Docker
The whole car:
- Dashboard
- Steering
- Air Conditioning
- Seats
- Controls
- Engine
containerd
The car’s engine / core running mechanism
In other words:
Docker = Full Car
containerd = Engine
It isn’t an exact technical mapping, but it helps with the concept.
18. Do Docker images still work on Kubernetes?
Yes.
This is one of the most important points of the tutorial.
You can build an image locally with Docker:
docker build -t myapp .
Then push it to a registry.
Example:
Docker
↓
Build Image
↓
Container Registry
↓
Kubernetes
↓
containerd
↓
Run Image
Because the image is OCI-compatible.
19. Practical Workflow
Developer machine:
Code
↓
Dockerfile
↓
docker build
↓
Image
Then:
Image
↓
Registry
Kubernetes cluster:
Registry
↓
containerd pulls image
↓
Pod starts
↓
Container runs
So even though Docker is no longer directly connected to Kubernetes as its runtime:
20. Now let’s understand the CLI tools
The tutorial introduced three command-line tools:
- ctr
- nerdctl
- crictl
These are easy to confuse.
So let’s look at them one at a time.
21. What is ctr?
ctr comes with containerd.
It is a: low-level containerd CLI
It is mainly used for:
- Testing
- Debugging
- Low-level containerd interaction
Example:
ctr images pull docker.io/library/redis:latest
ctr run docker.io/library/redis:latest redis
Simple definition:
It isn’t very user-friendly for a normal, everyday developer workflow.
22. What is nerdctl?
nerdctl is a: Docker-like CLI for containerd
If you know Docker, nerdctl commands will feel familiar.
Example:
nerdctl run nginx
nerdctl ps
nerdctl logs <container-id>
See how it mirrors Docker:
docker run → nerdctl run
docker ps → nerdctl ps
Simple definition:
23. Why is nerdctl useful?
Say your machine doesn’t have Docker Engine.
But it does have:
containerd
And you want a Docker-style experience.
Then you can use nerdctl.
Concept:
You
↓
nerdctl
↓
containerd
↓
Container
24. What is crictl?
Now a very important debugging tool for Kubernetes: crictl
crictl is a CLI from the Kubernetes community ecosystem.
It communicates with CRI-compatible runtimes.
Example runtimes:
- containerd
- CRI-O
- Other CRI-compatible runtimes
Simple definition:
25. crictl Commands
Examples:
crictl ps
Shows running containers.
crictl images
Shows images.
crictl logs <container-id>
Shows logs.
crictl pods
Shows Pods / runtime-level pod sandboxes.
crictl exec -it <container-id> sh
Runs a command inside a container.
26. When should I use crictl?
Say a Kubernetes Pod isn’t starting properly.
Your initial investigation with kubectl isn’t giving you useful information.
Then you may need to go to the node and debug at the runtime level.
Example:
Kubernetes Pod Problem
↓
kubectl inspect
↓
Need deeper runtime debugging
↓
SSH / access Node
↓
crictl
At that point, these can be useful:
crictl ps -a
crictl logs <container-id>
crictl images
27. Should you create production containers manually with crictl?
Mainly: No.
crictl primarily debugging tool.
Because managing Kubernetes workloads is the responsibility of the Kubelet.
If you create a container manually, outside Kubernetes:
You
↓
crictl/manual runtime action
↓
Container
that container isn’t part of Kubernetes’s desired state.
So Kubernetes doesn’t treat that manually created container as a normal managed application.
The main principle in a Kubernetes environment:
For example:
- Deployment
- Pod
- StatefulSet
- DaemonSet
28. kubectl vs crictl
This is a very important difference.
kubectl
kubectl
↓
Kubernetes API
↓
Kubernetes Objects
Use it to:
- Pods manage
- Deployments manage
- Services manage
- Nodes inspect
- Cluster state inspect
crictl
crictl
↓
CRI
↓
Container Runtime
Use it for: node/runtime-level troubleshooting.
29. ctr vs nerdctl vs crictl
| Tool | Main Purpose | Talks To | Typical User |
|---|---|---|---|
| ctr | Low-level debugging | containerd | Runtime/admin |
| nerdctl | Docker-like container management | containerd | Developer/admin |
| crictl | Kubernetes runtime debugging | CRI runtime | Kubernetes admin |
| kubectl | Kubernetes management | API Server | Kubernetes user/admin |
30. Easy Memory Trick
Remember these four lines:
kubectl → Kubernetes manage
crictl → Kubernetes runtime debug
nerdctl → Docker-like containerd CLI
ctr → Low-level containerd CLI
31. Docker Commands vs crictl Commands
Many of the commands look similar.
| Docker | crictl | Purpose |
|---|---|---|
| docker ps | crictl ps | Running containers |
| docker images | crictl images | Images |
| docker logs | crictl logs | Logs |
| docker exec | crictl exec | Command inside a container |
| docker inspect | crictl inspect | Container details |
| docker version | crictl version | Version |
But their purpose is different.
Docker: General-purpose container workflow
crictl: Kubernetes runtime troubleshooting
32. Which tool for which situation?
To build an image locally
Use: Docker
docker build -t myapp .
For Docker-like commands with containerd
Use: nerdctl
To debug containerd at a low level
Use: ctr
To troubleshoot a Kubernetes node’s runtime
Use: crictl
To manage Kubernetes applications
Use: kubectl
33. Full Architecture
Now let’s connect everything together.
Developer side:
Developer
↓
Docker
↓
Build Image
↓
OCI Image
↓
Registry
Kubernetes side:
Kubernetes
↓
Kubelet
↓
CRI
↓
containerd
↓
runc
↓
Container
This flow is very important.
34. Kubernetes Runtime Architecture
In more detail:
Kubernetes Control Plane
│
▼
Kubelet
│
▼
CRI
│
▼
containerd
│
▼
runc
│
▼
Container
Here:
- Kubernetes
- says what needs to run.
- Kubelet
- Node-level agent.
- CRI
- Communication interface.
- containerd
- Manages the container lifecycle.
- runc
- Does the low-level container execution.
35. Docker Architecture vs Kubernetes Architecture
Docker
Developer
↓
Docker CLI
↓
Docker Engine
↓
containerd
↓
runc
↓
Container
Kubernetes
Kubernetes
↓
Kubelet
↓
CRI
↓
containerd
↓
runc
↓
Container
Notice that both can share the same components at the bottom:
containerd
↓
runc
That is why Docker and the Kubernetes/containerd ecosystem have historically been so closely related.
36. Most Important Difference
Remember this:
And:
Docker:
Build
Run
Network
Volumes
CLI
Developer UX
containerd:
Pull images
Manage containers
Run containers
Runtime lifecycle
37. Very Important Misunderstanding
Many people say:
That is the wrong mental model.
Correct:
Docker Engine as Kubernetes runtime
→ No longer directly used through built-in dockershim
But:
Docker-built OCI Image
→ Works ✅
Because:
38. Image vs Runtime
Keep this clear too.
Image
An application’s packaged artifact.
Example:
myapp:1.0
Runtime
Runs containers from images.
Example:
containerd
Flow:
Image
↓
Runtime
↓
Running Container
So having a Docker image doesn’t mean you need Docker Engine.
39. CRI vs OCI
These two are easy to confuse.
CRI: Container Runtime Interface
Question:
Answer: CRI
Concept:
Kubernetes
↓
CRI
↓
Runtime
OCI: Open Container Initiative
Question:
Answer: OCI
Concept:
OCI
├── Image Specification
└── Runtime Specification
40. CRI vs OCI Easy Memory
Remember:
Kubernetes
↓
CRI
↓
containerd
And:
Docker Image
↓
OCI Standard
↓
Different compatible runtimes
41. Everything through the car analogy
Imagine:
Docker
The whole car.
- Dashboard
- Steering
- Seats
- Controls
- Engine
containerd
Engine/core runtime.
ctr
The mechanic’s low-level diagnostic tool.
nerdctl
A Docker-like steering/control interface for containerd.
crictl
The Kubernetes mechanic’s runtime diagnostic tool.
kubectl
The remote/control panel for controlling the whole Kubernetes system.
42. Tool Mental Model
Docker = Full container platform
containerd = Container runtime
ctr = Low-level containerd debugging
nerdctl = Docker-like containerd CLI
crictl = Kubernetes runtime debugging
kubectl = Kubernetes management
43. The 7 most important points
1. Docker is a full platform
Docker
=
CLI + Build + Network + Volumes + Runtime Components
2. containerd is a runtime
containerd
↓
Runs/manages containers
3. Kubernetes uses the CRI
Kubernetes
↓
CRI
↓
containerd
4. OCI provides standardization
OCI
↓
Image + Runtime Standards
5. dockershim was a bridge
Kubernetes
↓
dockershim
↓
Docker
6. dockershim has been removed
Modern path:
Kubernetes
↓
CRI
↓
containerd
7. Docker images still work
Docker Build
↓
OCI Image
↓
containerd
↓
Kubernetes Container
44. Final Architecture Diagram
DEVELOPMENT
│
▼
Docker CLI
│
▼
Docker Build
│
▼
OCI Image
│
▼
Container Registry
│
▼
─────────────────────
KUBERNETES
│
▼
Kubelet
│
▼
CRI
│
▼
containerd
│
▼
runc
│
▼
Container
45. Final Simplified Explanation
The whole tutorial, simply put:
Kubernetes used to use Docker:
Kubernetes
↓
Docker
But Kubernetes wanted to support different container runtimes.
So the CRI (Container Runtime Interface) was created.
Because Docker didn’t fit the CRI architecture directly, Kubernetes used dockershim.
The architecture was:
Kubernetes
↓
dockershim
↓
Docker
↓
containerd
Later, Kubernetes removed dockershim.
Modern architecture:
Kubernetes
↓
CRI
↓
containerd
↓
runc
↓
Container
But Docker images still work.
Because:
So you can build an image with Docker:
docker build -t myapp .
and Kubernetes can run that image with containerd.
One-Line Summary
The most useful memory flow:
Docker
↓
Build OCI Image
↓
Registry
↓
Kubernetes
↓
Kubelet
↓
CRI
↓
containerd
↓
runc
↓
Container
And the tools:
kubectl → Kubernetes manage
crictl → Kubernetes runtime debug
nerdctl → Docker-like containerd CLI
ctr → Low-level containerd debug
