Native containers and lab networks
Most of a lab should be native arm64 containers, because they run at full speed and use almost no memory. Before you build on an image, check that it has an arm64 build: docker buildx imagetools inspect lists the platforms an image was published for.
FRR publishes arm64 images, so an FRR container on this Mac is a real arm64 Linux running at full speed (uname -m says aarch64). So does Debian, which the Linux hosts in these labs are built on. When an image has no arm64 build, Docker quietly pulls the amd64 one instead and runs it translated. That works, but it's worth knowing when it's happening.
Layer-2-only networks
An ordinary Docker network hands every container an IPv4 address, a subnet and a default route to Docker's own gateway. In a routing lab that's a problem: every router and host gets an extra address and an extra way out that you didn't configure, and traffic can quietly bypass the router you're trying to test.
These labs use networks with Docker's IPv4 turned off (enable_ipv4: false), plus a private IPv6 subnet only because Docker requires some subnet. A container on such a network gets no IPv4 address and no routes: it's a plain Ethernet segment. Every address in the lab is one you configured (in FRR, VyOS or ip addr), so what you see in a routing table is what you built.
You can't reach containers from the Mac
Containers live inside Docker Desktop's Linux VM, and the Mac has no route into its networks. Even an ordinary network's container address doesn't answer a ping from macOS, though other containers reach it instantly. So don't try to SSH or ping into a lab from the Mac's terminal. Work inside it with docker compose exec: docker compose exec r1 vtysh for an FRR router, docker compose exec host sh for a Linux host.
mac$ docker buildx imagetools inspect quay.io/frrouting/frr:10.2.1 | grep Platform
Platform: linux/amd64
Platform: linux/arm64
Platform: linux/ppc64le
Platform: linux/s390x
Platform: linux/arm/v7
Platform: linux/arm/v6
mac$ docker buildx imagetools inspect debian:bookworm-slim | grep Platform
Platform: linux/amd64
Platform: unknown/unknown
Platform: linux/arm/v7
Platform: unknown/unknown
Platform: linux/arm64/v8
Platform: unknown/unknown
Platform: linux/386
Platform: unknown/unknown
Platform: linux/ppc64le
Platform: unknown/unknown
mac$ docker run --rm --entrypoint uname quay.io/frrouting/frr:10.2.1 -m
aarch64- Line 3: FRR publishes an arm64 build, so it runs natively.
- Line 14: So does Debian (arm64/v8). The
unknown/unknownentries are attestations, not images. - Lines 21–22: Proof: FRR's container reports aarch64.
# Two containers: one on an ordinary Docker network, one on a layer-2-only network.
name: l2-demo
services:
normal:
image: alpine
command: sleep infinity
networks: [normal]
l2only:
image: alpine
command: sleep infinity
networks: [l2only]
networks:
normal: {}
l2only:
enable_ipv4: false
enable_ipv6: true
ipam: { config: [{ subnet: "fd00:99::/64" }] }- Line 13: An ordinary Docker network.
- Lines 14–17: Docker's IPv4 off; an IPv6 ULA subnet only because Docker insists on one.
mac$ docker compose -f l2.yaml exec normal ip -4 addr show eth0
11: eth0@if1322: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
inet 172.25.0.2/16 brd 172.25.255.255 scope global eth0
valid_lft forever preferred_lft forever
mac$ docker compose -f l2.yaml exec l2only ip -4 addr show eth0
mac$ docker compose -f l2.yaml exec normal ip route
default via 172.25.0.1 dev eth0
172.25.0.0/16 dev eth0 scope link src 172.25.0.2
mac$ docker compose -f l2.yaml exec l2only ip route- Line 3: On an ordinary network, Docker hands out an address you didn't choose…
- Line 9: …and a default route to Docker's gateway: a hidden way out of your lab.
- Line 6: On the layer-2-only network: no IPv4 address at all…
- Line 12: …and no routes. Every address and route will be yours.
mac$ ping -c 2 -t 3 172.25.0.2
PING 172.25.0.2 (172.25.0.2): 56 data bytes
Request timeout for icmp_seq 0
--- 172.25.0.2 ping statistics ---
2 packets transmitted, 0 packets received, 100.0% packet loss
mac$ docker compose -f l2.yaml exec normal ping -c 2 172.25.0.2
PING 172.25.0.2 (172.25.0.2): 56 data bytes
64 bytes from 172.25.0.2: seq=0 ttl=64 time=0.027 ms
64 bytes from 172.25.0.2: seq=1 ttl=64 time=0.033 ms
--- 172.25.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.027/0.030/0.033 ms- Lines 1–6: macOS has no route into Docker Desktop's networks: nothing answers.
- Lines 8–15: From another container, the same address answers in microseconds. Work inside the lab with
docker compose exec.