Questions
Two containers can't communicate with each other. Diagnose and fix the networking issue.
The Scenario
You have a Node.js API container trying to connect to a Redis container:
$ docker ps
CONTAINER ID IMAGE PORTS NAMES
a1b2c3d4e5f6 api:v1 0.0.0.0:3000->3000/tcp api
b2c3d4e5f6g7 redis:7 0.0.0.0:6379->6379/tcp redis
$ docker logs api
Error: connect ECONNREFUSED 127.0.0.1:6379
at TCPConnectWrap.afterConnect
The API can’t reach Redis, but you can connect to Redis from your host machine. What’s wrong?
The Challenge
Diagnose the networking issue and fix it. Explain the different Docker networking modes and when to use each.
A junior engineer might try using localhost or 127.0.0.1 to connect between containers, expose more ports thinking that's the issue, restart both containers hoping the network resets, or try to use the container's IP address directly. These fail because localhost inside a container refers to that container itself, exposing ports is for host access not container-to-container communication, restarts don't fix architectural issues, and container IPs are dynamic and change on restart.
A senior engineer understands that containers need to be on the same Docker network to communicate by name. The fix is to create a user-defined bridge network and connect both containers to it. Then containers can reach each other using their container names as hostnames. This provides automatic DNS resolution, better isolation, and more control over networking.
Step 1: Understand the Problem
# Check which networks each container is on
docker inspect api --format='{{range .NetworkSettings.Networks}}{{.NetworkID}}{{end}}'
docker inspect redis --format='{{range .NetworkSettings.Networks}}{{.NetworkID}}{{end}}'
# List all networks
docker network ls
# Inspect the default bridge network
docker network inspect bridgeThe issue: By default, containers on the default bridge network can’t resolve each other by name. They need to be on a user-defined network for DNS resolution.
Step 2: Create a User-Defined Network
# Create a custom bridge network
docker network create app-network
# Verify it was created
docker network lsStep 3: Connect Containers to the Network
# Option 1: Connect running containers
docker network connect app-network api
docker network connect app-network redis
# Option 2: Start containers on the network
docker run -d --name redis --network app-network redis:7
docker run -d --name api --network app-network -p 3000:3000 api:v1Step 4: Update Application Configuration
// Before (wrong)
const redis = new Redis({
host: '127.0.0.1', // This is the container itself!
port: 6379
});
// After (correct)
const redis = new Redis({
host: 'redis', // Container name as hostname
port: 6379
});Step 5: Verify Connectivity
# Test DNS resolution from API container
docker exec api ping redis
# Test TCP connection
docker exec api nc -zv redis 6379
# Check network configuration
docker inspect api --format='{{json .NetworkSettings.Networks}}' | jq Docker Network Types
| Network Type | Use Case | Container-to-Container | Host Access |
|---|---|---|---|
| bridge (default) | Default for standalone containers | By IP only (no DNS) | Via port mapping |
| user-defined bridge | Multi-container apps | By name (DNS) | Via port mapping |
| host | Performance-critical apps | Via localhost | Direct (no port mapping) |
| none | Maximum isolation | No networking | None |
| overlay | Multi-host (Swarm/K8s) | By name across hosts | Via routing mesh |
Docker Compose Solution
The best way to handle multi-container networking:
# docker-compose.yml
version: '3.8'
services:
api:
build: ./api
ports:
- "3000:3000"
environment:
- REDIS_HOST=redis
depends_on:
- redis
networks:
- app-network
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
redis-data:
Docker Compose automatically:
- Creates a network named
<project>_app-network - Connects all services to it
- Enables DNS resolution by service name
Debugging Network Issues
# Check container's network configuration
docker inspect <container> --format='{{json .NetworkSettings}}' | jq
# List containers on a network
docker network inspect app-network --format='{{range .Containers}}{{.Name}} {{end}}'
# Test connectivity from inside container
docker exec -it api sh
$ ping redis
$ nc -zv redis 6379
$ curl http://other-service:8080/health
# Check DNS resolution
docker exec api nslookup redis
# Check iptables rules (on host)
sudo iptables -L -n | grep DOCKER
Practice Question
Why can't containers on the default bridge network communicate using container names?