How to Run Docker Containers on a Weave Network: Multi-Host Networking and Service Discovery

How to Run Docker Containers on a Weave Network

Once I had Weave running across my AWS hosts, the next question I had to answer was a practical one: how do I actually run real, multi-service applications on top of it? Peering routers is only step one — the day-to-day work is attaching containers, discovering services by name, load balancing between replicas, and making sure the network survives restarts and scaling events. This article covers all of that.

A Quick Recap of the Model

Docker’s default networking is host-scoped: every container gets an IP on the host’s private docker0 bridge, and that IP means nothing to any other host. Weave replaces this mental model with a single flat network address space shared by every container on every participating host. From the container’s point of view, there’s no difference between talking to a container on the same machine and a container three hosts away — the Weave router handles routing and encapsulation transparently.

This matters because it lets you write application configuration (connection strings, service URLs) using stable names instead of juggling host IPs and port mappings, which is exactly how service discovery works in more complex orchestrators like Kubernetes or Swarm, just at a simpler scale.

Attaching Containers to Weave

There are two ways to get a container onto the Weave network.

Method 1: weave env and docker run

eval "$(weave env)"
docker run -d --name redis redis:7-alpine

Every container launched in a shell where weave env has been evaluated is automatically attached, because Weave rewrites DOCKER_HOST to point at a proxy that intercepts docker run calls and injects the network attachment.

To go back to normal Docker networking in that shell:

eval "$(weave env --restore)"

Method 2: weave attach (attach an already-running container)

If a container is already running on the default Docker bridge and I want to add it to Weave without restarting it:

docker run -d --name worker myorg/worker:latest
weave attach worker

weave attach returns the newly assigned Weave IP:

10.40.0.5

I use weave detach worker to remove it from the overlay again if needed.

Naming and Service Discovery

Weave includes a built-in DNS server (weaveDNS) that automatically registers every attached container under <container-name>.weave.local.

docker run -d --name api myorg/api:latest
docker run -it --rm busybox nslookup api.weave.local

Expected output:

Server:    172.17.0.1
Address:   172.17.0.1:53

Name:      api.weave.local
Address 1: 10.40.0.7 api

If I run multiple replicas of the same service under the same name, weaveDNS automatically load-balances DNS responses across all of them in round-robin fashion:

docker run -d --name api myorg/api:latest
docker run -d --name api myorg/api:latest
docker run -d --name api myorg/api:latest

Now nslookup api.weave.local returns three A records, and each new TCP connection from a client will typically hit a different backend depending on client-side DNS caching behavior.

Running a Real Multi-Host App: A Practical Example

Let’s say I’m deploying a small web app with a frontend, an API, and a Redis cache, split across two AWS hosts.

On host1 (runs Redis and the API):

eval "$(weave env)"
docker run -d --name redis redis:7-alpine
docker run -d --name api -e REDIS_HOST=redis.weave.local myorg/api:latest

On host2 (runs the frontend):

eval "$(weave env)"
docker run -d --name frontend -e API_URL=http://api.weave.local:8080 -p 80:80 myorg/frontend:latest

The frontend container on host2 reaches the API container on host1 purely through the DNS name api.weave.local — no hardcoded IPs, no manually published ports between hosts, and no VPC route table changes required beyond allowing Weave’s control-plane ports.

Using Weave with Docker Compose Across Hosts

Compose is inherently single-host by default, but I can still use it per-host and rely on Weave to bridge them. Here’s the Compose file I run on host1:

version: "3.9"
services:
  redis:
    image: redis:7-alpine
    container_name: redis
  api:
    image: myorg/api:latest
    container_name: api
    environment:
      - REDIS_HOST=redis.weave.local
    depends_on:
      - redis

And on host2:

version: "3.9"
services:
  frontend:
    image: myorg/frontend:latest
    container_name: frontend
    environment:
      - API_URL=http://api.weave.local:8080
    ports:
      - "80:80"

I bring each up with:

eval "$(weave env)"
docker compose up -d

Because weave env reroutes the Docker CLI/Compose calls through the Weave proxy, containers created by Compose land on the overlay just like containers created by plain docker run.

Inspecting the Network

A few commands I use to understand what’s actually attached:

weave ps                 # list all containers on the Weave network with IP/MAC
weave dns-lookup api      # test DNS resolution manually
weave status targets      # peers Weave is trying to connect to

Sample weave ps output:

weave:expose  ae:14:8f:00:00:01 10.40.0.1/12
redis         7e:2b:91:aa:00:02 10.40.0.2/12
api           1c:44:5d:bb:00:03 10.40.0.3/12
frontend      92:0a:6c:cc:00:04 10.40.0.4/12

