Docker vs. Kubernetes: Container Basics
Understand the difference between container runtime engines and cluster orchestration platforms.
Introduction
Docker and Kubernetes are complementary technologies that solve different problems in the container ecosystem. Docker is a container runtime β it packages your application code, dependencies, and OS libraries into a portable image that runs identically anywhere. Kubernetes is a container orchestrator β it manages where, when, and how many copies of that container run across a cluster of machines.
Confusingly, developers often phrase the choice as βDocker vs. Kubernetes,β but a more accurate framing is βDocker alone vs. Docker managed by Kubernetes.β Nearly every Kubernetes cluster still uses the Docker image format (OCI spec) under the hood.
Step-by-Step: From Dockerfile to Running Cluster
flowchart TD
A["1. Write a Multi-Stage Dockerfile"]
B["2. Build and Push the Image"]
C["3. Define a Kubernetes Deployment"]
D["4. Expose with a Service"]
E["5. Scale with HPA"]
A --> B
B --> C
C --> D
D --> E
Step 1: Write a Multi-Stage Dockerfile
Multi-stage builds separate the build environment from the runtime image, keeping final images small:
# Stage 1: Build
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o api-server ./cmd/api
# Stage 2: Minimal runtime (25 MB vs 800 MB)
FROM gcr.io/distroless/static-debian12
COPY --from=builder /app/api-server /api-server
EXPOSE 8080
USER nonroot:nonroot
ENTRYPOINT ["/api-server"]
Step 2: Build and Push the Image
docker build -t registry.example.com/api-server:v1.2.0 .
docker push registry.example.com/api-server:v1.2.0
Step 3: Define a Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
namespace: production
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: api-server
template:
metadata:
labels:
app: api-server
spec:
containers:
- name: api-container
image: registry.example.com/api-server:v1.2.0
ports:
- containerPort: 8080
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "100m"
memory: "256Mi"
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
Step 4: Expose with a Service
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
selector:
app: api-server
ports:
- port: 80
targetPort: 8080
type: LoadBalancer
Step 5: Scale with HPA
kubectl autoscale deployment api-deployment --cpu-percent=70 --min=3 --max=10
Key Takeaways
- Docker packages apps into OCI-compliant images; multi-stage builds dramatically reduce final image size.
- Kubernetes manages desired state β you declare what you want (3 replicas) and K8s ensures reality matches.
- Rolling updates with
maxUnavailable: 0guarantee zero-downtime deployments. - Liveness and readiness probes let K8s automatically restart unhealthy containers.
- Use resource requests and limits to prevent noisy-neighbor CPU starvation in shared clusters.
Historical figures, architectures, and capabilities are for informational purposes only. Not technical, professional, legal, or financial advice. Sources: Research papers, developer documentation.