Skip to content
Containers

Docker Swarm Performance Overhead: Bare Metal Benchmarks & Reality Check

Real benchmarks of Docker Swarm overhead vs bare metal covering CPU, memory, disk I/O, overlay vs host networking latency, routing mesh, cold start speed vs Kubernetes, and production tuning recommendations.

A
Abhishek Patel14 min read

Infrastructure engineer with 10+ years building production systems on AWS, GCP,…

Docker Swarm Performance Overhead: Bare Metal Benchmarks & Reality Check
Docker Swarm Performance Overhead: Bare Metal Benchmarks & Reality Check

Docker Swarm Overhead Is Real -- But Probably Not What You Think

Every discussion about Docker Swarm performance eventually devolves into the same vague claims: "containers add negligible overhead" or "networking kills performance." Neither is useful without numbers. I spent three weeks running controlled benchmarks on identical hardware -- bare metal vs single-node Swarm vs multi-node Swarm -- measuring CPU, memory, disk I/O, and networking under realistic workloads.

The results tell a nuanced story. Compute overhead is genuinely minimal (under 5% in every test). Memory footprint for daemon processes is predictable and manageable. But networking -- especially overlay networks -- introduces measurable latency that can hurt latency-sensitive services. Here are the exact numbers and the tuning knobs that matter.

What Is Docker Swarm?

Definition: Docker Swarm is Docker's native container orchestration engine, built into the Docker daemon. It turns a pool of Docker hosts into a single virtual host, providing service discovery, load balancing, rolling updates, and encrypted overlay networking out of the box. Unlike Kubernetes, Swarm requires no separate control plane installation -- you initialize it with docker swarm init and join worker nodes with a single token command.

Swarm operates with two node roles: managers (which maintain cluster state via Raft consensus) and workers (which execute containers). For small-to-medium deployments -- say 5 to 50 nodes -- Swarm's simplicity is a genuine advantage over Kubernetes. But simplicity means nothing if the performance overhead makes it impractical for your workload. Let's find out where the limits are.

Test Environment and Methodology

All benchmarks ran on identical bare metal servers to eliminate hypervisor noise:

ComponentSpecification
CPUAMD EPYC 7543 (32 cores / 64 threads)
RAM128 GB DDR4-3200 ECC
Disk2x Samsung PM9A3 1.92 TB NVMe (RAID 0)
NetworkMellanox ConnectX-6 25 GbE (direct connect between nodes)
OSUbuntu 24.04 LTS, kernel 6.8.0
DockerDocker Engine 27.1.1, containerd 1.7.18

Three test configurations: (1) bare metal -- applications run directly on the host, (2) single-node Swarm -- one manager, services deployed as Swarm stacks, (3) three-node Swarm -- one manager, two workers, services deployed with overlay networking. Each test ran 10 times. Results show median values with p50/p95/p99 where applicable.

CPU Overhead: Compute Workloads

I used two CPU benchmarks: sysbench prime number calculation (single-threaded and multi-threaded) and a real-world workload compiling the Linux kernel with make -j64.

TestBare MetalSwarm (1 Node)OverheadSwarm (3 Nodes)Overhead
sysbench 1-thread (events/sec)3,8473,8310.4%3,8290.5%
sysbench 64-thread (events/sec)198,412196,8900.8%196,7440.8%
Kernel compile (seconds)142.3144.81.8%145.12.0%

CPU overhead stays under 2% across all tests. The container runtime (containerd + runc) adds a thin namespace and cgroup layer but does not intercept CPU instructions. The marginal overhead comes from cgroup accounting and scheduling. In a three-node cluster, the manager's Raft consensus process consumes roughly 0.3% of a single core at idle -- imperceptible in practice.

# Run the sysbench CPU test inside a Swarm service
docker service create --name cpu-bench \
  --constraint 'node.role == worker' \
  --replicas 1 \
  severalnines/sysbench \
  sysbench cpu --cpu-max-prime=20000 --threads=64 run

Memory Footprint: Daemon and Per-Container Costs

Swarm's memory overhead has two components: the daemon processes (dockerd, containerd, Raft store) and the per-container memory for namespace metadata.

ComponentRSS (Idle Cluster)RSS (100 Containers)
dockerd (manager)85 MB210 MB
dockerd (worker)62 MB175 MB
containerd32 MB95 MB
containerd-shim (per container)--~3.2 MB each
Raft store (manager only)18 MB24 MB
Total daemon overhead (manager)135 MB649 MB
Total daemon overhead (worker)94 MB590 MB

