Debugging Network Issues
LEVEL 0
The Problem
Something’s broken. Your multi-container application worked yesterday, but today:
- The frontend can’t reach the API
- The database connection is timing out
- External API calls are failing
- Port mapping isn’t working
You need to debug network issues in Docker. But where do you start?
LEVEL 1
The Concept — The Network Detective Toolkit
The Concept
Imagine you’re a detective investigating why a phone call between two offices failed.
You’d check:
- Are both phones connected? (Network connectivity)
- Can they dial each other’s numbers? (DNS resolution)
- Is the line between them working? (Port accessibility)
- Are there firewalls blocking calls? (Firewall rules)
- Are there call logs? (Container logs)
Docker networking debugging follows the same pattern. You systematically check each layer until you find the problem.
LEVEL 2
The Debugging Checklist
1. Verify containers are running
docker ps
If a container is stopped or restarting, that’s your problem.
Check why it stopped:
docker logs <container>
docker inspect <container> --format='{{.State.Status}}'
2. Check which networks containers are on
# See a container's networks
docker inspect <container> --format='{{json .NetworkSettings.Networks}}' | jq
# See all containers on a network
docker network inspect <network-name>
Common issue: Containers on different networks trying to communicate.
3. Verify IP addresses
docker inspect <container> --format='{{.NetworkSettings.IPAddress}}'
If the IP is empty, the container isn’t on the default bridge. Check which networks it’s on.
4. Test DNS resolution
# Can container1 resolve container2's name?
docker exec container1 nslookup container2
# Or using getent
docker exec container1 getent hosts container2
Common issue: Trying to use container names on the default bridge (no DNS support).
5. Test connectivity with ping
docker exec container1 ping -c 3 container2
If this fails:
- Containers are on different networks
- Firewall rules blocking ICMP
- Container2 is down
6. Test port accessibility
# Test if container2's port 8080 is accessible from container1
docker exec container1 nc -zv container2 8080
# Or using telnet
docker exec container1 telnet container2 8080
If connection fails:
- Service not listening on that port
- Firewall blocking the port
- Wrong port number
7. Check actual application logs
docker logs <container> --tail 100 -f
Look for:
- Connection errors
- Timeouts
- DNS resolution failures
- “Connection refused” errors
8. Inspect port mappings
docker ps
# Check PORTS column
docker port <container>
# Shows all port mappings
Common issue: Expecting container to be accessible on a port, but port mapping wasn’t set up.
LEVEL 3
Advanced Debugging Techniques
1. Run a debug container on the same network
# Start a container with networking tools
docker run -it --network <network-name> nicolaka/netshoot
# Inside the container, you have:
# - ping, nc, telnet, curl, wget
# - dig, nslookup, host
# - tcpdump, iperf, netstat
This is incredibly useful for testing network connectivity without modifying your application containers.
2. Capture network traffic
# On the host, capture docker0 bridge traffic
sudo tcpdump -i docker0 -nn
# Capture traffic for a specific container
# First find the veth interface
docker inspect <container> | grep SandboxKey
# Then capture on that interface
sudo tcpdump -i <veth-interface>
3. Check iptables rules
sudo iptables -t nat -L -n -v
sudo iptables -t filter -L -n -v
Look for DOCKER chains. Port mappings and NAT rules are here.
4. Trace routing
# From inside a container
docker exec <container> traceroute google.com
# Or to another container
docker exec container1 traceroute container2
5. Check DNS resolution chain
# Inside container
docker exec <container> cat /etc/resolv.conf
# See what DNS Docker is configured to use
docker inspect <container> --format='{{.HostConfig.Dns}}'
LEVEL 4
Common Issues and Solutions
Issue 1: “Cannot resolve container name”
Symptoms:
docker exec web ping api
# ping: api: Name or service not known
Cause: Containers on default bridge (no DNS) or different networks
Solution:
# Put both on a custom network
docker network create mynet
docker network connect mynet web
docker network connect mynet api
Issue 2: “Connection refused” on port mapping
Symptoms:
curl http://localhost:8080
# curl: (7) Failed to connect to localhost port 8080: Connection refused
Debugging:
# Is the container running?
docker ps | grep myapp
# Is the port mapping correct?
docker port myapp
# Should show: 80/tcp -> 0.0.0.0:8080
# Is the app inside the container actually listening?
docker exec myapp netstat -tlnp | grep 80
Common causes:
- App not listening on port 80 inside container
- Port mapping set up for wrong port
- App bound to 127.0.0.1 instead of 0.0.0.0
Issue 3: “Connection timeout” to external service
Symptoms:
docker logs myapp
# Error: Connection timeout connecting to api.stripe.com
Debugging:
# Can the container resolve the hostname?
docker exec myapp nslookup api.stripe.com
# Can it reach it?
docker exec myapp ping api.stripe.com
# Can the host reach it?
ping api.stripe.com
# Check DNS settings
docker exec myapp cat /etc/resolv.conf
Common causes:
- DNS resolution failing
- Corporate firewall blocking outbound connections
- Proxy configuration needed
Issue 4: “No route to host” between containers
Symptoms:
docker exec frontend curl http://api:3000
# curl: (7) Failed to connect to api port 3000: No route to host
Debugging:
# Are they on the same network?
docker network inspect mynet | grep -E "frontend|api"
# Check if both containers are actually on the network
docker inspect frontend --format='{{json .NetworkSettings.Networks}}'
docker inspect api --format='{{json .NetworkSettings.Networks}}'
Solution: Connect both to the same network
LEVEL 5
Debugging Tools and Commands Reference
Essential commands:
# Network inspection
docker network ls
docker network inspect <network>
# Container network details
docker inspect <container> --format='{{json .NetworkSettings}}'
docker port <container>
# Connectivity tests (from inside container)
docker exec <container> ping <target>
docker exec <container> nc -zv <target> <port>
docker exec <container> curl <url>
docker exec <container> nslookup <hostname>
# Logs
docker logs <container> -f --tail 100
# Host-level debugging
sudo tcpdump -i docker0
sudo iptables -t nat -L -n
ip addr show
# Debug container with tools
docker run -it --rm --network <network> nicolaka/netshoot
Debugging workflow:
- Verify both containers are running:
docker ps - Check networks:
docker network inspect - Test DNS:
docker exec C1 nslookup C2 - Test ping:
docker exec C1 ping C2 - Test port:
docker exec C1 nc -zv C2 PORT - Check logs:
docker logs C2 - Check iptables:
sudo iptables -t nat -L -n