Container Orchestration: Docker Swarm vs Kubernetes
Compare Docker Swarm and Kubernetes for container orchestration. Learn the architecture, setup, scaling, and networking of both platforms with practical examples.
What you'll learn
- ✓What container orchestration solves and why you need it
- ✓Docker Swarm architecture, setup, and service management
- ✓Kubernetes architecture, core concepts, and deployment patterns
- ✓When to choose Swarm vs Kubernetes for your workloads
Prerequisites
- •Comfortable building and running Docker containers
- •Basic understanding of networking concepts
- •Command-line experience on Linux or macOS
Why Container Orchestration?
Running a single container on a single machine is simple. Running dozens of containers across multiple machines is not. Container orchestration solves the problems that appear at scale:
- Scheduling: Which machine should each container run on, based on available resources?
- Scaling: How do you add or remove container instances based on demand?
- Networking: How do containers find and communicate with each other across machines?
- Health management: What happens when a container crashes or a machine goes down?
- Rolling updates: How do you deploy new versions without downtime?
- Service discovery: How does one service locate another without hardcoded addresses?
Docker Swarm and Kubernetes are the two most prominent solutions. They approach these problems differently, with different trade-offs in complexity, capability, and operational overhead.
Docker Swarm
Docker Swarm is Docker’s native orchestration solution. It is built into the Docker Engine, which means you do not need to install anything extra if you already have Docker. Its design philosophy prioritizes simplicity.
Architecture
Swarm uses a manager-worker architecture:
- Manager nodes maintain the cluster state, schedule services, and serve the Swarm API. You should run an odd number (3 or 5) for high availability via Raft consensus.
- Worker nodes run the containers. They receive tasks from managers and report their status back.
Setting Up a Swarm Cluster
Initialize the Swarm on the first manager:
# On the manager node
docker swarm init --advertise-addr 192.168.1.10
This outputs a join token. Use it on worker nodes:
# On each worker node
docker swarm join --token SWMTKN-1-abc123... 192.168.1.10:2377
Add additional managers for high availability:
# Get the manager join token
docker swarm join-token manager
# On additional manager nodes
docker swarm join --token SWMTKN-1-xyz789... 192.168.1.10:2377
Verify the cluster:
docker node ls
# ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
# abc123 * manager-1 Ready Active Leader
# def456 manager-2 Ready Active Reachable
# ghi789 worker-1 Ready Active
# jkl012 worker-2 Ready Active
Deploying Services
Create a service in Swarm:
docker service create \
--name web \
--replicas 3 \
--publish 80:8080 \
--update-delay 10s \
--update-parallelism 1 \
--restart-condition on-failure \
myregistry/web-app:v1.0
Or use a Docker Compose file with docker stack deploy:
# docker-compose.yml
version: "3.8"
services:
web:
image: myregistry/web-app:v1.0
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
rollback_config:
parallelism: 1
delay: 5s
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
resources:
limits:
cpus: "0.5"
memory: 256M
reservations:
cpus: "0.1"
memory: 128M
ports:
- "80:8080"
networks:
- app-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 5s
retries: 3
redis:
image: redis:7-alpine
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
volumes:
- redis_data:/data
networks:
- app-network
networks:
app-network:
driver: overlay
volumes:
redis_data:
Deploy the stack:
docker stack deploy -c docker-compose.yml myapp
# Check services
docker stack services myapp
# Check tasks (individual containers)
docker service ps myapp_web
# Scale a service
docker service scale myapp_web=5
# Update the image
docker service update --image myregistry/web-app:v1.1 myapp_web
# Roll back if something goes wrong
docker service rollback myapp_web
Swarm Networking
Swarm creates an overlay network that spans all nodes. Services on the same overlay network can reach each other by service name:
# From inside a container on the app-network
curl http://redis:6379 # Service discovery by name
Swarm also includes a built-in load balancer called the routing mesh. Any node in the swarm can accept traffic for a published port, even if that node is not running a task for the service. The mesh routes the request to a node that is.
Swarm Secrets
Store sensitive data securely:
# Create a secret
echo "my-db-password" | docker secret create db_password -
# Use it in a service
docker service create \
--name api \
--secret db_password \
myregistry/api:v1.0
Inside the container, the secret is available at /run/secrets/db_password.
Kubernetes
Kubernetes (K8s) is the industry standard for container orchestration. It is more complex than Swarm but offers significantly more features, extensibility, and ecosystem support.
Architecture
Kubernetes has a control plane and worker nodes:
Control plane components:
- API Server: The front door for all operations, accepts REST requests.
- etcd: Distributed key-value store holding all cluster state.
- Scheduler: Assigns pods to nodes based on resource requirements and constraints.
- Controller Manager: Runs control loops that maintain desired state (e.g., ensuring the right number of replicas exist).
Worker node components:
- kubelet: Agent that runs on each node, manages pods.
- kube-proxy: Handles networking rules for service communication.
- Container runtime: Runs containers (containerd, CRI-O).
Setting Up a Local Cluster
For development, use kind (Kubernetes in Docker):
# Install kind
brew install kind # macOS
# or
curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64 && chmod +x ./kind && sudo mv ./kind /usr/local/bin/
# Create a multi-node cluster
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
- role: worker
EOF
# Verify
kubectl get nodes
Core Concepts
Pod: The smallest deployable unit. Usually contains one container but can hold multiple tightly coupled containers.
Deployment: Manages a set of identical pods with declarative updates.
Service: Provides a stable network endpoint for a set of pods.
Namespace: Logical isolation boundary within a cluster.
ConfigMap / Secret: Externalized configuration and sensitive data.
Deploying Applications
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: web
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: myregistry/web-app:v1.0
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
---
apiVersion: v1
kind: Service
metadata:
name: web
namespace: production
spec:
selector:
app: web
ports:
- port: 80
targetPort: 8080
type: ClusterIP
# Apply the manifests
kubectl apply -f deployment.yaml
# Watch the rollout
kubectl rollout status deployment/web -n production
# Scale
kubectl scale deployment/web --replicas=5 -n production
# Update the image
kubectl set image deployment/web web=myregistry/web-app:v1.1 -n production
# Roll back
kubectl rollout undo deployment/web -n production
Horizontal Pod Autoscaling
Kubernetes can automatically scale based on CPU, memory, or custom metrics:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
Swarm has no built-in autoscaling; you need external tools or scripts.
Kubernetes Networking with Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
namespace: production
annotations:
nginx.ingress.kubernetes.io/rate-limit: "100"
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
tls:
- hosts:
- app.example.com
secretName: app-tls
Head-to-Head Comparison
| Feature | Docker Swarm | Kubernetes |
|---|---|---|
| Setup complexity | Minutes | Hours (or use managed service) |
| Learning curve | Low | Steep |
| Scaling | Manual or scripted | Built-in HPA, VPA, cluster autoscaler |
| Networking | Overlay with routing mesh | CNI plugins, Ingress controllers |
| Storage | Volume drivers | CSI, PV/PVC, StorageClasses |
| Ecosystem | Limited | Massive (Helm, operators, service mesh) |
| Configuration | Docker Compose files | YAML manifests, Helm charts, Kustomize |
| RBAC | Basic | Fine-grained |
| Self-healing | Restarts failed containers | Restarts, reschedules, replaces |
| Community | Small, declining | Enormous, growing |
| Managed offerings | None | EKS, GKE, AKS, and many more |
When to Choose What
Choose Docker Swarm when:
- Your team is small and already comfortable with Docker Compose.
- You have a handful of services (under 20) running on a few nodes.
- You need to get something running quickly without a steep learning investment.
- You do not need advanced features like custom autoscaling, service mesh, or complex RBAC.
Choose Kubernetes when:
- You are running many services at scale across dozens or hundreds of nodes.
- You need autoscaling, advanced networking, or fine-grained access control.
- You want access to the vast Kubernetes ecosystem (Helm charts, operators, service mesh).
- You can use a managed Kubernetes service (EKS, GKE, AKS) to reduce operational burden.
- Your organization is investing in platform engineering.
For most teams starting today, managed Kubernetes is the practical choice. Services like GKE Autopilot or EKS with Fargate eliminate much of the operational complexity while giving you access to the full Kubernetes ecosystem. Swarm remains a valid choice for simple workloads where operational simplicity is the top priority.
Wrapping Up
Container orchestration is essential once you move beyond a single machine. Docker Swarm offers the shortest path from Docker Compose to a multi-node cluster, with familiar tooling and minimal configuration. Kubernetes provides a more powerful and extensible platform at the cost of increased complexity. The right choice depends on your team size, workload complexity, and how much of the Kubernetes ecosystem you need. Start with whichever gets you to production fastest, and migrate to Kubernetes when your needs outgrow Swarm’s capabilities.
Related articles
- DevOps Kubernetes Pods vs Deployments
How Pods, ReplicaSets, and Deployments relate, why you almost never create Pods directly, and how rolling updates and rollbacks actually happen.
- Docker Docker Compose vs Kubernetes: When to Use Which
A pragmatic comparison of Docker Compose and Kubernetes covering scope, operational cost, and the signals that tell you it is time to graduate.
- DevOps GitOps with ArgoCD: Deploy Kubernetes Apps Automatically
Learn GitOps principles and deploy Kubernetes applications with ArgoCD. Covers installation, app configuration, sync policies, multi-environment setups, and rollbacks.
- DevOps Zero-Downtime Deployments: Strategies and Patterns
Master zero-downtime deployment strategies including rolling updates, blue-green, canary, and feature flags. Learn practical patterns for Kubernetes and cloud platforms.