# Multi-Tenant Optimized Docker Compose # Supports running multiple isolated app instances with direct Docker host port binding # Each instance: ~50MB base + 20-30MB per 20 users # # Usage: # docker-compose -f docker-compose-multitenant.yml up -d # # Example: Start the stack and expose the app on host port 10000 # INVENTAR_HTTP_PORT=10000 docker-compose -f docker-compose-multitenant.yml up -d services: # Management Container for multi-tenant scripts tenant-manager: image: python:3.12-alpine container_name: tenant-manager restart: "no" profiles: - tools volumes: - /var/run/docker.sock:/var/run/docker.sock - .:/workspace entrypoint: > sh -c "apk add --no-cache bash docker-cli docker-cli-compose && cd /workspace && ./manage-tenant.sh \"$$@\"" -- 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 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", "1000", "--max-requests-jitter", "100", "--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 ports: - "${INVENTAR_HTTP_PORT:-10000}:8000" 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 INVENTAR_CONFIG_PATH: /app/config.json # Redis Configuration (for sessions and caching) INVENTAR_REDIS_HOST: redis INVENTAR_REDIS_PORT: "6379" INVENTAR_REDIS_DB: "0" INVENTAR_TENANT_PORT_MAP: "${INVENTAR_TENANT_PORT_MAP:-}" # Storage Configuration INVENTAR_BACKUP_FOLDER: /data/backups INVENTAR_LOGS_FOLDER: /data/logs INVENTAR_DELETED_ARCHIVE_FOLDER: /data/deleted-archives # Performance Tuning INVENTAR_WORKER_CLASS: ${INVENTAR_WORKER_CLASS:-gevent} INVENTAR_WORKERS: "${INVENTAR_WORKERS:-4}" INVENTAR_THREADS: "${INVENTAR_THREADS:-2}" INVENTAR_WORKER_TIMEOUT: "${INVENTAR_WORKER_TIMEOUT:-30}" INVENTAR_WORKER_CONNECTIONS: "${INVENTAR_WORKER_CONNECTIONS:-100}" # Auto-scaled runtime settings INVENTAR_APP_CPUS: ${INVENTAR_APP_CPUS:-1.0} INVENTAR_APP_MEM_LIMIT: ${INVENTAR_APP_MEM_LIMIT:-256m} INVENTAR_APP_MEM_SWAP_LIMIT: ${INVENTAR_APP_MEM_SWAP_LIMIT:-512m} # 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: "${INVENTAR_APP_MEM_LIMIT:-256m}" memswap_limit: "${INVENTAR_APP_MEM_SWAP_LIMIT:-512m}" cpus: "${INVENTAR_APP_CPUS:-1.0}" # Health check for load balancer healthcheck: test: [ "CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=5).read(); print('OK')" ] 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