What you will build
A disposable two-service Docker lab that starts broken. You will distinguish a host port from a container port, repair service DNS, and recover a missing network attachment without deleting volumes or restarting every container on the host.
Allow 60-90 minutes. Use Docker Engine and Compose 2+ on a non-production exercise machine. Container images require downloads; the exercise needs no hosted AI service.
Before you start
Create a new docker-network-lab directory and verify host loopback port 18080 is unused. Do not place credentials or personal files in this directory. All commands below use the explicit project name fieldguide-net so they cannot accidentally operate on a nearby Compose project.
Create compose.yml:
services:
origin:
image: nginx:alpine
ports:
- "127.0.0.1:18080:80"
checker:
image: busybox:1.37
command:
- sh
- -c
- 'while true; do wget -qO- http://web:18080/ || true; sleep 10; done'
The unpinned nginx tag is acceptable only for initial discovery. Record the pulled digest and pin it if you keep the lab as a repeatable test. The checker intentionally uses both a wrong service name and a wrong internal port.
1. Establish the actual state
docker compose -p fieldguide-net config --quiet
docker compose -p fieldguide-net up -d
docker compose -p fieldguide-net ps
docker compose -p fieldguide-net logs --tail=20 checker
curl --fail http://127.0.0.1:18080/
Checkpoint: the host can retrieve nginx's welcome page, while the checker reports a failure. "The app works in my browser" does not prove that another container can reach it.
2. Separate naming from port selection
The Compose service is named origin, not web. Test its container DNS name from the checker:
docker compose -p fieldguide-net exec checker nslookup origin
docker compose -p fieldguide-net exec checker wget -qO- http://origin:80/
The host port 18080 maps to container port 80. Containers on the same network normally use origin:80; they do not use the host's loopback publication.
Edit the checker's command to request http://origin:80/ and recreate only that service:
docker compose -p fieldguide-net up -d checker
docker compose -p fieldguide-net logs --tail=20 checker
You should now see successful page output. Distinguish a fresh successful log line from an older error still present in retained logs.
3. Introduce a network fault deliberately
Change only the checker configuration to attach to an independent network:
checker:
image: busybox:1.37
networks: [isolated]
command:
- sh
- -c
- 'while true; do wget -qO- http://origin:80/ || true; sleep 10; done'
networks:
isolated: {}
Keep the original origin service in the same Compose file. This is a fragment showing the changed checker and new top-level network; it is not a replacement file containing only the checker.
Recreate the checker, then inspect the attached network names:
docker compose -p fieldguide-net up -d checker
docker inspect "$(docker compose -p fieldguide-net ps -q origin)" --format '{{json .NetworkSettings.Networks}}'
docker inspect "$(docker compose -p fieldguide-net ps -q checker)" --format '{{json .NetworkSettings.Networks}}'
The containers no longer share a network. Remove the exercise's networks: [isolated] line from the checker so it rejoins the default network, validate the file, and recreate it. Do not repair the fault by opening nginx to every host interface.
4. Practice interpreting errors
| Evidence | Next layer to inspect |
|---|---|
| Name does not resolve | Service name and shared network |
| Connection refused | Internal port, listener, and startup |
| Timeout | Routing, policy, or a stalled service |
| HTTP 401 or 403 | Credentials and resource authorization |
| Host works, container fails | Different loopback and network views |
Do not disable authentication in a real application to fix a network error. Do not use a blanket volume prune as a DNS repair.
Verify, clean up, and recover
Confirm both the host request and the checker succeed after a controlled restart. Note which configuration change fixed each fault.
docker compose -p fieldguide-net down
This removes the lab's containers and networks; this particular lab declares no persistent volumes. Leave shared images and unrelated projects alone. No daemon restart or system-wide prune is required.