Connecting Store Services
Real e-commerce apps have multiple services: product API, user service, cart, database, cache. These need to communicate. Docker networking makes this seamless.
The Problem
Run two containers:
docker run -d --name api-container nginx
docker run -d --name db-container postgres:15
Can api-container connect to db-container? Not easily on the default network.
Docker Networks
Docker networks let containers communicate securely:
┌─────────────────────────────────────────────────┐
│ shopflow-network │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ product │ │ cart │ │ postgres │ │
│ │ api │◄──│ service │──►│ db │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ Containers communicate by name: │
│ "postgres://shopflow-db:5432" │
│ "http://product-api:3000" │
└─────────────────────────────────────────────────┘
Create a Network
# Create a bridge network for our e-commerce app
docker network create shopflow-network
Output:
a1b2c3d4e5f6g7h8i9j0...
List networks:
docker network ls
Output:
NETWORK ID NAME DRIVER SCOPE
abc123... bridge bridge local
def456... host host local
ghi789... shopflow-network bridge local
Connect Containers to a Network
Method 1: At Creation Time
# Start database on our network
docker run -d \
--name shopflow-db \
--network shopflow-network \
-e POSTGRES_USER=shopflow \
-e POSTGRES_PASSWORD=secretpass \
-e POSTGRES_DB=shopflow \
postgres:15
# Start Redis cache on same network
docker run -d \
--name shopflow-cache \
--network shopflow-network \
redis:7-alpine
Method 2: Connect Existing Container
# Start a container (default network)
docker run -d --name product-api nginx
# Connect it to our network
docker network connect shopflow-network product-api
Service Communication Example
Let's create a complete e-commerce network setup:
1. Create the network:docker network create shopflow-network
2. Start PostgreSQL:
docker run -d \
--name shopflow-db \
--network shopflow-network \
-e POSTGRES_USER=shopflow \
-e POSTGRES_PASSWORD=secretpass \
-e POSTGRES_DB=shopflow \
postgres:15
3. Start Redis:
docker run -d \
--name shopflow-cache \
--network shopflow-network \
redis:7-alpine
4. Create a Product API that connects to both:
Create test-api/server.js:
const express = require('express');
const { Pool } = require('pg');
const Redis = require('ioredis');
const app = express();
// Connect to PostgreSQL using container name as host
const db = new Pool({
host: 'shopflow-db', // Container name!
port: 5432,
user: 'shopflow',
password: 'secretpass',
database: 'shopflow'
});
// Connect to Redis using container name
const cache = new Redis({
host: 'shopflow-cache', // Container name!
port: 6379
});
app.get('/health', async (req, res) => {
try {
// Test database connection
await db.query('SELECT 1');
// Test cache connection
await cache.ping();
res.json({
status: 'healthy',
database: 'connected',
cache: 'connected'
});
} catch (err) {
res.status(500).json({
status: 'unhealthy',
error: err.message
});
}
});
app.get('/api/products', async (req, res) => {
// Try cache first
const cached = await cache.get('products');
if (cached) {
return res.json({ source: 'cache', products: JSON.parse(cached) });
}
// Query database
const result = await db.query('SELECT * FROM products');
// Cache for 60 seconds
await cache.setex('products', 60, JSON.stringify(result.rows));
res.json({ source: 'database', products: result.rows });
});
app.listen(3000, () => {
console.log('Product API running on port 3000');
});
5. Build and run the API:
docker build -t shopflow/product-api:1.0 .
docker run -d \
--name product-api \
--network shopflow-network \
-p 3000:3000 \
shopflow/product-api:1.0
DNS Resolution in Action
Inside any container on the network, hostnames resolve automatically:
# Enter the product-api container
docker exec -it product-api sh
# Ping the database by name
ping shopflow-db
# Ping the cache by name
ping shopflow-cache
Output:
PING shopflow-db (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.089 ms
Docker's internal DNS resolved shopflow-db to 172.18.0.2.
Inspect the Network
docker network inspect shopflow-network
Output:
{
"Name": "shopflow-network",
"Driver": "bridge",
"Containers": {
"abc123...": {
"Name": "shopflow-db",
"IPv4Address": "172.18.0.2/16"
},
"def456...": {
"Name": "shopflow-cache",
"IPv4Address": "172.18.0.3/16"
},
"ghi789...": {
"Name": "product-api",
"IPv4Address": "172.18.0.4/16"
}
}
}
Network Isolation
Containers on different networks can't communicate:
# Create a separate network
docker network create admin-network
# Start admin service on admin network
docker run -d \
--name admin-panel \
--network admin-network \
nginx
# admin-panel CANNOT reach shopflow-db
# shopflow services CANNOT reach admin-panel
This is useful for security - isolate admin tools from customer-facing services.
Multiple Networks
A container can be on multiple networks:
# Connect admin panel to both networks
docker network connect shopflow-network admin-panel
# Now admin-panel can reach both networks
Complete E-commerce Network
Here's a typical setup:
# Create networks
docker network create frontend-net
docker network create backend-net
docker network create data-net
# Database only on data network (most secure)
docker run -d --name shopflow-db --network data-net postgres:15
# API connects to backend and data
docker run -d --name product-api --network backend-net product-api:1.0
docker network connect data-net product-api
# Frontend connects to backend only
docker run -d --name web-store --network frontend-net -p 80:80 nginx
docker network connect backend-net web-store
┌─────────────────────────────────────────────────────────┐
│ frontend-net │
│ ┌───────────┐ │
│ │ web-store │──────────┐ │
│ │ :80 │ │ │
│ └───────────┘ │ │
└─────────────────────────┼───────────────────────────────┘
│
┌─────────────────────────┼───────────────────────────────┐
│ backend-net ▼ │
│ ┌─────────────────┐ │
│ │ product-api │──────────┐ │
│ │ :3000 │ │ │
│ └─────────────────┘ │ │
└────────────────────────────────────────────┼────────────┘
│
┌────────────────────────────────────────────┼────────────┐
│ data-net ▼ │
│ ┌─────────────────┐ │
│ │ shopflow-db │ │
│ │ :5432 │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────┘
Connection String Patterns
In your app code, use container names:
PostgreSQL:const connectionString = 'postgresql://shopflow:secretpass@shopflow-db:5432/shopflow';
Redis:
const redisUrl = 'redis://shopflow-cache:6379';
Another API:
const productApiUrl = 'http://product-api:3000/api/products';
Cleanup
# Remove containers
docker rm -f product-api shopflow-db shopflow-cache
# Remove network
docker network rm shopflow-network
# Remove all unused networks
docker network prune
Key Takeaways
- docker network create makes isolated networks
- Containers on the same network use names as hostnames
- --network connects at creation, network connect adds later
- Networks provide isolation and security
- Use multiple networks to segment your architecture
Next, let's learn about volumes to persist our product data!