# Multi-Tenant Optimized Docker Compose # Supports running multiple isolated app instances per subdomain # Each instance: ~50MB base + 20-30MB per 20 users # # Usage: # docker-compose -f docker-compose-multitenant.yml up -d # # Scale example: To support 10 tenants with 20 users each: # docker-compose -f docker-compose-multitenant.yml up -d --scale app=10 services: cloudflared: image: cloudflare/cloudflared:latest container_name: cloudflared restart: unless-stopped profiles: - cloudflare command: ["--config", "/etc/cloudflared/config.yml", "tunnel", "run"] volumes: - ./docker/cloudflared/config.yml:/etc/cloudflared/config.yml:ro - /etc/cloudflared/credentials.json:/etc/cloudflared/credentials.json:ro depends_on: nginx: condition: service_started networks: - inventar-net # Management Container for multi-tenant scripts tenant-manager: image: docker:cli container_name: tenant-manager restart: "no" profiles: - tools volumes: - /var/run/docker.sock:/var/run/docker.sock - .:/workspace entrypoint: ["sh", "-c", "cd /workspace && ./manage-tenant.sh \"$$@\"", "--"] nginx: image: nginx:1.27-alpine container_name: inventarsystem-nginx restart: unless-stopped depends_on: app: condition: service_started redis: condition: service_started ports: - "${INVENTAR_HTTP_PORT:-80}:80" - "${INVENTAR_HTTPS_PORT:-443}:443" volumes: - ./docker/nginx/multitenant.conf:/etc/nginx/conf.d/default.conf:ro - ./certs:/etc/nginx/certs:ro - ./docker/nginx/acme:/etc/nginx/acme:ro networks: - inventar-net healthcheck: test: ["CMD", "wget", "-q", "-O-", "http://localhost/health"] interval: 30s timeout: 5s retries: 3 environment: NGINX_WORKER_PROCESSES: auto NGINX_WORKER_CONNECTIONS: 1024 redis: image: redis:7-alpine container_name: inventarsystem-redis restart: unless-stopped command: redis-server --appendonly yes --maxmemory 512mb --maxmemory-policy allkeys-lru ports: - "6379:6379" volumes: - redis_data:/data networks: - inventar-net healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 mongodb: image: mongo:7.0 container_name: inventarsystem-mongodb restart: unless-stopped command: mongod --wiredTigerCacheSizeGB 2 expose: - "27017" volumes: - mongodb_data:/data/db - ./docker/mongo:/docker-entrypoint-initdb.d:ro networks: - inventar-net healthcheck: test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"] interval: 10s timeout: 5s retries: 10 environment: MONGO_INITDB_DATABASE: inventar_default app: build: context: . dockerfile: Dockerfile args: PYTHON_VERSION: "3.13" OPTIMIZATION_LEVEL: 2 working_dir: /app/Web command: ["gunicorn", "app:app", "--bind", "0.0.0.0:8000", "--workers", "2", "--timeout", "30", "--graceful-timeout", "20", "--max-requests", "200", "--max-requests-jitter", "50", "--log-level", "info", "--access-logfile", "-", "--error-logfile", "-"] restart: unless-stopped security_opt: - no-new-privileges:true depends_on: mongodb: condition: service_healthy redis: condition: service_healthy networks: - inventar-net expose: - "8000" volumes: - ./config.json:/app/config.json:ro - app_uploads:/app/Web/uploads:cached - app_thumbnails:/app/Web/thumbnails:cached - app_previews:/app/Web/previews:cached - app_qrcodes:/app/Web/QRCodes:cached - app_backups:/data/backups - app_logs:/data/logs - app_deleted_archives:/data/deleted-archives environment: # Database Configuration INVENTAR_MONGODB_HOST: mongodb INVENTAR_MONGODB_PORT: "27017" INVENTAR_MONGODB_DB: inventar_default # Redis Configuration (for sessions and caching) INVENTAR_REDIS_HOST: redis INVENTAR_REDIS_PORT: "6379" INVENTAR_REDIS_DB: "0" # Storage Configuration INVENTAR_BACKUP_FOLDER: /data/backups INVENTAR_LOGS_FOLDER: /data/logs INVENTAR_DELETED_ARCHIVE_FOLDER: /data/deleted-archives # Performance Tuning INVENTAR_WORKER_CLASS: gevent INVENTAR_WORKERS: "4" INVENTAR_THREADS: "2" INVENTAR_WORKER_TIMEOUT: "30" INVENTAR_WORKER_CONNECTIONS: "100" # Multi-Tenant INVENTAR_MULTITENANT_ENABLED: "true" INVENTAR_SESSION_BACKEND: redis # Logging INVENTAR_LOG_LEVEL: WARNING # Flask FLASK_ENV: production FLASK_DEBUG: "0" # Python Optimization PYTHONOPTIMIZE: "2" PYTHONDONTWRITEBYTECODE: "1" PYTHONUNBUFFERED: "1" # Resource Limits (per instance) # With 10 instances: each gets ~150MB, totaling ~1.5GB # Adjust based on server resources mem_limit: 256m memswap_limit: 512m cpus: "1.0" # Health check for load balancer healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s volumes: mongodb_data: driver: local redis_data: driver: local app_uploads: driver: local app_thumbnails: driver: local app_previews: driver: local app_qrcodes: driver: local app_backups: driver: local app_logs: driver: local app_deleted_archives: driver: local networks: inventar-net: driver: bridge # Scale guidance: # 1 tenant (20 users): 1 app instance + redis + mongodb = ~500MB # 5 tenants: 5 app instances + shared redis/mongodb = ~1.5GB # 10 tenants: 10 app instances + shared redis/mongodb = ~2.5GB # 20 tenants: 20 app instances + shared redis/mongodb = ~4.5GB # # Server sizing recommendations: # - Small (1-2 tenants): 2GB RAM, 1-2 CPU cores # - Medium (5-10 tenants): 4GB RAM, 2-4 CPU cores # - Large (10-20 tenants): 8GB RAM, 4-8 CPU cores # - Jumbo (20+ tenants): 16GB+ RAM, 8+ CPU cores with clustering