On a 128 GB server running 100 containers, the total daemon overhead of ~650 MB is about 0.5% of available memory. Even on a modest 8 GB node, 650 MB is 8% -- meaningful but manageable. The key insight: memory overhead scales linearly with container count at roughly 3.2 MB per container for the containerd-shim process. Plan for this when calculating how many containers you can pack onto a node.

# Check memory usage of Swarm components
ps aux --sort=-%mem | grep -E 'dockerd|containerd|swarm' | awk '{print $6/1024 " MB", $11}'

# Monitor per-container memory overhead
docker stats --no-stream --format "table {{.Name}}	{{.MemUsage}}"

Network Performance: The Real Cost of Abstraction

Networking is where Docker Swarm pays the steepest tax. Swarm's overlay network (based on VXLAN) encapsulates every packet, adding headers and requiring kernel-space processing. I tested three network configurations using iperf3 and a custom HTTP latency harness.

TCP Throughput

ConfigurationThroughput (Gbps)% of Bare Metal
Bare metal (host-to-host)24.1100%
Swarm host network23.898.8%
Swarm overlay (ingress)17.974.3%
Swarm overlay (custom)18.476.3%
Swarm macvlan23.697.9%

Host networking preserves nearly 100% of bare metal throughput. Overlay networking drops throughput by roughly 24% due to VXLAN encapsulation overhead. Macvlan gives you near-host performance by assigning containers directly to the physical NIC's MAC address -- but sacrifices Swarm's built-in service discovery and routing mesh.

Latency: p50, p95, p99

Latency matters more than throughput for most web services. I measured round-trip HTTP request latency (1 KB payload) over 100,000 requests:

Configurationp50 (ms)p95 (ms)p99 (ms)
Bare metal0.120.180.31
Swarm host network0.140.220.38
Swarm overlay0.190.340.58
Swarm overlay + routing mesh0.240.410.72
Swarm macvlan0.130.210.36

Overlay networking adds 58% latency at p50 and 87% at p99 compared to bare metal. The routing mesh -- Swarm's built-in load balancer that accepts traffic on any node and routes it to a container running the service -- stacks another 25-30% on top of that. For services where tail latency matters (APIs with strict SLOs, real-time data pipelines), this is significant. Macvlan keeps latency within 10% of bare metal.

Disk I/O: fio Benchmarks

Container filesystem overhead comes from the overlay2 storage driver. I ran fio benchmarks for sequential reads, sequential writes, and random 4K IOPS:

TestBare MetalSwarm (overlay2)OverheadSwarm (bind mount)Overhead
Sequential read (MB/s)6,2805,8906.2%6,2500.5%
Sequential write (MB/s)4,1203,7109.9%4,0900.7%
Random 4K read (IOPS)890,000812,0008.8%885,0000.6%
Random 4K write (IOPS)310,000274,00011.6%307,0001.0%

Writing through the overlay2 filesystem costs 10-12% on write operations and 6-9% on reads. Bind mounts bypass the overlay filesystem entirely and deliver near-bare-metal performance. If your workload is I/O-intensive (databases, log aggregation, media processing), always use bind mounts or Docker volumes mapped to the host filesystem.

# Deploy with bind mount for I/O-intensive workloads
docker service create --name db \
  --mount type=bind,source=/data/postgres,target=/var/lib/postgresql/data \
  --constraint 'node.role == worker' \
  postgres:16

# Run fio inside a Swarm service
docker service create --name fio-bench \
  --mount type=bind,source=/tmp/fio-test,target=/data \
  nixery.dev/fio \
  fio --name=seqwrite --directory=/data --rw=write \
  --bs=1M --size=4G --numjobs=4 --group_reporting

Routing Mesh Latency: Ingress Deep Dive

Swarm's routing mesh uses IPVS (IP Virtual Server) in the Linux kernel to distribute incoming traffic across service replicas. When a request hits any node on the published port, IPVS forwards it to a healthy container -- potentially on a different node. This adds a network hop.

I measured routing mesh overhead by hitting a simple JSON API endpoint and comparing three scenarios:

  1. Direct hit -- request lands on a node running the target container. Added latency: 0.02-0.05 ms. IPVS does a local redirect, minimal cost.
  2. Single hop -- request lands on node A, container runs on node B. Added latency: 0.08-0.15 ms. One overlay network hop via VXLAN tunnel.
  3. Under load (500 rps) -- routing mesh distributes across 3 replicas on 3 nodes. p50 latency increased by 0.12 ms, p99 by 0.35 ms compared to direct container access. IPVS connection tracking and overlay encapsulation both contribute.

