#version: '3.8' # ============================================================================ # Recticel Quality Application - Docker Compose Configuration # Production-ready with mapped volumes for code, data, and backups # ============================================================================ services: # ========================================================================== # MariaDB Database Service # ========================================================================== db: image: mariadb:11.3 container_name: quality-app-db restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${DB_NAME} MYSQL_USER: ${DB_USER} MYSQL_PASSWORD: ${DB_PASSWORD} MYSQL_INNODB_BUFFER_POOL_SIZE: ${MYSQL_BUFFER_POOL} MYSQL_MAX_CONNECTIONS: ${MYSQL_MAX_CONNECTIONS} ports: - "${DB_PORT}:3306" volumes: # Database data persistence - CRITICAL: Do not delete this volume - ${DB_DATA_PATH}:/var/lib/mysql # Database initialization script - ./init-db.sql:/docker-entrypoint-initdb.d/01-init.sql:ro # Backup folder mapped for easy database dumps - ${BACKUP_PATH}:/backups networks: - quality-app-network healthcheck: test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] interval: 10s timeout: 5s retries: 5 start_period: 30s deploy: resources: limits: cpus: ${DB_CPU_LIMIT} memory: ${DB_MEMORY_LIMIT} reservations: cpus: ${DB_CPU_RESERVATION} memory: ${DB_MEMORY_RESERVATION} logging: driver: json-file options: max-size: ${LOG_MAX_SIZE} max-file: ${DB_LOG_MAX_FILES} # ========================================================================== # Flask Web Application Service # ========================================================================== web: build: context: . dockerfile: Dockerfile args: BUILD_DATE: ${BUILD_DATE} VERSION: ${VERSION} VCS_REF: ${VCS_REF} image: trasabilitate-quality-app:${VERSION} container_name: quality-app restart: unless-stopped depends_on: db: condition: service_healthy environment: # Database connection DB_HOST: ${DB_HOST} DB_PORT: ${DB_PORT} DB_NAME: ${DB_NAME} DB_USER: ${DB_USER} DB_PASSWORD: ${DB_PASSWORD} DB_MAX_RETRIES: ${DB_MAX_RETRIES} DB_RETRY_INTERVAL: ${DB_RETRY_INTERVAL} # Flask settings FLASK_ENV: ${FLASK_ENV} FLASK_APP: run.py SECRET_KEY: ${SECRET_KEY} # Gunicorn settings GUNICORN_WORKERS: ${GUNICORN_WORKERS} GUNICORN_WORKER_CLASS: ${GUNICORN_WORKER_CLASS} GUNICORN_TIMEOUT: ${GUNICORN_TIMEOUT} GUNICORN_BIND: ${GUNICORN_BIND} GUNICORN_LOG_LEVEL: ${GUNICORN_LOG_LEVEL} GUNICORN_PRELOAD_APP: ${GUNICORN_PRELOAD_APP} GUNICORN_MAX_REQUESTS: ${GUNICORN_MAX_REQUESTS} # Initialization flags INIT_DB: ${INIT_DB} SEED_DB: ${SEED_DB} IGNORE_DB_INIT_ERRORS: ${IGNORE_DB_INIT_ERRORS} IGNORE_SEED_ERRORS: ${IGNORE_SEED_ERRORS} SKIP_HEALTH_CHECK: ${SKIP_HEALTH_CHECK} # Localization TZ: ${TZ} LANG: ${LANG} # Backup path BACKUP_PATH: ${BACKUP_PATH} ports: - "${APP_PORT}:8781" volumes: # Application code - mapped for easy updates without rebuilding - ${APP_CODE_PATH}:/app # Application logs - persistent across container restarts - ${LOGS_PATH}:/srv/quality_app/logs # Instance configuration files (database config) - ${INSTANCE_PATH}:/app/instance # Backup storage - shared with database container - ${BACKUP_PATH}:/srv/quality_app/backups # Host /data folder for direct access (includes /data/backups) - /data:/data networks: - quality-app-network healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8781/"] interval: 30s timeout: 10s retries: 3 start_period: 60s deploy: resources: limits: cpus: ${APP_CPU_LIMIT} memory: ${APP_MEMORY_LIMIT} reservations: cpus: ${APP_CPU_RESERVATION} memory: ${APP_MEMORY_RESERVATION} logging: driver: json-file options: max-size: ${LOG_MAX_SIZE} max-file: ${LOG_MAX_FILES} compress: "true" # ============================================================================ # Network Configuration # ============================================================================ networks: quality-app-network: driver: bridge ipam: config: - subnet: ${NETWORK_SUBNET} # ============================================================================ # USAGE NOTES # ============================================================================ # VOLUME STRUCTURE: # ./data/mariadb/ - Database files (MariaDB data directory) # ./config/instance/ - Application configuration (external_server.conf) # ./logs/ - Application logs # ./backups/ - Database backups # ./py_app/ - (Optional) Application code for development # # FIRST TIME SETUP: # 1. Create directory structure: # mkdir -p data/mariadb config/instance logs backups # 2. Copy .env.example to .env and customize all values # 3. Set INIT_DB=true and SEED_DB=true in .env for first deployment # 4. Change default passwords and SECRET_KEY in .env (CRITICAL!) # 5. Build and start: docker-compose up -d --build # # SUBSEQUENT DEPLOYMENTS: # 1. Set INIT_DB=false and SEED_DB=false in .env # 2. Start: docker-compose up -d # # COMMANDS: # - Build and start: docker-compose up -d --build # - Stop: docker-compose down # - Stop & remove data: docker-compose down -v (WARNING: deletes database!) # - View logs: docker-compose logs -f web # - Database logs: docker-compose logs -f db # - Restart: docker-compose restart # - Rebuild image: docker-compose build --no-cache web # # BACKUP: # - Manual backup: docker-compose exec db mysqldump -u trasabilitate -p trasabilitate > backups/manual_backup.sql # - Restore: docker-compose exec -T db mysql -u trasabilitate -p trasabilitate < backups/backup.sql # # DATABASE ACCESS: # - MySQL client: docker-compose exec db mysql -u trasabilitate -p trasabilitate # - From host: mysql -h 127.0.0.1 -P 3306 -u trasabilitate -p # ============================================================================