Overview
The distributed notification system uses Docker and Docker Compose to containerize all services and dependencies. This approach ensures consistent environments across development, testing, and production deployments.Containerization Strategy
The system employs a multi-container architecture with:- Multi-stage builds for Node.js services to minimize image sizes
- Official base images (Alpine Linux for Node.js, .NET 9.0 for C#, Python 3.12-slim)
- Production-optimized layers with separate build and runtime stages
- Health checks for critical infrastructure services
- Named volumes for persistent data storage
Docker Compose Services
Thedocker-compose.yml orchestrates 9 containers:
Application Services
| Service | Port Mapping | Technology | Description |
|---|---|---|---|
| api-gateway | 8000:8000 | Node.js 20 (Alpine) | Main entry point for notification requests |
| user-service | 8001:8081 | Node.js 20 (Alpine) | User management and preferences |
| template-service | 8002:8002 | Python 3.12 (FastAPI) | Notification template management |
| email-service | 8003:8080 | .NET 9.0 (C#) | Email notification processing |
| push-service | 8004:8004 | Node.js 20 (Alpine) | Push notification handling |
Infrastructure Services
| Service | Port Mapping | Image | Description |
|---|---|---|---|
| rabbitmq | 5673:5672, 15673:15672 | rabbitmq:3.11-management | Message broker for async communication |
| redis | 6379:6379 | redis:7-alpine | Caching and rate limiting |
| postgres | 5432:5432 | postgres:15 | Primary database |
| mailhog | 1025:1025, 8025:8025 | mailhog/mailhog | SMTP testing tool |
Network Configuration
All services communicate through a custom bridge network:- Services can reference each other by container name (e.g.,
http://user-service:8081) - Isolated from host network and other Docker networks
- Automatic DNS resolution between containers
Volume Management
Three named volumes persist data across container restarts:| Volume | Mount Point | Purpose |
|---|---|---|
pgdata | /var/lib/postgresql/data | PostgreSQL database files |
rabbitmq_data | /var/lib/rabbitmq | RabbitMQ queues and messages |
redis_data | /data | Redis cache and persistence |
Building and Running
Prerequisites
- Docker Engine 20.10+
- Docker Compose 2.0+
- 4GB+ available RAM
- 10GB+ available disk space
Build All Services
Start the System
- Infrastructure (postgres, redis, rabbitmq, mailhog)
- User Service and Template Service (depend on postgres)
- API Gateway, Email Service, Push Service (depend on infrastructure + user/template services)
Verify Services are Running
View Logs
Stop the System
Individual Dockerfile Highlights
API Gateway (api-gateway/Dockerfile)
Type: Multi-stage Node.js build
- Two-stage build separates compilation from runtime
npm ci --omit=devinstalls only production dependencies- Alpine base reduces image size (~120MB vs ~900MB for standard Node)
User Service (user-service/Dockerfile)
Type: Multi-stage Node.js build
Similar structure to API Gateway:
- Node.js 20 Alpine base
- Multi-stage build for optimization
- Production dependencies only in final stage
- Exposes port 8001
Template Service (template-service/Dockerfile)
Type: Single-stage Python build
- Python 3.12-slim reduces image size
--no-cache-dirprevents pip cache bloat- uvicorn ASGI server for FastAPI
Email Service (email-service/EmailService/Dockerfile)
Type: Multi-stage .NET build
- Three-stage build (build, publish, runtime)
- SDK image only used for compilation
- Minimal ASP.NET runtime for final image
- Exposes ports 8080 and 8081
Push Service (push-service/Dockerfile)
Type: Multi-stage Node.js build
Similar to API Gateway and User Service:
- Node.js 20 Alpine base
- Multi-stage optimization
- Exposes port 8004
- Command:
node dist/main.js
Health Checks
RabbitMQ includes a health check configuration:Best Practices
Use
.dockerignore files to exclude unnecessary files (node_modules, .git, etc.) from build contextsLayer caching optimization - Copy
package.json before source code to cache dependency installationMinimal base images - Alpine and slim variants significantly reduce image sizes and attack surface
Multi-stage builds - Separate build tools from runtime, keeping final images lean