How do Docker and Kubernetes differ, and when do you need Kubernetes?
Docker builds images and runs containers on one host. Kubernetes runs them across many nodes, schedules Pods, keeps replica counts and exposes Services.
Beginner5 min read
DOCKER one host docker build docker run Dockerfile ────────────image app:1 ────────────container ● (layers) Up ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ KUBERNETES Deployment app: replicas 3 image app:1 READY 3/3 ┌─ node 1 ────────┐ ┌─ node 2 ────────┐ ┌─ node 3 ────────┐ │ Ready ● │ │ Ready ● │ │ Ready ● │ │ [pod a] │ │ [pod b] │ │ [pod c] │ │ │ │ │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ································································ desired: 3 Pods the controller compares actual and fixes it
On this page
The short answer: Docker builds images and runs containers on a machine with a Docker daemon. Kubernetes manages containers across many machines at once: it decides where each one runs, keeps the number you asked for, and replaces the ones that disappear.
So they don't really compete. Images built with Docker work with every container runtime Kubernetes supports. The better question is whether your system needs Kubernetes yet.
DOCKER one host docker build docker run Dockerfile ────────────image app:1 ────────────container ● (layers) Up ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ KUBERNETES Deployment app: replicas 3 image app:1 READY 3/3 ┌─ node 1 ────────┐ ┌─ node 2 ────────┐ ┌─ node 3 ────────┐ │ Ready ● │ │ Ready ● │ │ Ready ● │ │ [pod a] │ │ [pod b] │ │ [pod c] │ │ │ │ │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ································································ desired: 3 Pods the controller compares actual and fixes it
What does Docker do?
Docker is a platform to package and run an application in a container. It uses a client-server design: the docker command sends requests over a REST API to the Docker daemon (dockerd), which does the work of building, running, and distributing containers. On Linux, Docker uses kernel namespaces to provide the isolated workspace called the container.
Day to day, it comes down to a few commands:
docker build -t app:1 . # Dockerfile -> image
docker run -d -p 8080:80 app:1 # image -> container
docker push registry.example.com/app:1
What is the difference between an image and a container?
An image is a read-only template with instructions for creating a container. Each instruction in a Dockerfile creates a layer, and when you change the Dockerfile and rebuild, only the layers that changed are rebuilt.
A container is a runnable instance of an image. On docker run, Docker adds a read-write filesystem as the final layer. When the container is removed, any changes to its state that aren't stored in persistent storage disappear. Anything you need to keep belongs in a volume.
The image format isn't Docker's alone. The Open Container Initiative's image-spec defines an image as a manifest, an optional image index, a set of filesystem layers and a configuration, so that different tools can build, move and run the same image.
What does Kubernetes add on top?
Kubernetes is a platform for managing containerized workloads and services on a cluster made of a control plane and one or more worker nodes. You don't tell it to run one container at a time. You describe the state you want and let it make that true. Its docs describe it as a set of independent control processes that continuously drive the current state towards the provided desired state.
Five pieces do most of that work.
Pod
A Pod is the smallest deployable unit in Kubernetes: one or more containers sharing storage and network. One container per Pod is the most common case, and you usually don't create Pods directly; a workload resource such as a Deployment creates them.
Deployment
A Deployment says what the Pods should look like and how many there should be. Its controller changes the actual state to the desired state at a controlled rate:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
replicas: 3
selector:
matchLabels: { app: app }
template:
metadata:
labels: { app: app }
spec:
containers:
- name: app
image: registry.example.com/app:1
ports:
- containerPort: 80
Change the image tag and the Deployment does a rolling update, by default with 25% max unavailable and 25% max surge. If the new version misbehaves, you can roll back to an earlier revision.
Service
Pods come and go, and their IP addresses go with them. A Service exposes a group of Pods over the network through a selector and gets its own cluster IP. The Service's controller continuously scans for Pods that match its selector and updates the endpoint list, so callers never need to know which Pods exist right now.
Scheduler
kube-scheduler places each Pod that has no node yet in two steps: filtering, then scoring. Filtering drops nodes that can't meet the Pod's resource requests; scoring ranks the rest and the highest score wins. If no node passes, the Pod remains unscheduled until one can take it.
Self-healing
Kubernetes restarts containers that fail, replaces containers, kills containers that don't respond to your user-defined health check, and doesn't send them traffic until they are ready. If a whole node fails, a controller creates a replacement Pod and the scheduler places it onto a healthy node.
It also helps to know what Kubernetes leaves out. It does not deploy source code and does not build your application, and it ships no database, message bus or logging stack. You still choose and run those yourself.
Does Kubernetes still use Docker?
It runs images that Docker builds, but it no longer talks to Docker Engine directly. Kubernetes talks to runtimes through the Container Runtime Interface (CRI), and Docker Engine doesn't implement CRI. The project kept a temporary bridge called dockershim, which was removed in Kubernetes v1.24.
In practice that means three things:
- Images produced by
docker buildwork with all CRI implementations. OCI maintains the shared specs for packaging images and running containers. - CRI runtimes such as containerd and CRI-O use runc as their default low-level runtime.
- On your own machine, nothing changes: you can keep building and testing with Docker. If a node really must use Docker Engine, there is an adapter called
cri-dockerd.
When is one host with Docker Compose enough?
In my view, when the system fits on one machine and you can accept that it stops if that machine stops, until you bring it back.
Docker Compose describes services, networks, volumes, configs and secrets in a single compose.yaml file, and docker compose up starts the services and creates the networks and volumes they need. For restarts, Docker has restart policies such as on-failure, always and unless-stopped (Start containers automatically), which Compose sets with restart: (Compose services reference):
services:
web:
image: registry.example.com/app:1
ports: ["8080:80"]
restart: unless-stopped
depends_on: [worker]
worker:
image: registry.example.com/worker:1
restart: unless-stopped
The limit is that the Docker daemon on that host applies those policies. If the host is gone, nothing moves the containers somewhere else. That is the point where Kubernetes starts to earn its extra complexity.
A quick check:
| Question | If the answer is yes |
|---|---|
| Must the system keep running when one machine fails? | You need several nodes and something that moves workloads |
| Do you need zero-downtime releases with a one-command rollback? | Deployments give you rolling updates and rollback |
| Do several services need to scale with load? | Kubernetes does horizontal scaling |
| Is there someone who can run a cluster? | If not, the upkeep may cost more than it saves |
If every answer is no, Compose on one host plus good backups is usually enough.
Where should a beginner start?
Start with Docker, because images and containers are what Kubernetes runs. The order I'd suggest:
- Get comfortable writing a Dockerfile, building an image and running a container.
- Run a multi-service app on your own machine with Docker Compose.
- Try Kubernetes locally; Docker Desktop includes Kubernetes. Write a Deployment and a Service for the same app, then delete a Pod and watch the controller create a new one.
Step 3 is where the difference shows most clearly. Docker does what you type. Kubernetes compares what is running with what you wrote down, and fixes the gap itself.
Sources
- Docker Docs: What is Docker?
- Docker Docs: How Compose works
- Docker Docs: Compose file reference, services
- Docker Docs: Start containers automatically
- OCI Image Format Specification
- Kubernetes: Overview
- Kubernetes: Components
- Kubernetes: Pods
- Kubernetes: Deployments
- Kubernetes: Service
- Kubernetes: Kubernetes Scheduler
- Kubernetes Blog (17 February 2022): Updated: Dockershim Removal FAQ
Keep reading
Related posts
Building software
RPC vs REST: what's the difference, and which should you use?
RPC calls a named procedure on a server; REST sends requests to resources through HTTP's uniform interface. A side-by-side comparison with gRPC and JSON-RPC examples, from Fielding, RFC 9110 and the specs.
Beginner10 min read
- API
- RPC
- REST
- gRPC
- JSON-RPC
- HTTP
Building software
WebSocket vs SSE vs polling: how each works and when to use it
Polling sends a new request each round, SSE holds one response open for server events, WebSocket upgrades to two-way frames. Reconnects, proxies and firewalls.
Intermediate9 min read
- WebSocket
- Server-Sent Events
- SSE
- Long Polling
- HTTP
- Reverse Proxy
- nginx
Building software
How do OAuth 2.0 and OpenID Connect differ?
OAuth 2.0 gets an app an access token to call an API; OpenID Connect adds an ID token that says who signed in. The code flow with PKCE, request by request.
Intermediate7 min read
- OAuth 2.0
- OpenID Connect
- PKCE
- Authentication
- Authorization
- Tokens