- scheduler: scheduler:run → schedule:run (correct console command) - queue-worker: console.php queue:work → worker.php (standalone script)
525 lines
20 KiB
YAML
525 lines
20 KiB
YAML
# Staging Environment Override
|
||
# Usage: docker-compose -f docker-compose.base.yml -f docker-compose.staging.yml up
|
||
#
|
||
# This file overrides base configuration with staging-specific settings:
|
||
# - Container names with "staging-" prefix
|
||
# - Traefik integration for staging.michaelschiemer.de
|
||
# - Git clone functionality for staging branch
|
||
# - Staging-specific networks (traefik-public, staging-internal)
|
||
# - Staging-specific volumes
|
||
|
||
services:
|
||
# PHP-FPM Application Runtime
|
||
php:
|
||
image: localhost:5000/framework:latest
|
||
container_name: php
|
||
restart: unless-stopped
|
||
networks:
|
||
- app-backend
|
||
- app-internal
|
||
environment:
|
||
- TZ=Europe/Berlin
|
||
- APP_ENV=staging
|
||
- APP_DEBUG=false
|
||
- APP_URL=https://staging.michaelschiemer.de
|
||
- APP_KEY=${APP_KEY:-}
|
||
# Git Repository - clones staging branch
|
||
- GIT_REPOSITORY_URL=${GIT_REPOSITORY_URL:-}
|
||
- GIT_BRANCH=staging
|
||
- GIT_TOKEN=${GIT_TOKEN:-}
|
||
- GIT_USERNAME=${GIT_USERNAME:-}
|
||
- GIT_PASSWORD=${GIT_PASSWORD:-}
|
||
# Database - using separate staging database
|
||
- DB_HOST=postgres
|
||
- DB_PORT=5432
|
||
- DB_DATABASE=${DB_DATABASE:-michaelschiemer_staging}
|
||
- DB_USERNAME=${DB_USERNAME}
|
||
- DB_PASSWORD=${DB_PASSWORD}
|
||
# Redis
|
||
- REDIS_HOST=redis
|
||
- REDIS_PORT=6379
|
||
# Cache
|
||
- CACHE_DRIVER=redis
|
||
- CACHE_PREFIX=${CACHE_PREFIX:-staging}
|
||
# Session
|
||
- SESSION_DRIVER=redis
|
||
- SESSION_LIFETIME=${SESSION_LIFETIME:-120}
|
||
# Queue
|
||
- QUEUE_DRIVER=redis
|
||
- QUEUE_CONNECTION=default
|
||
# Use Docker Secrets via *_FILE pattern (Framework supports this automatically)
|
||
# Note: These paths will be set by the entrypoint script after copying secrets
|
||
# to /var/www/html/storage/secrets/ for www-data access
|
||
# The entrypoint script will copy secrets and set these paths
|
||
- DB_PASSWORD_FILE=/var/www/html/storage/secrets/db_user_password
|
||
- REDIS_PASSWORD_FILE=/var/www/html/storage/secrets/redis_password
|
||
- APP_KEY_FILE=/var/www/html/storage/secrets/app_key
|
||
volumes:
|
||
- app-code:/var/www/html
|
||
- app-storage:/var/www/html/storage
|
||
- app-logs:/var/www/html/storage/logs
|
||
- /etc/timezone:/etc/timezone:ro
|
||
- /etc/localtime:/etc/localtime:ro
|
||
secrets:
|
||
- db_user_password
|
||
- redis_password
|
||
- app_key
|
||
# Override entrypoint to only start PHP-FPM (not nginx) + fix git ownership
|
||
entrypoint: ["/bin/sh", "-c"]
|
||
command:
|
||
- |
|
||
|
||
# Copy Docker Secrets to readable location for www-data
|
||
# Docker Secrets are only readable by root, but PHP (www-data) needs to read them.
|
||
# We copy them here as root to a location where www-data can read them.
|
||
# Note: Use $$ to escape shell variables in docker-compose YAML
|
||
echo "🔐 Setting up Docker Secrets for PHP access..."
|
||
SECRETS_DIR="/var/www/html/storage/secrets"
|
||
# Ensure we're in the right directory
|
||
cd /var/www/html || exit 1
|
||
# Create secrets directory if it doesn't exist
|
||
mkdir -p "$$SECRETS_DIR"
|
||
chmod 750 "$$SECRETS_DIR"
|
||
chown www-data:www-data "$$SECRETS_DIR"
|
||
|
||
if [ -f /run/secrets/redis_password ]; then
|
||
cp /run/secrets/redis_password "$$SECRETS_DIR/redis_password" 2>/dev/null || true
|
||
chmod 640 "$$SECRETS_DIR/redis_password"
|
||
chown www-data:www-data "$$SECRETS_DIR/redis_password"
|
||
export REDIS_PASSWORD_FILE="$$SECRETS_DIR/redis_password"
|
||
echo "✅ Copied redis_password to $$SECRETS_DIR/redis_password"
|
||
else
|
||
echo "⚠️ Warning: /run/secrets/redis_password not found"
|
||
fi
|
||
|
||
if [ -f /run/secrets/db_user_password ]; then
|
||
cp /run/secrets/db_user_password "$$SECRETS_DIR/db_user_password" 2>/dev/null || true
|
||
chmod 640 "$$SECRETS_DIR/db_user_password"
|
||
chown www-data:www-data "$$SECRETS_DIR/db_user_password"
|
||
export DB_PASSWORD_FILE="$$SECRETS_DIR/db_user_password"
|
||
echo "✅ Copied db_user_password to $$SECRETS_DIR/db_user_password"
|
||
else
|
||
echo "⚠️ Warning: /run/secrets/db_user_password not found"
|
||
fi
|
||
|
||
if [ -f /run/secrets/app_key ]; then
|
||
cp /run/secrets/app_key "$$SECRETS_DIR/app_key" 2>/dev/null || true
|
||
chmod 640 "$$SECRETS_DIR/app_key"
|
||
chown www-data:www-data "$$SECRETS_DIR/app_key"
|
||
export APP_KEY_FILE="$$SECRETS_DIR/app_key"
|
||
echo "✅ Copied app_key to $$SECRETS_DIR/app_key"
|
||
else
|
||
echo "⚠️ Warning: /run/secrets/app_key not found"
|
||
fi
|
||
|
||
|
||
# Fix Git ownership issue
|
||
# Ensure Git treats the mounted repository as safe regardless of owner
|
||
git config --global --add safe.directory /var/www/html 2>/dev/null || true
|
||
git config --system --add safe.directory /var/www/html 2>/dev/null || true
|
||
|
||
# Git Clone/Pull functionality
|
||
if [ -n "$GIT_REPOSITORY_URL" ]; then
|
||
echo ""
|
||
echo "📥 Cloning/Pulling code from Git repository..."
|
||
|
||
GIT_BRANCH="${GIT_BRANCH:-main}"
|
||
GIT_TARGET_DIR="/var/www/html"
|
||
|
||
# Setup Git credentials
|
||
if [ -n "$GIT_TOKEN" ]; then
|
||
GIT_URL_WITH_AUTH=$(echo "$GIT_REPOSITORY_URL" | sed "s|https://|https://${GIT_TOKEN}@|")
|
||
elif [ -n "$GIT_USERNAME" ] && [ -n "$GIT_PASSWORD" ]; then
|
||
GIT_URL_WITH_AUTH=$(echo "$GIT_REPOSITORY_URL" | sed "s|https://|https://${GIT_USERNAME}:${GIT_PASSWORD}@|")
|
||
else
|
||
GIT_URL_WITH_AUTH="$GIT_REPOSITORY_URL"
|
||
fi
|
||
|
||
# Clone or pull
|
||
if [ ! -d "$GIT_TARGET_DIR/.git" ]; then
|
||
echo "📥 Cloning repository from $GIT_REPOSITORY_URL (branch: $GIT_BRANCH)..."
|
||
if [ "$(ls -A $GIT_TARGET_DIR 2>/dev/null)" ]; then
|
||
find "$GIT_TARGET_DIR" -mindepth 1 -maxdepth 1 ! -name "storage" -exec rm -rf {} \; 2>/dev/null || true
|
||
fi
|
||
TEMP_CLONE="${GIT_TARGET_DIR}.tmp"
|
||
rm -rf "$TEMP_CLONE" 2>/dev/null || true
|
||
if git -c safe.directory=/var/www/html clone --branch "$GIT_BRANCH" --depth 1 "$GIT_URL_WITH_AUTH" "$TEMP_CLONE"; then
|
||
find "$GIT_TARGET_DIR" -mindepth 1 -maxdepth 1 ! -name "storage" -exec rm -rf {} \; 2>/dev/null || true
|
||
find "$TEMP_CLONE" -mindepth 1 -maxdepth 1 ! -name "." ! -name ".." -exec mv {} "$GIT_TARGET_DIR/" \; 2>/dev/null || true
|
||
rm -rf "$TEMP_CLONE" 2>/dev/null || true
|
||
echo "✅ Repository cloned successfully"
|
||
fi
|
||
else
|
||
echo "🔄 Pulling latest changes from $GIT_BRANCH..."
|
||
cd "$GIT_TARGET_DIR"
|
||
git -c safe.directory=/var/www/html fetch origin "$GIT_BRANCH" || echo "⚠️ Git fetch failed"
|
||
git -c safe.directory=/var/www/html reset --hard "origin/$GIT_BRANCH" || echo "⚠️ Git reset failed"
|
||
git -c safe.directory=/var/www/html clean -fd || true
|
||
fi
|
||
|
||
# Install dependencies
|
||
if [ -f "$GIT_TARGET_DIR/composer.json" ]; then
|
||
echo "📦 Installing/updating Composer dependencies..."
|
||
cd "$GIT_TARGET_DIR"
|
||
composer install --no-dev --optimize-autoloader --no-interaction --no-scripts || echo "⚠️ Composer install failed"
|
||
composer dump-autoload --optimize --classmap-authoritative || true
|
||
fi
|
||
|
||
echo "✅ Git sync completed"
|
||
else
|
||
echo ""
|
||
echo "ℹ️ GIT_REPOSITORY_URL not set, using code from image"
|
||
fi
|
||
|
||
echo ""
|
||
echo "📊 Environment variables:"
|
||
env | grep -E "DB_|APP_" | grep -v "PASSWORD|KEY|SECRET" || true
|
||
|
||
# Run database migrations
|
||
if [ -f /var/www/html/console.php ]; then
|
||
echo ""
|
||
echo "🗄️ Running database migrations..."
|
||
cd /var/www/html
|
||
php console.php db:migrate --force || echo "⚠️ Migration warning (may be OK if already migrated)"
|
||
fi
|
||
|
||
# Warm up caches
|
||
echo ""
|
||
echo "🔥 Warming up caches..."
|
||
cd /var/www/html
|
||
php console.php cache:warm 2>/dev/null || echo "ℹ️ Cache warmup skipped (command may not exist)"
|
||
|
||
echo ""
|
||
echo "🛠️ Adjusting filesystem permissions..."
|
||
chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache 2>/dev/null || true
|
||
find /var/www/html/storage /var/www/html/bootstrap/cache -type d -exec chmod 775 {} \; 2>/dev/null || true
|
||
find /var/www/html/storage /var/www/html/bootstrap/cache -type f -exec chmod 664 {} \; 2>/dev/null || true
|
||
|
||
# Keep PHP-FPM secure with clear_env = yes (default)
|
||
# The *_FILE environment variables are passed explicitly via docker-compose environment section
|
||
# PHP's DockerSecretsResolver will read the secrets from the files specified in *_FILE vars
|
||
|
||
# Start PHP-FPM only (no nginx)
|
||
echo ""
|
||
echo "🚀 Starting PHP-FPM..."
|
||
echo "REDIS_PASSWORD_FILE: ${REDIS_PASSWORD_FILE:-NOT SET}"
|
||
exec php-fpm
|
||
healthcheck:
|
||
# Use HTTP liveness check via php-fpm (not via nginx)
|
||
# This checks if the PHP application is actually responding
|
||
test: ["CMD-SHELL", "php-fpm-healthcheck || exit 1"]
|
||
interval: 15s
|
||
timeout: 5s
|
||
retries: 3
|
||
start_period: 60s
|
||
depends_on:
|
||
redis:
|
||
condition: service_started
|
||
# Nginx Web Server
|
||
nginx:
|
||
image: localhost:5000/framework:latest
|
||
container_name: nginx
|
||
restart: unless-stopped
|
||
networks:
|
||
- traefik-public
|
||
- app-backend
|
||
environment:
|
||
- TZ=Europe/Berlin
|
||
- APP_ENV=staging
|
||
- APP_DEBUG=false
|
||
# Git Repository - clones staging branch
|
||
- GIT_REPOSITORY_URL=${GIT_REPOSITORY_URL:-}
|
||
- GIT_BRANCH=staging
|
||
- GIT_TOKEN=${GIT_TOKEN:-}
|
||
- GIT_USERNAME=${GIT_USERNAME:-}
|
||
- GIT_PASSWORD=${GIT_PASSWORD:-}
|
||
volumes:
|
||
- ./deployment/stacks/staging/nginx/conf.d:/etc/nginx/conf.d:ro
|
||
- app-code:/var/www/html:ro
|
||
- app-storage:/var/www/html/storage:ro
|
||
- /etc/timezone:/etc/timezone:ro
|
||
- /etc/localtime:/etc/localtime:ro
|
||
# Wait for code to be available (cloned by php container) then start nginx
|
||
entrypoint: ["/bin/sh", "-c"]
|
||
command:
|
||
- |
|
||
# Wait for code to be available in shared volume (php container clones it)
|
||
GIT_TARGET_DIR="/var/www/html"
|
||
echo "⏳ [staging-nginx] Waiting for code to be available in shared volume..."
|
||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||
if [ -d "$$GIT_TARGET_DIR/public" ]; then
|
||
echo "✅ [staging-nginx] Code found in shared volume"
|
||
break
|
||
fi
|
||
echo " [staging-nginx] Waiting... ($$i/10)"
|
||
sleep 2
|
||
done
|
||
|
||
# If code still not available after wait, try to copy from image as fallback
|
||
if [ ! -d "$$GIT_TARGET_DIR/public" ] && [ -d "/var/www/html.orig" ]; then
|
||
echo "⚠️ [staging-nginx] Code not found in shared volume, copying from image..."
|
||
find /var/www/html.orig -mindepth 1 -maxdepth 1 ! -name "storage" -exec cp -r {} "$$GIT_TARGET_DIR/" \; 2>/dev/null || true
|
||
fi
|
||
|
||
# Fix nginx upstream configuration - sites-enabled/default is a symlink to sites-available/default
|
||
# This is critical: nginx config uses production-php:9000 but staging uses php container
|
||
for NGINX_CONF in /etc/nginx/sites-enabled/default /etc/nginx/sites-available/default; do
|
||
if [ -f "$$NGINX_CONF" ]; then
|
||
echo "🔧 [staging-nginx] Fixing PHP-FPM upstream in $$NGINX_CONF..."
|
||
# Replace production-php with staging php container name
|
||
sed -i 's|server production-php:9000;|server php:9000;|g' "$$NGINX_CONF" || true
|
||
# Replace localhost/127.0.0.1 references
|
||
sed -i '/upstream php-upstream {/,/}/s|server 127.0.0.1:9000;|server php:9000;|g' "$$NGINX_CONF" || true
|
||
sed -i '/upstream php-upstream {/,/}/s|server localhost:9000;|server php:9000;|g' "$$NGINX_CONF" || true
|
||
# Replace any auto-generated container names (like 5aad84af7c9e_php)
|
||
sed -i 's|server [a-zA-Z0-9_-]*php:9000;|server php:9000;|g' "$$NGINX_CONF" || true
|
||
# Replace any direct fastcgi_pass references too
|
||
sed -i 's|fastcgi_pass 127.0.0.1:9000;|fastcgi_pass php-upstream;|g' "$$NGINX_CONF" || true
|
||
sed -i 's|fastcgi_pass localhost:9000;|fastcgi_pass php-upstream;|g' "$$NGINX_CONF" || true
|
||
sed -i 's|fastcgi_pass production-php:9000;|fastcgi_pass php-upstream;|g' "$$NGINX_CONF" || true
|
||
echo "✅ [staging-nginx] PHP-FPM upstream fixed in $$NGINX_CONF"
|
||
fi
|
||
done
|
||
|
||
# Wait for PHP-FPM to be ready before starting nginx
|
||
# This prevents 502 Bad Gateway errors during startup
|
||
echo "⏳ [staging-nginx] Waiting for PHP-FPM to be ready..."
|
||
MAX_WAIT=30
|
||
WAITED=0
|
||
while [ $$WAITED -lt $$MAX_WAIT ]; do
|
||
# Check if PHP-FPM is accepting connections on port 9000
|
||
if nc -z php 9000 2>/dev/null; then
|
||
echo "✅ [staging-nginx] PHP-FPM is ready on php:9000"
|
||
break
|
||
fi
|
||
echo " [staging-nginx] PHP-FPM not ready yet... ($$WAITED/$$MAX_WAIT)"
|
||
sleep 1
|
||
WAITED=$$((WAITED + 1))
|
||
done
|
||
|
||
if [ $$WAITED -ge $$MAX_WAIT ]; then
|
||
echo "⚠️ [staging-nginx] PHP-FPM did not become ready within $$MAX_WAIT seconds, starting anyway..."
|
||
fi
|
||
|
||
# Start nginx only (no PHP-FPM, no Git clone - php container handles that)
|
||
echo "🚀 [staging-nginx] Starting nginx..."
|
||
exec nginx -g "daemon off;"
|
||
labels:
|
||
- "traefik.enable=true"
|
||
# HTTP Router for staging subdomain
|
||
- "traefik.http.routers.staging.rule=Host(`staging.michaelschiemer.de`)"
|
||
- "traefik.http.routers.staging.entrypoints=websecure"
|
||
- "traefik.http.routers.staging.tls=true"
|
||
- "traefik.http.routers.staging.tls.certresolver=letsencrypt"
|
||
# Service
|
||
- "traefik.http.services.staging.loadbalancer.server.port=80"
|
||
# Network
|
||
- "traefik.docker.network=traefik-public"
|
||
healthcheck:
|
||
# Use /health/live endpoint for lightweight liveness check
|
||
test: ["CMD-SHELL", "curl -sf http://127.0.0.1/health/live || exit 1"]
|
||
interval: 15s
|
||
timeout: 5s
|
||
retries: 3
|
||
start_period: 30s
|
||
depends_on:
|
||
php:
|
||
condition: service_started
|
||
# Remove base service dependencies and build
|
||
ports: []
|
||
|
||
# Redis Cache/Session/Queue Backend (separate from production)
|
||
redis:
|
||
image: redis:7-alpine
|
||
container_name: redis
|
||
restart: unless-stopped
|
||
networks:
|
||
- app-backend
|
||
environment:
|
||
- TZ=Europe/Berlin
|
||
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
|
||
secrets:
|
||
- redis_password
|
||
# Use entrypoint script to inject password from Docker Secret into config
|
||
# Note: Script runs as root to read Docker Secrets, then starts Redis
|
||
entrypoint: ["/bin/sh", "-c"]
|
||
command:
|
||
- |
|
||
# Read password from Docker Secret (as root)
|
||
REDIS_PASSWORD=$$(cat /run/secrets/redis_password 2>/dev/null || echo '')
|
||
# Start Redis with all settings as command line arguments (no config file to avoid conflicts)
|
||
if [ -n "$$REDIS_PASSWORD" ]; then
|
||
exec redis-server \
|
||
--bind 0.0.0.0 \
|
||
--dir /data \
|
||
--maxmemory 256mb \
|
||
--maxmemory-policy allkeys-lru \
|
||
--save 900 1 \
|
||
--save 300 10 \
|
||
--save 60 10000 \
|
||
--appendonly yes \
|
||
--appendfsync everysec \
|
||
--requirepass "$$REDIS_PASSWORD"
|
||
else
|
||
exec redis-server \
|
||
--bind 0.0.0.0 \
|
||
--dir /data \
|
||
--maxmemory 256mb \
|
||
--maxmemory-policy allkeys-lru \
|
||
--save 900 1 \
|
||
--save 300 10 \
|
||
--save 60 10000 \
|
||
--appendonly yes \
|
||
--appendfsync everysec
|
||
fi
|
||
volumes:
|
||
- redis-data:/data
|
||
- /etc/timezone:/etc/timezone:ro
|
||
- /etc/localtime:/etc/localtime:ro
|
||
|
||
# Queue Worker (Background Jobs)
|
||
queue-worker:
|
||
image: localhost:5000/framework:latest
|
||
container_name: queue-worker
|
||
restart: unless-stopped
|
||
networks:
|
||
- app-backend
|
||
- app-internal
|
||
environment:
|
||
- TZ=Europe/Berlin
|
||
- APP_ENV=staging
|
||
- APP_DEBUG=false
|
||
# Database - using separate staging database
|
||
- DB_HOST=postgres
|
||
- DB_PORT=5432
|
||
- DB_DATABASE=${DB_DATABASE:-michaelschiemer_staging}
|
||
- DB_USERNAME=${DB_USERNAME}
|
||
- DB_PASSWORD=${DB_PASSWORD}
|
||
# Use Docker Secrets via *_FILE pattern (Framework supports this automatically)
|
||
- DB_PASSWORD_FILE=/run/secrets/db_user_password
|
||
- APP_KEY_FILE=/run/secrets/app_key
|
||
# Redis
|
||
- REDIS_HOST=redis
|
||
- REDIS_PORT=6379
|
||
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
|
||
# Queue
|
||
- QUEUE_DRIVER=redis
|
||
- QUEUE_CONNECTION=default
|
||
- QUEUE_WORKER_SLEEP=${QUEUE_WORKER_SLEEP:-3}
|
||
- QUEUE_WORKER_TRIES=${QUEUE_WORKER_TRIES:-3}
|
||
- QUEUE_WORKER_TIMEOUT=${QUEUE_WORKER_TIMEOUT:-60}
|
||
volumes:
|
||
- app-code:/var/www/html
|
||
- app-storage:/var/www/html/storage
|
||
- app-logs:/var/www/html/storage/logs
|
||
- /etc/timezone:/etc/timezone:ro
|
||
- /etc/localtime:/etc/localtime:ro
|
||
command: php worker.php
|
||
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
|
||
depends_on:
|
||
php:
|
||
condition: service_started
|
||
redis:
|
||
condition: service_started
|
||
entrypoint: ""
|
||
stop_grace_period: 30s
|
||
secrets:
|
||
- db_user_password
|
||
- redis_password
|
||
- app_key
|
||
|
||
# Scheduler (Cron Jobs)
|
||
scheduler:
|
||
image: localhost:5000/framework:latest
|
||
container_name: scheduler
|
||
restart: unless-stopped
|
||
networks:
|
||
- app-backend
|
||
- app-internal
|
||
environment:
|
||
- TZ=Europe/Berlin
|
||
- APP_ENV=staging
|
||
- APP_DEBUG=false
|
||
# Database - using separate staging database
|
||
- DB_HOST=postgres
|
||
- DB_PORT=5432
|
||
- DB_DATABASE=${DB_DATABASE:-michaelschiemer_staging}
|
||
- DB_USERNAME=${DB_USERNAME}
|
||
- DB_PASSWORD=${DB_PASSWORD}
|
||
# Use Docker Secrets via *_FILE pattern (Framework supports this automatically)
|
||
- DB_PASSWORD_FILE=/run/secrets/db_user_password
|
||
- APP_KEY_FILE=/run/secrets/app_key
|
||
# Redis
|
||
- REDIS_HOST=redis
|
||
- REDIS_PORT=6379
|
||
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
|
||
volumes:
|
||
- app-code:/var/www/html
|
||
- app-storage:/var/www/html/storage
|
||
- app-logs:/var/www/html/storage/logs
|
||
- /etc/timezone:/etc/timezone:ro
|
||
- /etc/localtime:/etc/localtime:ro
|
||
command: php console.php schedule:run
|
||
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
|
||
depends_on:
|
||
php:
|
||
condition: service_started
|
||
redis:
|
||
condition: service_started
|
||
entrypoint: ""
|
||
stop_grace_period: 30s
|
||
secrets:
|
||
- db_user_password
|
||
- redis_password
|
||
- app_key
|
||
|
||
# Disable base services (override from docker-compose.base.yml)
|
||
web:
|
||
profiles: [never]
|
||
minio:
|
||
profiles: [never]
|
||
|
||
networks:
|
||
traefik-public:
|
||
external: true
|
||
app-backend:
|
||
driver: bridge
|
||
app-internal:
|
||
external: true
|
||
name: app-internal
|
||
|
||
volumes:
|
||
app-code:
|
||
name: staging-code
|
||
app-storage:
|
||
name: staging-storage
|
||
app-logs:
|
||
name: staging-logs
|
||
redis-data:
|
||
name: staging-redis-data
|
||
|
||
# Docker Secrets Configuration
|
||
# Secrets are inherited from docker-compose.base.yml
|
||
# But we need to explicitly define them here to ensure they're available
|
||
secrets:
|
||
db_user_password:
|
||
file: ./deployment/secrets/staging/db_password.txt
|
||
external: false
|
||
redis_password:
|
||
file: ./deployment/secrets/staging/redis_password.txt
|
||
external: false
|
||
app_key:
|
||
file: ./deployment/secrets/staging/app_key.txt
|
||
external: false
|
||
|