Overlay networks & the routing mesh
Cross-node networking and load balancing.
Services on different nodes talk over an overlay network — a software-defined network spanning the whole swarm via VXLAN encapsulation, so a container on node-1 reaches one on node-2 as if they shared a LAN. You create an overlay on a manager and attach services to it; the swarm extends it to every node that runs a task on it. Add --attachable if you also want standalone containers to join it for debugging.
$ docker network create -d overlay --attachable appnet$ docker service create --name api --network appnet registry.internal/api:1.0$ docker service create --name web --network appnet -p 80:80 registry.internal/web:1.0# web reaches api by name across nodes: http://api:8080
The routing mesh
When you publish a service port in the default (ingress) mode, the swarm sets up the routing mesh: that port is open on every node, and a request to it on any node — even one running no task for that service — is forwarded to a healthy task somewhere in the swarm. So you can point a plain external load balancer at all node IPs and never track which node hosts which replica.
Scenario: bypass the mesh for source IP
A service needs the client’s real source IP (for rate-limiting or logging), but the routing mesh NATs it away. Publish in host mode instead: the port binds directly on the node running the task, preserving the source IP — at the cost of the mesh’s any-node convenience, so you front it with a load balancer that targets only the nodes actually running the task.
# ingress (default): any node answers, source IP is NATed$ docker service create --name web --publish published=80,target=80 web:1.0# host mode: binds on the task’s node only, real client IP preserved$ docker service create --name web --publish mode=host,published=80,target=80 web:1.0
Internal load balancing and DNS modes
Inside the swarm each service gets a stable virtual IP (VIP); resolving the service name returns the VIP, and the swarm load-balances connections across the healthy tasks behind it — callers use one name and never track task IPs. If you need clients to see the individual task IPs instead (some stateful protocols, custom load balancing), switch the endpoint mode to dnsrr and DNS returns each task address directly.
$ docker service create --name api --endpoint-mode vip --network appnet api:1.0 # default: one VIP, LB behind it$ docker service create --name db --endpoint-mode dnsrr --network appnet db:1.0 # DNS returns each task IP