Isolation with Sub-Networks

If I need to segment traffic — say, keeping a database tier reachable only by the API tier — Weave supports IP range allocation per application:

weave launch --ipalloc-range 10.32.0.0/12 --ipalloc-default-subnet 10.32.0.0/16
docker run -d --name db --net=weave --ip 10.32.5.10 myorg/postgres:latest

Combined with standard iptables rules on each host (Weave itself doesn’t enforce firewalling by application identity the way a Kubernetes NetworkPolicy does), this gives coarse-grained isolation.

Troubleshooting Common Issues

  • Containers can’t resolve .weave.local names: confirm weaveDNS is running with weave status dns; it’s enabled by default but can be disabled with --no-dns at launch.
  • weave env doesn’t seem to apply: this sets shell environment variables, so it only affects the current shell session — remember to re-run it in every new terminal or script context, or bake it into your deployment scripts.
  • Stale entries after a container is removed: Weave automatically deregisters DNS entries when a container stops, but if a host crashes ungracefully, run weave status dns to check for orphaned records and weave forget <ip> if needed.

Best Practices

  • Use container names deliberately, since they become your service discovery keys — treat them the way you’d treat hostnames in production DNS.
  • Keep weave env calls inside your deployment scripts (Ansible, systemd unit ExecStartPre, CI/CD pipeline) rather than typing them manually, so environments stay reproducible.
  • Combine Weave with a health-check sidecar or your app’s own readiness endpoint, since weaveDNS load balancing is naive round-robin and doesn’t check backend health.
  • For anything beyond a handful of hosts, evaluate whether you actually need full Kubernetes with a proper CNI instead of hand-rolled Weave + Compose, since Weave’s Kubernetes-native mode gives you NetworkPolicy support that plain Docker Weave lacks.

Scaling to a Larger Fleet

Everything above works fine with two or three hosts, but once I started running Weave across a dozen or more EC2 instances, a few extra considerations came up that are worth knowing before you scale.

Peer discovery at scale. Rather than hardcoding every peer’s IP into every weave launch command, I use a small bootstrap pattern: each new host only needs to know about one existing peer, and Weave’s gossip protocol handles discovering the rest of the mesh automatically.

# On a brand new host joining an existing 10-node cluster
weave launch 10.0.1.10

Weave will learn about the other nine peers from 10.0.1.10 within a few gossip rounds, which I can confirm with:

weave status peers

Restarting Weave safely. If I need to restart the Weave router on a host (say, after an upgrade), running containers keep their existing network state, but new connections briefly pause:

weave stop
weave launch <peer-ip>

I always script this one host at a time, never all hosts simultaneously, so the gossip mesh never loses quorum entirely.

Resource footprint. The Weave router itself is a lightweight Go binary running as a container, typically consuming under 50MB of RAM at idle and scaling modestly with the number of peers and attached containers — small enough that I don’t think twice about running it alongside application containers even on smaller t3.medium instances.

A Real-World Deployment Pattern

In one project, I used exactly this setup to run a staging environment that mirrored production topology across three AWS Availability Zones without provisioning a managed Kubernetes cluster just for staging. Each AZ had one EC2 host running a slice of the application (frontend, API, worker, cache), all peered over Weave, with weave dns-lookup used inside health-check scripts to confirm a given service was actually reachable from every AZ before promoting a deployment. It was a pragmatic middle ground — much simpler to operate than EKS for a small staging fleet, while still exercising real cross-host, cross-AZ networking behavior before code shipped to the production cluster.

Summary

Running Docker containers on a Weave network turns a set of independent Docker hosts into something that behaves like a single logical cluster for networking purposes. Containers get real, routable IPs, name-based discovery works out of the box through weaveDNS, and Compose files translate almost unchanged from single-host to multi-host deployments. It’s a lightweight way to get multi-host container networking without adopting a full orchestrator, and it’s a good stepping stone for understanding the service discovery patterns you’ll meet again in Kubernetes.

References

  • Docker container networking: https://docs.docker.com/network/
  • Docker Compose file reference: https://docs.docker.com/compose/compose-file/
  • Weave Net documentation (archived): https://www.weave.works/docs/net/latest/overview/
  • Kubernetes Service and DNS concepts: https://kubernetes.io/docs/concepts/services-networking/service/

Total
0
Shares

Leave a Reply

Previous Post
How to Build a GRE Tunnel Between Docker Hosts

How to Build a GRE Tunnel Between Docker Hosts: Cross-Host Container Connectivity Guide

Next Post
How to Run a Weave Network on AWS

How to Run a Weave Network on AWS: Docker Container Networking and Overlay Setup Guide

Related Posts