18 KiB
Architecture Patterns
Domain: Docker-based Cloud Lab Environments for Education Researched: 2026-03-24 Confidence: HIGH
Recommended Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ Docker Host System │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Student/Developer Interface │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Terminal/SSH │ │ Browser │ │ Git Client │ │ │
│ │ │ (docker cli) │ │ (Web Console)│ │ (Versioning) │ │ │
│ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │
│ └─────────┼─────────────────┼─────────────────┼─────────────────┘ │
├────────────┼─────────────────┼─────────────────┼─────────────────────┤
│ │ │ │ │
│ ┌─────────▼─────────────────▼─────────────────▼─────────────────┐ │
│ │ Docker Engine (v24.0+) │ │
│ │ Container Orchestration │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────┼───────────────────────────────────┐ │
│ │ │ │ │
│ │ ┌────────────────────────▼─────────────────────────────┐ │ │
│ │ │ Docker Compose (Project Level) │ │ │
│ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │ │ │
│ │ │ │ Lab 1 │ │ Lab 2 │ │ Lab 3 │ │ Lab 4 │ │ │ │
│ │ │ │ IAM │ │ Network │ │ Compute │ │Storage │ │ │ │
│ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └───┬────┘ │ │ │
│ │ └───────┼─────────────┼─────────────┼─────────────┼──────┘ │ │
│ └──────────┼─────────────┼─────────────┼─────────────┼───────────┘ │
│ │ │ │ │ │
│ ┌──────────▼─────────────▼─────────────▼─────────────▼───────────┐ │
│ │ Docker Networks Layer │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ Public Network │ │ Private Net 1 │ │ Private Net 2 │ │ │
│ │ │ (bridge) │ │ (isolated) │ │ (isolated) │ │ │
│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────▼───────────────────────────────────┐ │
│ │ Storage Layer │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │ │
│ │ │ Named Volume │ │ Named Volume │ │ Bind Mounts │ │ │
│ │ │ (Block) │ │ (Object) │ │ (Config/Scripts) │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Component Boundaries
| Component | Responsibility | Communicates With |
|---|---|---|
| Docker Engine | Container lifecycle, image management, network isolation | Docker CLI, Docker Compose |
| Docker Compose | Multi-container orchestration per lab, service dependencies | Docker Engine, docker-compose.yml files |
| Bridge Networks | VPC/Subnet simulation, network isolation, DNS resolution | Containers within same network only |
| Named Volumes | Persistent data storage (DB, Object Storage), data isolation | Containers mounting specific volumes |
| Test Containers | Network connectivity verification, service health checks | Target services via internal DNS |
| Student Workspace | Git repo, lab documentation, test scripts | Docker CLI via socket |
Data Flow
1. Lab Initialization:
Student → git checkout lab-XX-network
↓
Student → docker compose up -d
↓
Docker Compose → Parse compose.yml
↓
Docker Engine → Create networks (public, private-a, private-b)
↓
Docker Engine → Create volumes (data-b, logs)
↓
Docker Engine → Start containers (attach to networks)
↓
Containers → Internal DNS resolution (service names)
2. Cross-Network Communication (VPC Simulation):
Container A (Public Net) → curl http://backend:8080
↓
Docker Internal DNS → Resolve backend to 10.0.1.2
↓
Network Layer → Check routing table
↓
[Different networks] → REJECT (no route)
↓
[Same network] → Allow → Container B receives request
3. Persistent Storage Flow:
Container (PostgreSQL) → Write to /var/lib/postgresql/data
↓
Volume Mount (named volume: db-data)
↓
Docker Volume Driver → Store in /var/lib/docker/volumes/db-data/_data
↓
Container restart → Data persists
↓
docker compose down -v → Volume removed
Patterns to Follow
Pattern 1: Network Isolation for VPC Simulation
What: Use multiple bridge networks to simulate VPC public/private subnets. Containers in different networks cannot communicate unless explicitly connected.
When: All network labs, security isolation demonstrations, multi-tier applications.
Example:
# docker-compose.yml
networks:
public-subnet:
driver: bridge
ipam:
config:
- subnet: 10.0.1.0/24
private-subnet:
driver: bridge
internal: true # No internet access
ipam:
config:
- subnet: 10.0.2.0/24
services:
web-server:
networks:
- public-subnet
- private-subnet # Can talk to both
database:
networks:
- private-subnet # Only private
Pattern 2: Resource Limits for Compute Quota
What: Enforce CPU and memory limits at container level to simulate cloud instance sizes (t3.micro, t3.small, etc.).
When: Compute labs, performance testing, resource isolation demos.
Example:
services:
app-tier:
deploy:
resources:
limits:
cpus: '0.5' # 0.5 vCPU = t3.micro equivalent
memory: 512M # 512MB RAM
reservations:
cpus: '0.25'
memory: 256M
Pattern 3: Healthcheck for Service Readiness
What: Use built-in HEALTHCHECK directive to ensure services are ready before dependent containers start.
When: Multi-tier applications, database-dependent services, testing labs.
Example:
services:
postgres:
healthcheck:
test: ["CMD", "pg_isready", "-U", "admin"]
interval: 5s
timeout: 3s
retries: 5
app:
depends_on:
postgres:
condition: service_healthy
Pattern 4: Volume Initialization with Seed Data
What: Use init containers or volume pre-population to create databases with initial schema/data.
When: Database labs, storage testing, demonstration environments.
Example:
services:
db-init:
image: postgres:15
volumes:
- db-data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
environment:
POSTGRES_DB: labdb
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
Pattern 5: Test Container Pattern
What: Create lightweight "probe" containers to verify network isolation and connectivity.
When: Network labs, security testing, isolation verification.
Example:
# test-connectivity.yml
services:
probe-public:
image: nicolaka/netshoot
networks:
- public-subnet
command: |
sh -c "nc -zv web-server 80 &&
nc -zv minio 9000 &&
! nc -zv database 5432" # Should fail
Anti-Patterns to Avoid
Anti-Pattern 1: Using Default Bridge Network
What: Not defining custom networks, letting containers use the default bridge network.
Why bad: Containers communicate without restriction, no DNS resolution by name, poor security simulation.
Instead: Always create named bridge networks with explicit subnets.
Anti-Pattern 2: Running Containers as Root
What: Not specifying user: directive in Dockerfile or compose file.
Why bad: Security vulnerability, violates cloud best practices (no root in production).
Instead: Use user: "1000:1000" or create users in Dockerfile.
Anti-Pattern 3: Exposing All Ports to Host
What: Using ports: ["8080:8080"] for all services.
Why bad: Port conflicts, security exposure, breaks isolation simulation.
Instead: Only expose public-facing services. Use internal networking for backend.
Anti-Pattern 4: Anonymous Volumes for Persistent Data
What: Letting Docker create anonymous volumes without naming.
Why bad: Difficult to manage, can't backup easily, hard to reference.
Instead: Always use named volumes in compose file.
Anti-Pattern 5: No Resource Limits
What: Running containers without CPU/memory constraints.
Why bad: No cloud quota simulation, one container can starve others, unrealistic behavior.
Instead: Always set limits matching simulated instance sizes.
Scalability Considerations
| Concern | Single Student Lab | Classroom (20 students) | Online Course (1000+) |
|---|---|---|---|
| Docker Daemon | Single instance sufficient | Local daemon per machine | Consider Docker-in-Docker or VMs |
| Network Overhead | Negligible | < 50 networks per host | Use network cleanup between labs |
| Storage | Named volumes on host | Same, per student machine | Cloud storage for container images |
| Resource Limits | Not critical | Important to prevent host OOM | Enforce quotas via Docker daemon limits |
Build Order Implications
Phase 1: Foundation (Prerequisites)
- Docker Engine + Docker Compose installation
- Base network setup (public/private networks)
- Volume structure creation
Phase 2: IAM & Security (Lab 1)
- Independent, can run parallel
- No dependencies on other labs
- Tests: user permissions, Docker socket access
Phase 3: Network (Lab 2)
- Depends on: Docker Engine understanding
- Enables: All subsequent labs
- Tests: Network isolation, DNS resolution
Phase 4: Compute (Lab 3)
- Depends on: Network (for service communication)
- Enables: Multi-tier applications
- Tests: Resource limits, health checks
Phase 5: Storage (Lab 4)
- Depends on: Network (for access patterns)
- Independent from: Compute
- Tests: Volume persistence, permissions
Phase 6: Database (Lab 5)
- Depends on: Network (VPC simulation), Storage (volumes)
- Culmination: Multi-tier architecture
- Tests: Cross-network communication, persistence
Lab Environment Structure
Recommended Directory Layout
laboratori-cloud/
├── .planning/ # Project planning
│ ├── PROJECT.md # Project requirements
│ └── research/ # Research documents
├── labs/ # Individual labs
│ ├── lab-01-iam/
│ │ ├── docker-compose.yml
│ │ ├── README.md # Tutorial
│ │ ├── how-to/ # How-to guides
│ │ ├── reference/ # Technical specs
│ │ ├── tests/ # Test scripts
│ │ │ ├── test-iam-setup.sh
│ │ │ └── verify-permissions.sh
│ │ └── docs/ # Explanation documents
│ ├── lab-02-network/
│ │ ├── docker-compose.yml
│ │ ├── networks.yml # Network definitions
│ │ ├── README.md
│ │ ├── tests/
│ │ │ ├── test-isolation.sh
│ │ │ └── test-routing.sh
│ │ └── docs/
│ ├── lab-03-compute/
│ │ ├── docker-compose.yml
│ │ ├── Dockerfile # Custom image
│ │ ├── README.md
│ │ ├── tests/
│ │ │ ├── test-resources.sh
│ │ │ └── test-oom.sh
│ │ └── docs/
│ ├── lab-04-storage/
│ │ ├── docker-compose.yml
│ │ ├── README.md
│ │ ├── tests/
│ │ │ ├── test-volumes.sh
│ │ │ └── test-minio.sh
│ │ └── docs/
│ └── lab-05-database/
│ ├── docker-compose.yml
│ ├── init.sql
│ ├── README.md
│ ├── tests/
│ │ ├── test-connectivity.sh
│ │ └── test-persistence.sh
│ └── docs/
├── shared/ # Shared resources
│ ├── base-images/ # Custom base images
│ ├── test-utils/ # Common test utilities
│ └── monitoring/ # Optional monitoring tools
├── ARCHITECTURE.md # This document
├── CLAUDE.md # Development manifesto
└── PRD.md # Product requirements
Security Architecture
Isolation Layers
- Host Level: User namespaces, AppArmor profiles
- Network Level: Bridge networks, iptables rules
- Container Level: Non-root users, read-only filesystems
- Resource Level: CPU/memory limits, disk quotas
Authentication Simulation
Local IAM (Lab 1) Cloud IAM (Parallel)
├── Linux users ├── AWS IAM Users
├── Unix groups ├── IAM Groups
├── Docker socket permissions ├── IAM Roles
└── SSH key pairs ├── Access Keys
Sources
HIGH Confidence (Official Documentation)
- Docker Networking Documentation - https://docs.docker.com/engine/network/ - Bridge networks, internal networks, DNS resolution
- Docker Compose Documentation - https://docs.docker.com/compose/ - Multi-container orchestration, service dependencies
- Docker Storage Documentation - https://docs.docker.com/storage/volumes/ - Named volumes, bind mounts, data persistence
- MinIO Documentation - https://min.io/docs/minio/linux/index.html - S3-compatible object storage for local simulation
MEDIUM Confidence (Best Practices)
- Docker Security Best Practices - Container hardening, user namespaces
- Cloud Lab Environment Patterns - Educational infrastructure simulation
- Multi-stage Docker Builds - Image optimization for labs
Project Context
- .planning/PROJECT.md - Project requirements and lab structure
- laboratori-cloud/prd.md - Detailed lab specifications and learning objectives
Architecture research for: Docker-based Cloud Lab Environments Researched: 2026-03-24