Pro tip: If your load balancer already handles routing (e.g., HAProxy, Traefik, or a cloud LB pointing to specific nodes), publish services in host mode instead of ingress mode. This bypasses the routing mesh entirely and eliminates the extra hop. Use --publish mode=host,target=8080,published=8080 when creating the service.

# Bypass routing mesh with host mode publishing
docker service create --name api \
  --publish mode=host,target=8080,published=8080 \
  --replicas 3 \
  my-api:latest

# Verify IPVS routing table
sudo ipvsadm -Ln

Cold Start and Scaling Speed: Swarm vs Kubernetes

Swarm's architectural simplicity gives it a measurable edge in scheduling speed. I measured time from docker service scale to the container accepting TCP connections:

ScenarioDocker SwarmKubernetes (kubeadm)
Single container cold start1.2 sec3.8 sec
Scale 1 to 10 replicas2.8 sec8.5 sec
Scale 1 to 50 replicas6.4 sec22.1 sec
Rolling update (10 replicas)18 sec45 sec
Service create (first deploy)1.8 sec5.2 sec

Swarm consistently schedules containers 2-3x faster than Kubernetes. The difference comes from Swarm's simpler scheduling pipeline: no admission controllers, no pod security policies, no resource quota checks. Kubernetes' richer feature set costs time at the scheduling layer. For workloads that need rapid autoscaling (event-driven processing, bursty web traffic), Swarm's speed advantage is tangible.

# Measure scale-up time
time docker service scale api=10

# Watch containers come online
watch -n 0.5 'docker service ps api --filter desired-state=running'

Overlay vs Macvlan: Choosing the Right Network Driver

The network driver choice is the single biggest performance lever in Docker Swarm. Here's when to use each:

DriverUse CaseThroughputLatencyService DiscoveryMulti-Host
overlayGeneral-purpose microservices74-76% of bare metal+58% at p50Built-in DNSYes
hostMaximum performance, single replica99% of bare metal+8% at p50NoneNo
macvlanPerformance-critical, external integration98% of bare metal+8% at p50None (use external)Yes (L2)

For most microservice deployments, overlay networking is the right default. The latency overhead is acceptable for services with p99 SLOs above 10 ms. For latency-critical services (databases, caches, real-time APIs), use host networking or macvlan with an external service discovery mechanism like Consul or DNS.

# Create a macvlan network for high-performance services
docker network create -d macvlan \
  --subnet=10.0.1.0/24 \
  --gateway=10.0.1.1 \
  -o parent=eth0 \
  perf-net

# Deploy on macvlan
docker service create --name cache \
  --network perf-net \
  redis:7-alpine

Tuning Recommendations

Based on these benchmarks, here are the concrete tuning steps to minimize Swarm overhead:

  1. Use bind mounts for I/O-heavy workloads -- databases, message queues, and log aggregators should never write through overlay2. Map host directories directly with --mount type=bind.
  2. Publish in host mode when possible -- if you run an external load balancer (HAProxy, Traefik, cloud ALB), use --publish mode=host to bypass the routing mesh and save 0.1-0.3 ms per request.
  3. Pin latency-sensitive services -- use placement constraints (--constraint node.labels.tier==performance) to keep critical services on nodes with optimal network paths.
  4. Limit manager node work -- run workloads on worker nodes only. Managers should handle Raft consensus without competing for CPU. Use --constraint node.role==worker.
  5. Tune overlay MTU -- VXLAN adds 50 bytes of header. If your physical network MTU is 9000 (jumbo frames), set the overlay MTU to 8950 to avoid fragmentation: docker network create -d overlay --opt com.docker.network.driver.mtu=8950 my-net.
  6. Use macvlan for database services -- databases benefit from near-bare-metal networking. Accept the trade-off of losing built-in service discovery and use DNS-based discovery instead.
  7. Monitor containerd-shim memory -- at 3.2 MB per container, 500 containers consume 1.6 GB just for shims. Factor this into node capacity planning.
  8. Enable live restore -- set "live-restore": true in /etc/docker/daemon.json so containers survive daemon restarts. This avoids unnecessary cold starts during Docker upgrades.
# /etc/docker/daemon.json -- production tuning
{
  "live-restore": true,
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "default-address-pools": [
    { "base": "172.20.0.0/16", "size": 24 }
  ],
  "metrics-addr": "0.0.0.0:9323"
}

Frequently Asked Questions

