Skip to content

Lab: Docker Networking

Pairs with: Docker Networking Fundamentals

Environment: Any host with Docker installed. An equivalent docker-compose.yml is shown below if you prefer Compose over the raw docker commands.

docker-compose.yml (optional)
services:
  web:
    image: nginx:1.27-alpine
    networks:
      - lab_net

  web2:
    image: nginx:1.27-alpine
    ports:
      - "8080:80"

networks:
  lab_net:
    driver: bridge

The lab itself is written around the raw docker CLI so each step (explicit network creation, explicit lack of one) stays visible; both forms give the same networking behavior.

Starting conditions

  1. Docker installed and running (docker ps works without error).
  2. No containers or networks from this lab already present (run docker network ls to confirm a clean baseline).

Instructions

Part 1 — Prove name resolution requires network membership, not just "Docker is running"

docker network create lab_net
docker run -d --name web --network lab_net nginx
docker run -it --rm --name tester --network lab_net alpine sh -c "wget -qO- http://web || echo FAILED"

Then, without --network lab_net:

docker run -it --rm --name outsider alpine sh -c "wget -qO- http://web || echo FAILED"

Part 2 — Prove -p is NAT, not a direct bind, and that it bypasses host firewall rules you might expect to apply

docker run -d --name web2 -p 8080:80 nginx
sudo ufw deny 8080/tcp 2>/dev/null || echo "(ufw not installed, skip this specific check)"
curl -i http://localhost:8080/

Expected results

  • Part 1: tester (on lab_net) succeeds — wget resolves web by name and gets nginx's default page. outsider (not on lab_net) fails with a DNS resolution error — the name web means nothing outside that specific network's embedded DNS.
  • Part 2: even with a ufw deny 8080/tcp rule in place, curl against the published port still succeeds — demonstrating that Docker's own iptables/nftables rules for published ports are evaluated independently of ufw's rules, which only govern the standard INPUT chain, not the DOCKER/DOCKER-USER chains Docker itself manages.

Diagnosis checklist

  • [ ] Did you confirm outsider's failure is specifically a DNS resolution failure (the name web doesn't resolve), not a connection-refused or timeout — this is the signal that it's a network-membership issue, not a reachability issue at the IP level?
  • [ ] Did you verify the ufw rule was actually in place (ufw status) before concluding it had no effect, rather than assuming?
  • [ ] Can you explain why ufw's rule doesn't apply — specifically, which iptables/nftables chain Docker inserts its own NAT rules into, and how that relates to chain evaluation order?

Success criteria

You can explain to someone else, using this lab's own output as evidence, why "I set a firewall rule to block this Docker port and it didn't work" is a frequently-reported, genuinely confusing but fully explainable behavior — not a Docker bug.

Cleanup / rollback

docker rm -f web web2 2>/dev/null
docker network rm lab_net 2>/dev/null
sudo ufw delete deny 8080/tcp 2>/dev/null || true

Confirm with docker network ls and docker ps -a that no lab containers or networks remain before considering the environment cleaned up.