fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled

This commit is contained in:
2025-11-24 21:28:25 +01:00
parent 4eb7134853
commit 77abc65cd7
1327 changed files with 91915 additions and 9909 deletions

View File

@@ -0,0 +1,370 @@
# Production Environment Override
# Usage: docker-compose -f docker-compose.base.yml -f docker-compose.production.yml --env-file .env.production up -d
#
# This file overrides base configuration with production-specific settings:
# - Stricter resource limits
# - Production restart policies (always)
# - JSON logging with proper rotation
# - No host mounts (security)
# - Production PostgreSQL configuration
# - Certbot for SSL certificates
# - Production port mappings (80, 443 for Let's Encrypt)
services:
web:
# Use pre-built image from registry (override build from base)
image: localhost:5000/framework:latest
# Build section removed - production-base.yml has no build sections
# Production restart policy
restart: always
# Note: Port mappings removed - Traefik handles all external routing
# No direct port bindings needed, Traefik proxies traffic to this container
# Override volumes - use Let's Encrypt certificates and mount application code
volumes:
- certbot-conf:/etc/letsencrypt:ro
- certbot-www:/var/www/certbot:ro
# Application code via rsync deployment
- /home/deploy/michaelschiemer/current:/var/www/html:ro
environment:
- APP_ENV=production
- APP_DEBUG=false
# Security hardening
# Note: no-new-privileges prevents PHP-FPM from switching to www-data
# We need to allow privilege escalation for PHP-FPM user switching
# security_opt:
# - no-new-privileges:true
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_OVERRIDE
- NET_BIND_SERVICE # Required for binding to ports 80/443
- SETGID # Required for PHP-FPM to switch to www-data
- SETUID # Required for PHP-FPM to switch to www-data
# Stricter health checks for production
healthcheck:
test: ["CMD", "curl", "-f", "https://localhost/health"]
interval: 15s
timeout: 5s
retries: 5
start_period: 30s
# JSON logging with rotation
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
compress: "true"
labels: "service,environment"
# Production resource limits (Nginx is lightweight)
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
reservations:
memory: 256M
cpus: '0.5'
depends_on:
php:
condition: service_healthy
certbot:
condition: service_started
php:
# Use pre-built image from registry (override build from base)
image: localhost:5000/framework:latest
# Build section removed - production-base.yml has no build sections
# Production restart policy
restart: always
# Override user setting - container must start as root for gosu to work
# The entrypoint script will use gosu to switch to appuser after setup
user: "root"
# Security hardening (applied after gosu switches to appuser)
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_OVERRIDE
# Load environment variables from .env file (generated by Ansible)
# Use absolute path to ensure .env is found regardless of working directory
env_file:
- /home/deploy/deployment/stacks/production/.env
environment:
- APP_ENV=production
- APP_DEBUG=false
- PHP_MEMORY_LIMIT=512M
- PHP_MAX_EXECUTION_TIME=30
# Disable Xdebug in production
- XDEBUG_MODE=off
# Use Docker Secrets via *_FILE pattern (Framework supports this automatically)
- DB_PASSWORD_FILE=/run/secrets/db_user_password
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
- APP_KEY_FILE=/run/secrets/app_key
- VAULT_ENCRYPTION_KEY_FILE=/run/secrets/vault_encryption_key
secrets:
- db_user_password
- redis_password
- app_key
- vault_encryption_key
# Stricter health checks
healthcheck:
test: ["CMD", "php", "-v"]
interval: 15s
timeout: 5s
retries: 5
start_period: 30s
# JSON logging
logging:
driver: json-file
options:
max-size: "10m"
max-file: "10"
compress: "true"
labels: "service,environment"
# Production resource limits
deploy:
resources:
limits:
memory: 1G
cpus: '2.0'
reservations:
memory: 512M
cpus: '1.0'
# Production volumes
volumes:
# Mount application code from rsync deployment (read-write for storage/var directories)
- /home/deploy/michaelschiemer/current:/var/www/html:rw
# Database service removed - using external PostgreSQL Stack (deployment/stacks/postgresql/)
# Connection via app-internal network using docker-compose.postgres-override.yml
# Redis service removed - using external Redis Stack (deployment/stacks/redis/)
# Connection via app-internal network using docker-compose.redis-override.yml
queue-worker:
# Use pre-built image from registry (override build from base)
image: localhost:5000/framework:latest
# Build section removed - production-base.yml has no build sections
# Production restart policy
restart: always
# Override user setting - container must start as root for gosu to work
# The entrypoint script will use gosu to switch to appuser after setup
user: "root"
# Override entrypoint to skip PHP-FPM/Nginx startup - queue-worker only needs PHP CLI
entrypoint: ""
# Worker command - direct PHP execution
command: ["php", "/var/www/html/worker.php"]
# Production volumes
volumes:
# Mount application code from rsync deployment (read-write for storage/var directories)
- /home/deploy/michaelschiemer/current:/var/www/html:rw
# Load environment variables from .env file (generated by Ansible)
# Use absolute path to ensure .env is found regardless of working directory
env_file:
- /home/deploy/deployment/stacks/production/.env
environment:
- APP_ENV=production
- WORKER_DEBUG=false
- WORKER_SLEEP_TIME=100000
- WORKER_MAX_JOBS=10000
# Use Docker Secrets via *_FILE pattern (Framework supports this automatically)
- DB_PASSWORD_FILE=/run/secrets/db_user_password
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
- APP_KEY_FILE=/run/secrets/app_key
- VAULT_ENCRYPTION_KEY_FILE=/run/secrets/vault_encryption_key
secrets:
- db_user_password
- redis_password
- app_key
- vault_encryption_key
# Production resource limits
deploy:
resources:
limits:
memory: 2G
cpus: '2.0'
reservations:
memory: 1G
cpus: '1.0'
# Note: replicas removed due to conflict with container_name
# To scale queue workers, use separate docker-compose service definitions
# JSON logging
logging:
driver: json-file
options:
max-size: "20m"
max-file: "10"
compress: "true"
labels: "service,environment"
# Graceful shutdown for long-running jobs
stop_grace_period: 60s
# Wait for dependencies to be healthy before starting
depends_on:
php:
condition: service_healthy
# Note: PostgreSQL and Redis are external services, connection via app-internal network
# php-test service removed for production (test profiles not used in production)
php-test:
image: localhost:5000/framework:latest
# Build section removed - production-base.yml has no build sections
profiles:
- never # Disable php-test in production
# Scheduler (Cron Jobs)
scheduler:
# Use pre-built image from registry (override build from base if exists)
image: localhost:5000/framework:latest
# Build section removed - production-base.yml has no build sections
container_name: scheduler
# Production restart policy
restart: always
# Override user setting - container must start as root for gosu to work
# The entrypoint script will use gosu to switch to appuser after setup
user: "root"
# Override entrypoint to skip PHP-FPM/Nginx startup - scheduler only needs PHP CLI
entrypoint: ""
# Scheduler command - direct PHP execution
command: php console.php scheduler:run
# Production volumes
volumes:
# Mount application code from rsync deployment (read-write for storage/var directories)
- /home/deploy/michaelschiemer/current:/var/www/html:rw
# Load environment variables from .env file (generated by Ansible)
# Use absolute path to ensure .env is found regardless of working directory
env_file:
- /home/deploy/deployment/stacks/production/.env
environment:
- TZ=Europe/Berlin
- APP_ENV=production
- APP_DEBUG=false
# Use Docker Secrets via *_FILE pattern (Framework supports this automatically)
- DB_PASSWORD_FILE=/run/secrets/db_user_password
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
- APP_KEY_FILE=/run/secrets/app_key
- VAULT_ENCRYPTION_KEY_FILE=/run/secrets/vault_encryption_key
secrets:
- db_user_password
- redis_password
- app_key
- vault_encryption_key
# Production resource limits
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
cpus: '0.25'
# Health checks
healthcheck:
test: ["CMD-SHELL", "php -r 'exit(0);' && test -f /var/www/html/console.php || exit 1"]
interval: 60s
timeout: 10s
retries: 3
start_period: 30s
# JSON logging
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
compress: "true"
labels: "service,environment"
# Graceful shutdown
stop_grace_period: 30s
# Wait for dependencies to be healthy before starting
depends_on:
php:
condition: service_healthy
# Note: PostgreSQL and Redis are external services, connection via app-internal network
# Certbot Sidecar Container for Let's Encrypt
certbot:
image: certbot/certbot:latest
container_name: certbot
restart: always
volumes:
# Share certificates with Nginx
- certbot-conf:/etc/letsencrypt
- certbot-www:/var/www/certbot
# Logs for debugging
- certbot-logs:/var/log/letsencrypt
# Auto-renewal every 12 hours
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot --quiet; sleep 12h & wait $${!}; done;'"
networks:
- frontend
# JSON logging
logging:
driver: json-file
options:
max-size: "5m"
max-file: "3"
compress: "true"
labels: "service,environment"
networks:
cache:
internal: true # Cache network is internal in production
volumes:
# Let's Encrypt SSL Certificates
certbot-conf:
driver: local
certbot-www:
driver: local
certbot-logs:
driver: local
# Application storage volume (single volume for entire storage directory)
storage:
driver: local
# Database volume removed - using external PostgreSQL Stack
# PostgreSQL data is managed by deployment/stacks/postgresql/