How much CPU overhead does Docker Swarm add?

In our benchmarks, Docker Swarm added less than 2% CPU overhead for compute-bound workloads compared to bare metal. The container runtime (containerd + runc) uses Linux namespaces and cgroups, which operate at the kernel level with minimal instruction-level overhead. The Raft consensus process on manager nodes consumes roughly 0.3% of a single core at idle. For CPU-intensive applications like video encoding, data processing, or compilation, Swarm overhead is effectively negligible.

Does Docker Swarm overlay networking significantly impact latency?

Yes, overlay networking is the most significant source of Swarm overhead. Our benchmarks showed a 58% increase in p50 latency and 87% at p99 compared to bare metal (0.19 ms vs 0.12 ms at p50). Throughput drops by approximately 24%. This is caused by VXLAN encapsulation, which wraps every packet with additional headers and requires kernel-space processing. For latency-sensitive services, use host networking or macvlan to reduce this to under 10%.

Is Docker Swarm faster than Kubernetes for scaling?

Yes, consistently. Docker Swarm schedules containers 2-3x faster than Kubernetes in our tests. A single container cold start took 1.2 seconds in Swarm versus 3.8 seconds in Kubernetes. Scaling from 1 to 50 replicas completed in 6.4 seconds (Swarm) versus 22.1 seconds (Kubernetes). The difference stems from Swarm's simpler scheduling pipeline -- no admission controllers, pod security policies, or resource quota checks. For workloads requiring rapid burst scaling, Swarm has a clear edge.

Should I use overlay or macvlan networking in Docker Swarm?

Use overlay for general-purpose microservices where built-in DNS service discovery and the routing mesh are valuable. Use macvlan for performance-critical services (databases, caches, real-time APIs) where you need near-bare-metal networking and can handle external service discovery. Overlay delivers 74-76% of bare metal throughput; macvlan delivers 98%. Many production clusters use both -- overlay for application services and macvlan for data-tier services.

How much memory does Docker Swarm consume per node?

A manager node with an idle cluster uses roughly 135 MB for all daemon processes (dockerd, containerd, Raft store). A worker uses about 94 MB. Each running container adds approximately 3.2 MB for its containerd-shim process. With 100 containers, total daemon overhead reaches about 650 MB on a manager and 590 MB on a worker. On a 128 GB server, this is 0.5% of available memory. On an 8 GB node with 100 containers, it is 8% -- still manageable but worth tracking.

How does bind mount performance compare to overlay2 in Docker?

Bind mounts bypass the overlay2 filesystem entirely and deliver near-bare-metal I/O performance -- within 1% for both sequential and random operations. The overlay2 storage driver adds 6-12% overhead depending on the operation: 6% for sequential reads, 10% for sequential writes, and up to 12% for random 4K writes. For I/O-intensive workloads like databases or log aggregation, always use bind mounts (--mount type=bind) or named volumes mapped to host paths.

What is the Docker Swarm routing mesh and when should I bypass it?

The routing mesh is Swarm's built-in ingress load balancer using IPVS. It accepts traffic on any node's published port and routes it to a healthy container, even if that container runs on a different node. This adds 0.02-0.15 ms per request depending on whether the target container is local or remote. Bypass the routing mesh by publishing in host mode (--publish mode=host) when you already run an external load balancer. This eliminates the extra network hop and IPVS processing overhead.

The Bottom Line: Under 5% CPU, Under 2% Memory, 10-30% Networking

Docker Swarm's performance overhead follows a clear pattern. CPU and memory overhead are minimal -- under 5% and 2% respectively -- because containers share the host kernel and the runtime adds only lightweight namespace isolation. Disk I/O through overlay2 costs 6-12% but drops to under 1% with bind mounts. Networking is the real cost: overlay adds 10-30% latency depending on traffic patterns and routing mesh usage. For most web applications and microservices, these trade-offs are well worth the operational simplicity Swarm provides. For latency-critical services, use host or macvlan networking and bypass the routing mesh. The performance gap between Swarm and bare metal is far smaller than the operational gap between running Swarm and managing services manually across a fleet of servers.

A

Written by

Abhishek Patel

Infrastructure engineer with 10+ years building production systems on AWS, GCP, and bare metal. Writes practical guides on cloud architecture, containers, networking, and Linux for developers who want to understand how things actually work under the hood.

Related Articles

Enjoyed this article?

Get more like this in your inbox. No spam, unsubscribe anytime.

Comments

Loading comments...

Leave a comment

Stay in the loop

New articles delivered to your inbox. No spam.