Multi-Tier Architectures
LEVEL 0
The Problem
Modern applications aren’t monoliths. They’re composed of multiple services:
- Presentation tier: Web servers, load balancers, reverse proxies
- Application tier: API servers, microservices, business logic
- Data tier: Databases, caches, message queues
- Background tier: Workers, schedulers, batch processors
Each tier has different requirements:
- Presentation needs to be internet-accessible
- Application needs to talk to presentation and data tiers
- Data tier should NOT be internet-accessible
- Background tier processes jobs asynchronously
How do you architect the networks so:
- Each tier can communicate with the tiers it needs?
- Tiers that shouldn’t communicate are isolated?
- Security boundaries are enforced?
- The architecture is maintainable and scalable?
LEVEL 1
The Concept — The Office Tower
The Concept
Imagine an office building with multiple floors:
Ground Floor (Presentation): Reception, customer service, showroom. Public access. Anyone can walk in.
Floors 2-5 (Application): Employee offices, meeting rooms. Employees can access, but customers can’t just walk up.
Basement (Data): Server room, archives, vault. Only authorized IT staff can access. No public access at all.
Sub-basement (Background): Building systems, HVAC, electrical. Automated systems that keep the building running. Separate from public areas.
The elevators and stairwells are the networks connecting these floors. Some elevators go to all floors (like an API server), while others only go to specific floors (like a database that’s only in the basement).
LEVEL 2
The Mechanics — Designing Multi-Tier Networks
The Mechanics
Tier 1: Presentation (DMZ)
Services that face the internet:
- Load balancers
- Reverse proxies
- Static file servers
- Web frontends
Network setup:
docker network create dmz-tier
# Load balancer exposed to internet
docker run -d \
--name lb \
--network dmz-tier \
-p 80:80 -p 443:443 \
nginx
# Web frontend
docker run -d \
--name web \
--network dmz-tier \
my-web-frontend
Tier 2: Application
Services with business logic:
- API servers
- Microservices
- Application backends
Network setup:
docker network create app-tier
# Connect web to app tier (bridge between DMZ and app)
docker network connect app-tier web
# API servers
docker run -d \
--name api-user-service \
--network app-tier \
user-service-api
docker run -d \
--name api-order-service \
--network app-tier \
order-service-api
Tier 3: Data
Persistent storage and caches:
- Databases
- Redis/Memcached
- Message queues
Network setup:
docker network create data-tier --internal
# Connect API services to data tier
docker network connect data-tier api-user-service
docker network connect data-tier api-order-service
# Database
docker run -d \
--name postgres \
--network data-tier \
-v pgdata:/var/lib/postgresql/data \
postgres:15
# Cache
docker run -d \
--name redis \
--network data-tier \
redis:7
Tier 4: Background
Asynchronous processing:
- Workers
- Schedulers
- Batch jobs
Network setup:
docker network create background-tier
# Workers need access to data tier
docker run -d \
--name worker-email \
--network background-tier \
email-worker
docker network connect data-tier worker-email
# Scheduler
docker run -d \
--name scheduler \
--network background-tier \
cron-scheduler
docker network connect data-tier scheduler
LEVEL 3
Complete Multi-Tier Architecture Example
Let’s build a complete e-commerce application with proper network segmentation:
#!/bin/bash
# Create networks
docker network create dmz-network
docker network create app-network
docker network create data-network --internal
docker network create worker-network
# --- DMZ TIER (Internet-facing) ---
# Nginx load balancer (only component exposed to internet)
docker run -d \
--name lb \
--network dmz-network \
-p 80:80 -p 443:443 \
--restart unless-stopped \
nginx:alpine
# React frontend (on DMZ and app networks)
docker run -d \
--name frontend \
--network dmz-network \
--restart unless-stopped \
my-ecommerce-frontend:latest
docker network connect app-network frontend
# --- APPLICATION TIER ---
# User service API
docker run -d \
--name api-users \
--network app-network \
--restart unless-stopped \
-e DATABASE_URL=postgres://db:5432/users \
my-user-service:latest
docker network connect data-network api-users
# Product service API
docker run -d \
--name api-products \
--network app-network \
--restart unless-stopped \
-e DATABASE_URL=postgres://db:5432/products \
my-product-service:latest
docker network connect data-network api-products
# Order service API
docker run -d \
--name api-orders \
--network app-network \
--restart unless-stopped \
-e DATABASE_URL=postgres://db:5432/orders \
-e REDIS_URL=redis://cache:6379 \
my-order-service:latest
docker network connect data-network api-orders
# --- DATA TIER (Internal only) ---
# PostgreSQL database
docker run -d \
--name db \
--network data-network \
--restart unless-stopped \
-e POSTGRES_PASSWORD=secret \
-v pgdata:/var/lib/postgresql/data \
postgres:15
# Redis cache
docker run -d \
--name cache \
--network data-network \
--restart unless-stopped \
redis:7
# RabbitMQ message queue
docker run -d \
--name queue \
--network data-network \
--restart unless-stopped \
rabbitmq:3-management
# --- WORKER TIER ---
# Email worker (needs queue and database access)
docker run -d \
--name worker-email \
--network worker-network \
--restart unless-stopped \
my-email-worker:latest
docker network connect data-network worker-email
# Image processing worker
docker run -d \
--name worker-images \
--network worker-network \
--restart unless-stopped \
my-image-worker:latest
docker network connect data-network worker-images
# Order fulfillment worker
docker run -d \
--name worker-fulfillment \
--network worker-network \
--restart unless-stopped \
my-fulfillment-worker:latest
docker network connect data-network worker-fulfillment
echo "Multi-tier architecture deployed!"
echo "Access at: http://localhost"
Network flow:
Internet → lb (DMZ only)
→ frontend (DMZ + app)
→ api-users (app + data)
→ api-products (app + data)
→ api-orders (app + data)
→ db (data only)
→ cache (data only)
→ queue (data only)
→ workers (worker + data)
Security boundaries enforced:
- Internet can only reach
lb - Frontend can reach APIs but NOT database
- APIs can reach database (controlled access)
- Workers process asynchronously, isolated from DMZ
- Database is on internal network, can’t reach internet
LEVEL 4
Scaling Multi-Tier Architectures
Horizontal scaling: Add more replicas
# Scale API servers
docker run -d --name api-users-2 --network app-network my-user-service
docker network connect data-network api-users-2
docker run -d --name api-users-3 --network app-network my-user-service
docker network connect data-network api-users-3
# Load balancer distributes traffic
Using Docker Compose for multi-tier deployments:
version: '3.8'
networks:
dmz-tier:
app-tier:
data-tier:
internal: true
services:
lb:
image: nginx
networks:
- dmz-tier
ports:
- "80:80"
- "443:443"
frontend:
image: my-frontend
networks:
- dmz-tier
- app-tier
api-users:
image: my-user-api
networks:
- app-tier
- data-tier
deploy:
replicas: 3
api-products:
image: my-product-api
networks:
- app-tier
- data-tier
deploy:
replicas: 2
database:
image: postgres:15
networks:
- data-tier
volumes:
- pgdata:/var/lib/postgresql/data
cache:
image: redis:7
networks:
- data-tier
volumes:
pgdata:
LEVEL 5
Monitoring and Observability
In multi-tier architectures, you need visibility into network traffic:
Tools for network monitoring:
- cAdvisor (Container metrics)
- Prometheus (Metrics collection)
- Grafana (Visualization)
- Jaeger (Distributed tracing)
These tools typically run on their own monitoring network with access to all tiers:
docker network create monitoring-network
# Prometheus
docker run -d \
--name prometheus \
--network monitoring-network \
prom/prometheus
# Connect monitoring to each tier
docker network connect dmz-network prometheus
docker network connect app-network prometheus
docker network connect data-network prometheus