Docker Compose Networks
Introduction
When building applications with Docker, containers often need to communicate with each other. Docker Compose simplifies this communication by providing built-in networking capabilities. Understanding how networking works in Docker Compose is essential for developing multi-container applications effectively.
In this guide, we'll explore how Docker Compose manages networks, how containers can communicate with each other, and how to customize network configurations for your specific needs.
Default Network Behavior
By default, Docker Compose creates a single network for your application, and all services defined in your docker-compose.yml
file are connected to this network. This means containers can communicate with each other using their service names as hostnames.
Let's look at a basic example:
version: '3'
services:
web:
image: nginx:latest
ports:
- "8080:80"
database:
image: postgres:latest
environment:
POSTGRES_PASSWORD: example
When you run docker-compose up
, both services (web
and database
) are placed on the same network. The web
service can reach the database
service using the hostname database
.
For example, if your web application needs to connect to the database, you could use:
// Node.js example
const { Client } = require('pg')
const client = new Client({
host: 'database', // This works because of Docker Compose networking
user: 'postgres',
password: 'example'
})
Visualizing the Default Network
Inspecting Networks
To see the networks created by Docker Compose, use:
docker-compose ps
docker network ls
You'll notice that Docker Compose creates a network with a name based on your project directory:
NETWORK ID NAME DRIVER SCOPE
f7d5ce87a756 myapp_default bridge local
To inspect a specific network:
docker network inspect myapp_default
Output (simplified):
[
{
"Name": "myapp_default",
"Driver": "bridge",
"Containers": {
"2a6e712d74c2": {
"Name": "myapp_web_1",
"IPv4Address": "172.18.0.2/16"
},
"d5fcf3d034fc": {
"Name": "myapp_database_1",
"IPv4Address": "172.18.0.3/16"
}
}
}
]
Custom Network Configuration
While the default network is sufficient for many use cases, Docker Compose allows you to define custom networks with specific settings.
Defining Custom Networks
version: '3'
services:
web:
image: nginx:latest
networks:
- frontend
api:
image: node:alpine
networks:
- frontend
- backend
database:
image: postgres:latest
networks:
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridge
In this example:
- We define two networks:
frontend
andbackend
- The
web
service can only communicate with theapi
service - The
database
service can only communicate with theapi
service - The
api
service can communicate with bothweb
anddatabase
Visualizing Custom Networks
Network Types and Drivers
Docker Compose supports different network drivers, each with specific use cases:
- bridge (default): Standard network driver for standalone containers
networks:
mynetwork:
driver: bridge
- host: Removes network isolation between container and host
networks:
mynetwork:
driver: host
- none: Disables networking for containers
networks:
mynetwork:
driver: none
- overlay: For multi-host networking (used with Docker Swarm)
networks:
mynetwork:
driver: overlay
Advanced Network Configuration
Setting Static IP Addresses
You can configure containers with static IP addresses:
version: '3'
services:
web:
image: nginx:latest
networks:
app_net:
ipv4_address: 172.16.238.10
networks:
app_net:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.16.238.0/24
Connecting to External Networks
You can connect to pre-existing networks (created outside Docker Compose):
version: '3'
services:
web:
image: nginx:latest
networks:
- existing_network
networks:
existing_network:
external: true
Network Aliases
You can give services additional network aliases to be reached by:
version: '3'
services:
database:
image: postgres:latest
networks:
backend:
aliases:
- db
- postgresql
networks:
backend:
driver: bridge
With this configuration, other services can connect to the database using either database
, db
, or postgresql
as the hostname.
Practical Example: Web Application with Database and Redis Cache
Let's create a practical example of a web application with a database and Redis cache:
version: '3'
services:
web:
build: ./web
ports:
- "3000:3000"
networks:
- frontend
- backend
depends_on:
- api
api:
build: ./api
networks:
- backend
depends_on:
- database
- redis
environment:
- DB_HOST=database
- REDIS_HOST=redis
database:
image: postgres:latest
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
environment:
POSTGRES_PASSWORD: example
redis:
image: redis:alpine
networks:
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridge
volumes:
db-data:
In this example:
- We have a web frontend that communicates with an API
- The API service communicates with both a database and Redis cache
- The database and Redis are only accessible to the API (not directly to the web frontend)
- We're using environment variables to pass connection information
Web App Architecture Diagram
Network Best Practices
-
Security through Segmentation: Separate your networks based on security requirements. For instance, keep your database in a different network than your frontend.
yamlnetworks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # No external connectivity -
Use network aliases wisely: They can make your configuration more flexible and descriptive.
-
Consider using the
internal
flag for networks that should not have internet access:yamlnetworks:
db_network:
driver: bridge
internal: true -
Use service discovery by default (service names as hostnames) instead of hardcoded IPs.
-
Document your network layout for complex applications.
Troubleshooting Docker Compose Networks
1. Check network connectivity between containers
Use the docker-compose exec
command to run commands inside containers:
docker-compose exec web ping database
2. Inspect the network
docker network inspect my_project_default
3. View logs for network-related issues
docker-compose logs [service_name]
4. Recreate networks
If you're experiencing networking issues, try:
docker-compose down
docker-compose up
Summary
Docker Compose networks provide a powerful way to manage communication between containers in multi-container applications. By default, Docker Compose creates a single network for all services, enabling easy communication between them using service names as hostnames.
For more complex applications, you can define custom networks with specific drivers and configurations, including static IP addresses, custom subnets, and network aliases. By understanding these networking capabilities, you can design more secure and efficient container-based applications.
Exercise: Create a Three-Tier Application
Exercise: Create a Docker Compose configuration for a three-tier application with:
- A frontend web server (Nginx)
- A backend API (Node.js)
- A database (MongoDB)
Requirements:
- The frontend should only communicate with the backend API
- The backend API should communicate with both the frontend and database
- The database should only be accessible to the backend API
- Define appropriate networks to enforce these communication patterns
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)