Files
michaelschiemer/deployment/applications/docker-compose.production.yml
Michael Schiemer 9526034e18 Simplify Docker Compose to single-file architecture
- Convert multi-file overlay approach to single docker-compose.yml
- Use environment variables for dev/production differences
- Remove complex network configuration conflicts
- Align with framework principles: simplicity over complexity
- Production config via .env.production file

Benefits:
- No more network subnet conflicts
- Single source of truth
- Framework-compliant architecture
- Easier maintenance and debugging

Related: #19 Docker network conflict resolution
2025-09-12 23:36:05 +02:00

211 lines
5.4 KiB
YAML

# Production overlay for Custom PHP Framework
# Extends base docker-compose.yml with production optimizations
version: '3.8'
services:
web:
environment:
- APP_ENV=production
- PHP_IDE_CONFIG= # Remove IDE config in production
ports:
# Remove development ports, only expose HTTPS
- "${APP_SSL_PORT:-443}:443/tcp"
- "443:443/udp"
volumes:
# Read-only application code in production
- ./:/var/www/html:ro
- ./ssl:/var/www/ssl:ro
healthcheck:
test: ["CMD", "curl", "-f", "-k", "https://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels: "service=nginx,environment=production"
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
reservations:
memory: 128M
cpus: '0.25'
php:
environment:
APP_ENV: production
APP_DEBUG: false
PHP_IDE_CONFIG: "" # Remove IDE config
XDEBUG_MODE: off # Disable Xdebug in production
build:
args:
- ENV=production
- COMPOSER_INSTALL_FLAGS=--no-dev --optimize-autoloader --classmap-authoritative
user: "www-data:www-data" # Use www-data in production
volumes:
# Read-only application code
- ./:/var/www/html:ro
# Writable storage volumes
- storage-data:/var/www/html/storage:rw
- var-data:/var/www/html/var:rw
# Composer cache (but less aggressive caching in prod)
- composer-cache:/var/www/.composer/cache
healthcheck:
test: ["CMD", "php", "/var/www/html/public/health.php"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels: "service=php,environment=production"
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
reservations:
memory: 256M
cpus: '0.5'
db:
environment:
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
- MYSQL_DATABASE=${DB_DATABASE}
- MYSQL_USER=${DB_USERNAME}
- MYSQL_PASSWORD=${DB_PASSWORD}
ports: [] # No external ports in production
volumes:
- db_data:/var/lib/mysql
# Production MySQL configuration
- ./docker/mysql/conf.d/security.cnf:/etc/mysql/conf.d/security.cnf:ro
healthcheck:
test: ["CMD", "mariadb-admin", "ping", "-h", "127.0.0.1", "-u", "root", "-p${DB_ROOT_PASSWORD}"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels: "service=mariadb,environment=production"
deploy:
resources:
limits:
memory: 1G
cpus: '1.0'
reservations:
memory: 512M
cpus: '0.5'
redis:
volumes:
# Use secure Redis configuration in production
- ./docker/redis/redis-secure.conf:/usr/local/etc/redis/redis.conf:ro
- redis_data:/data
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels: "service=redis,environment=production"
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
reservations:
memory: 128M
cpus: '0.25'
queue-worker:
environment:
- APP_ENV=production
- APP_DEBUG=false
- WORKER_DEBUG=false
- WORKER_SLEEP_TIME=${WORKER_SLEEP_TIME:-100000}
- WORKER_MAX_JOBS=${WORKER_MAX_JOBS:-1000}
- WORKER_MEMORY_LIMIT=${WORKER_MEMORY_LIMIT:-384M}
build:
args:
- ENV=production
- COMPOSER_INSTALL_FLAGS=--no-dev --optimize-autoloader
user: "www-data:www-data"
volumes:
# Read-only application code
- ./:/var/www/html:ro
# Writable logs and storage
- ./storage/logs:/var/www/html/storage/logs:rw
- ./src/Framework/CommandBus/storage:/var/www/html/src/Framework/CommandBus/storage:rw
restart: always
stop_grace_period: 60s # Longer grace period for production
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels: "service=queue-worker,environment=production"
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
cpus: '0.25'
# Security-focused network configuration
networks:
frontend:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.24.0.0/24
backend:
driver: bridge
internal: true # Backend network is internal-only
ipam:
driver: default
config:
- subnet: 172.25.0.0/24
cache:
driver: bridge
internal: true # Cache network is internal-only
ipam:
driver: default
config:
- subnet: 172.26.0.0/24
volumes:
redis_data:
driver: local
composer-cache:
driver: local
storage-data:
driver: local
var-data:
driver: local
db_data:
driver: local