ð docker-compose-networking
Use when configuring networks and service communication in Docker Compose including bridge networks, overlay networks, service discovery, and inter-service communication.
Overview
Master network configuration and service communication patterns in Docker Compose for building secure, scalable multi-container applications.
Default Bridge Network
Docker Compose automatically creates a default bridge network for all services in a compose file:
version: '3.8'
services:
frontend:
image: nginx:alpine
ports:
- "80:80"
# Can reach backend using service name as hostname
backend:
image: node:18-alpine
command: node server.js
# Accessible at hostname 'backend' from frontend
database:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: secret
# Accessible at hostname 'database' from backend
In this setup:
- All services can communicate using service names as hostnames
- Frontend can reach backend at
http://backend:3000 - Backend can reach database at
postgres://database:5432 - Only frontend's port 80 is exposed to host
Custom Bridge Networks
Define custom networks for service isolation and segmentation:
version: '3.8'
services:
frontend:
image: nginx:alpine
networks:
- frontend-network
ports:
- "80:80"
api:
image: node:18-alpine
networks:
- frontend-network
- backend-network
environment:
DATABASE_URL: postgresql://db:5432/app
database:
image: postgres:15-alpine
networks:
- backend-network
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: app
volumes:
- db-data:/var/lib/postgresql/data
cache:
image: redis:7-alpine
networks:
- backend-network
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
frontend-network:
driver: bridge
backend-network:
driver: bridge
internal: true
volumes:
db-data:
redis-data:
Network isolation:
- Frontend can only reach API
- Frontend cannot reach database or cache directly
- API can reach all services
- Backend network is internal (no external access)
Network Aliases
Configure multiple hostnames for service discovery:
version: '3.8'
services:
web:
image: nginx:alpine
networks:
public:
aliases:
- website
- www
- web-server
internal:
aliases:
- web-internal
api:
image: node:18-alpine
networks:
public:
aliases:
- api-server
- backend
internal:
aliases:
- api-internal
depends_on:
- database
database:
image: postgres:15-alpine
networks:
internal:
aliases:
- db
- postgres
- primary-db
environment:
POSTGRES_PASSWORD: secret
networks:
public:
driver: bridge
internal:
driver: bridge
internal: true
Services can be reached by any of their aliases:
http://website,http://www,http://web-serverall reach web servicepostgresql://db:5432,postgresql://postgres:5432both reach database
Static IP Addresses
Assign fixed IP addresses for services requiring stable networking:
version: '3.8'
services:
loadbalancer:
image: nginx:alpine
networks:
app-network:
ipv4_address: 172.28.1.10
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
app-1:
image: myapp:latest
networks:
app-network:
ipv4_address: 172.28.1.11
environment:
APP_ID: "1"
app-2:
image: myapp:latest
networks:
app-network:
ipv4_address: 172.28.1.12
environment:
APP_ID: "2"
app-3:
image: myapp:latest
networks:
app-network:
ipv4_address: 172.28.1.13
environment:
APP_ID: "3"
database:
image: postgres:15-alpine
networks:
app-network:
ipv4_address: 172.28.1.20
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
app-network:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
gateway: 172.28.1.1
volumes:
pgdata:
External Networks
Connect to existing Docker networks created outside Compose:
version: '3.8'
services:
api:
image: node:18-alpine
networks:
- app-network
- shared-network
environment:
DATABASE_URL: postgresql://db:5432/app
database:
image: postgres:15-alpine
networks:
- app-network
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
app-network:
driver: bridge
shared-network:
external: true
name: company-shared-network
volumes:
pgdata:
Create external network first:
docker network create company-shared-network
docker compose up -d
Host Network Mode
Use host networking for maximum performance (Linux only):
version: '3.8'
services:
high-performance-app:
image: myapp:latest
network_mode: "host"
environment:
BIND_ADDRESS: "0.0.0.0"
PORT: "8080"
# No port mapping needed - directly uses host's network stack
monitoring:
image: prometheus:latest
network_mode: "host"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.listen-address=0.0.0.0:9090'
volumes:
prometheus-data:
Note: Host networking bypasses Docker network isolation and is typically used for monitoring tools or high-throughput applications.
Service Discovery and DNS
Configure DNS resolution and service discovery:
version: '3.8'
services:
api:
image: node:18-alpine
networks:
- app-network
dns:
- 8.8.8.8
- 8.8.4.4
dns_search:
- company.local
extra_hosts:
- "legacy-api.company.local:192.168.1.100"
- "auth-service.company.local:192.168.1.101"
environment:
DATABASE_HOST: database.company.local
database:
image: postgres:15-alpine
networks:
app-network:
aliases:
- database.company.local
- db.company.local
hostname: primary-database
domainname: company.local
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
app-network:
driver: bridge
driver_opts:
com.docker.network.bridge.name: br-company-app
volumes:
pgdata:
Link Containers (Legacy)
While links is deprecated, understanding it helps migrate legacy configurations:
version: '3.8'
services:
# Modern approach - use networks instead
web:
image: nginx:alpine
networks:
- app-network
depends_on:
- api
api:
image: node:18-alpine
networks:
- app-network
depends_on:
- database
environment:
# Use service name as hostname
DATABASE_URL: postgresql://database:5432/app
database:
image: postgres:15-alpine
networks:
- app-network
environment:
POSTGRES_PASSWORD: secret
networks:
app-network:
driver: bridge
Multi-Network Architecture
Complex applications with multiple isolated networks:
version: '3.8'
services:
nginx:
image: nginx:alpine
networks:
- public
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- frontend
- api
frontend:
image: react-app:latest
networks:
- public
- frontend-tier
environment:
API_URL: http://api:3000
api:
image: node-api:latest
networks:
- frontend-tier
- backend-tier
environment:
DATABASE_URL: postgresql://postgres:5432/app
REDIS_URL: redis://cache:6379
QUEUE_URL: amqp://rabbitmq:5672
depends_on:
- database
- cache
- queue
worker:
image: node-worker:latest
networks:
- backend-tier
environment:
DATABASE_URL: postgresql://postgres:5432/app
QUEUE_URL: amqp://rabbitmq:5672
depends_on:
- database
- queue
deploy:
replicas: 3
database:
image: postgres:15-alpine
networks:
- backend-tier
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
cache:
image: redis:7-alpine
networks:
- backend-tier
command: redis-server --appendonly yes
volumes:
- redis-data:/data
queue:
image: rabbitmq:3-management-alpine
networks:
- backend-tier
- management
ports:
- "15672:15672" # Management UI
environment:
RABBITMQ_DEFAULT_USER: admin
RABBITMQ_DEFAULT_PASS: secret
volumes:
- rabbitmq-data:/var/lib/rabbitmq
monitoring:
image: prometheus:latest
networks:
- management
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
networks:
public:
driver: bridge
frontend-tier:
driver: bridge
internal: true
backend-tier:
driver: bridge
internal: true
management:
driver: bridge
volumes:
pgdata:
redis-data:
rabbitmq-data:
prometheus-data:
Network segmentation:
- Public: Internet-facing services (nginx, frontend)
- Frontend-tier: Frontend and API communication
- Backend-tier: API, workers, databases, cache, queue
- Management: Monitoring and administration tools
Port Publishing Strategies
Control how services expose ports:
version: '3.8'
services:
# Short syntax - host:container
web:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
networks:
- public
# Long syntax with protocol specification
api:
image: node:18-alpine
ports:
- target: 3000
published: 3000
protocol: tcp
mode: host
networks:
- app-network
# Random host port
app:
image: myapp:latest
ports:
- "3000" # Docker assigns random host port
networks:
- app-network
# Bind to specific host interface
admin:
image: admin-panel:latest
ports:
- "127.0.0.1:8080:80" # Only accessible from localhost
networks:
- admin-network
# UDP protocol
dns:
image: bind9:latest
ports:
- "53:53/udp"
- "53:53/tcp"
networks:
- dns-network
# Range of ports
streaming:
image: rtmp-server:latest
ports:
- "1935:1935"
- "8080-8089:8080-8089"
networks:
- streaming-network
networks:
public:
app-network:
admin-network:
internal: true
dns-network:
streaming-network:
Container Communication Patterns
Request-Response Pattern
version: '3.8'
services:
gateway:
image: nginx:alpine
networks:
- frontend
ports:
- "80:80"
volumes:
- ./nginx-gateway.conf:/etc/nginx/nginx.conf:ro
service-a:
image: service-a:latest
networks:
- frontend
- backend
environment:
SERVICE_B_URL: http://service-b:8080
DATABASE_URL: postgresql://db:5432/service_a
service-b:
image: service-b:latest
networks:
- frontend
- backend
environment:
DATABASE_URL: postgresql://db:5432/service_b
database:
image: postgres:15-alpine
networks:
- backend
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
volumes:
pgdata:
Pub-Sub Pattern
version: '3.8'
services:
publisher:
image: publisher:latest
networks:
- messaging
environment:
REDIS_URL: redis://redis:6379
depends_on:
- redis
subscriber-1:
image: subscriber:latest
networks:
- messaging
environment:
REDIS_URL: redis://redis:6379
SUBSCRIBER_ID: "1"
depends_on:
- redis
subscriber-2:
image: subscriber:latest
networks:
- messaging
environment:
REDIS_URL: redis://redis:6379
SUBSCRIBER_ID: "2"
depends_on:
- redis
redis:
image: redis:7-alpine
networks:
- messaging
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
messaging:
driver: bridge
driver_opts:
com.docker.network.bridge.enable_icc: "true"
volumes:
redis-data:
Network Troubleshooting Configuration
Enable debugging and monitoring:
version: '3.8'
services:
app:
image: myapp:latest
networks:
app-network:
aliases:
- primary-app
cap_add:
- NET_ADMIN
- NET_RAW
debug:
image: nicolaka/netshoot:latest
networks:
- app-network
command: sleep infinity
cap_add:
- NET_ADMIN
- NET_RAW
stdin_open: true
tty: true
database:
image: postgres:15-alpine
networks:
app-network:
aliases:
- db
environment:
POSTGRES_PASSWORD: secret
networks:
app-network:
driver: bridge
driver_opts:
com.docker.network.bridge.enable_ip_masquerade: "true"
com.docker.network.driver.mtu: "1500"
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
Debug commands:
# Enter debug container
docker compose exec debug bash
# Test connectivity
ping app
curl http://app:8080/health
# Check DNS resolution
nslookup app
dig app
# Network scanning
nmap -p- app
# Trace route
traceroute app
# Monitor traffic
tcpdump -i eth0 -n
IPv6 Networking
Enable IPv6 support:
version: '3.8'
services:
web:
image: nginx:alpine
networks:
- ipv6-network
ports:
- "80:80"
api:
image: node:18-alpine
networks:
ipv6-network:
ipv6_address: 2001:db8:1::10
database:
image: postgres:15-alpine
networks:
ipv6-network:
ipv6_address: 2001:db8:1::20
environment:
POSTGRES_PASSWORD: secret
networks:
ipv6-network:
driver: bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
- subnet: 2001:db8:1::/64
When to Use This Skill
Use docker-compose-networking when you need to:
- Configure custom network topologies for multi-container applications
- Implement network segmentation and service isolation
- Set up service discovery and inter-service communication
- Design secure network architectures with frontend/backend separation
- Configure static IP addresses for services
- Connect to external Docker networks
- Implement complex microservices communication patterns
- Troubleshoot network connectivity issues
- Configure DNS resolution and hostname aliases
- Set up pub-sub or message queue architectures
- Enable IPv6 networking
- Optimize network performance with host networking
- Configure port publishing and exposure strategies
Best Practices
-
Use Custom Networks for Isolation: Always create custom networks instead of relying solely on the default network for better security and organization.
-
Implement Network Segmentation: Separate frontend, backend, and data tiers into different networks to limit attack surface.
-
Use Internal Networks: Mark backend networks as
internal: trueto prevent external access to sensitive services like databases. -
Prefer Service Names Over IPs: Use Docker's built-in DNS and service names instead of hardcoding IP addresses for maintainability.
-
Configure Health Checks: Implement health checks to ensure services are ready before routing traffic to them.
-
Use Network Aliases: Define meaningful aliases for services to support multiple naming conventions and easier migration.
-
Avoid Host Networking Unless Necessary: Use bridge networks by default; host networking should only be used for specific performance requirements.
-
Document Network Architecture: Clearly comment your network design and document which services can communicate with each other.
-
Use Depends_on Wisely: Combine
depends_onwith health checks to ensure services start in the correct order. -
Implement Least Privilege: Only expose ports that absolutely need to be accessible from outside the Docker network.
-
Use Environment Variables for URLs: Configure service endpoints through environment variables for flexibility across environments.
-
Test Network Isolation: Regularly verify that services can only communicate through intended network paths.
-
Configure Appropriate MTU: Set MTU values based on your network infrastructure to avoid fragmentation issues.
-
Use External Networks for Shared Resources: When multiple Compose projects need to communicate, use external networks rather than duplicating services.
-
Monitor Network Performance: Use tools like
docker statsand dedicated monitoring containers to track network usage and identify bottlenecks.
Common Pitfalls
-
Exposing All Services Publicly: Don't publish ports for services that should only be accessed internally; use networks instead of port publishing.
-
Hardcoding IP Addresses: Avoid static IP addresses unless absolutely necessary; rely on service discovery instead.
-
Using Default Network Only: Not creating custom networks misses opportunities for proper segmentation and isolation.
-
Ignoring Network Modes: Using the wrong network mode (bridge vs host vs overlay) for your use case can cause connectivity or performance issues.
-
Missing Network Dependencies: Not properly configuring
depends_oncan cause services to fail when trying to connect to unavailable services. -
Overusing Host Networking: Using
network_mode: hostunnecessarily breaks container isolation and portability. -
Not Using Internal Networks: Failing to mark backend networks as internal leaves databases and sensitive services exposed.
-
Mixing Network Modes: Trying to publish ports or connect to networks when using
network_mode: hostcauses configuration errors. -
Circular Network Dependencies: Creating network dependencies that form a circle prevents containers from starting properly.
-
Ignoring DNS Configuration: Not configuring DNS properly can cause name resolution failures in containerized applications.
-
Subnet Conflicts: Using IP ranges that conflict with host or other Docker networks causes routing issues.
-
Not Testing Network Policies: Assuming network isolation works without testing can leave security vulnerabilities.
-
Exposing Management Interfaces: Publishing management ports (like RabbitMQ, Redis, PostgreSQL) without authentication or IP restrictions.
-
Using Links Instead of Networks: The deprecated
linksfeature should be replaced with modern network configuration. -
Ignoring Network Driver Options: Not configuring driver options like MTU or IP masquerade can cause subtle connectivity problems in production.
Resources
Official Documentation
Network Troubleshooting
- Nicolaka Netshoot - Network troubleshooting container
- Docker Network Inspect