Files
fotospiel-app/docs/deployment/docker.md
2025-11-12 20:42:46 +01:00

5.3 KiB

Docker Deployment Guide

This guide describes the recommended, repeatable way to run the Fotospiel platform in Docker for production or high-fidelity staging environments. It pairs a multi-stage build (PHP-FPM + asset pipeline) with a Compose stack that includes Nginx, worker processes, Redis, and MySQL.

Coolify users: see docs/deployment/coolify.md for service definitions, secrets, and how to wire the same containers (web, queue, scheduler, vsftpd) inside Coolify. That document builds on the base Docker instructions below.

1. Prerequisites

  • Docker Engine 24+ and Docker Compose v2.
  • A .env file for the application (see step 4).
  • Optional: an external MySQL/Redis if you do not want to run the bundled containers.

2. Build the application image

docker compose build app

The build performs the following steps:

  1. Installs Node dependencies and runs npm run build to produce production assets.
  2. Installs PHP dependencies with Composer (--no-dev --no-scripts).
  3. Creates a PHP 8.3 FPM image with required extensions (GD, intl, Redis, etc.).
  4. Stores the compiled application under /opt/app; the runtime entrypoint syncs it into the shared volume when a container starts.

3. Configure environment

Copy the sample Docker environment file and edit the secrets:

cp docker/.env.docker docker/.env.docker.local

Set (at minimum):

  • APP_KEY — generate with docker compose run --rm app php artisan key:generate --show.
  • Database credentials (DB_*). The provided MySQL service defaults to fotospiel/secret.
  • STORAGE_ALERT_EMAIL — recipient for upload failure alerts (optional).

Point docker-compose.yml to the file you created by either renaming it to docker/.env.docker or adjusting the env_file entries.

4. Boot the stack

docker compose up -d

Services started:

  • app: PHP-FPM container serving the Laravel application.
  • web: Nginx proxy forwarding requests to PHP-FPM on port 8080 by default (APP_HTTP_PORT).
  • queue & media-storage-worker: queue consumers (default + media archival).
  • scheduler: runs php artisan schedule:work.
  • horizon (optional, disabled unless --profile horizon is supplied).
  • redis & mysql.

Migrations & seeds

Run once after the first boot or when deploying new schema changes:

docker compose exec app php artisan migrate --force
docker compose exec app php artisan db:seed --class=MediaStorageTargetSeeder --force

If you already have data, skip the seeder or seed only new records.

5. Queue & Horizon management

Worker entrypoints live in docs/queue-supervisor/. The Compose services mount the same application volume so code stays in sync. Adjust concurrency by scaling services:

docker compose up -d --scale queue=2 --scale media-storage-worker=2

To enable Horizon (dashboard, smart balancing):

docker compose --profile horizon up -d horizon

6. Scheduler & cron jobs

The compose stack ships a scheduler service that runs php artisan schedule:work, so all scheduled commands defined in App\Console\Kernel stay active. For upload health monitoring, keep the helper script from cron/upload_queue_health.sh on the host (or inside a management container) and add a cron entry:

*/5 * * * * /var/www/html/cron/upload_queue_health.sh

This wrapper logs to storage/logs/cron-upload-queue-health.log and executes php artisan storage:check-upload-queues, which in turn issues guest-facing upload alerts when queues stall or fail repeatedly. In containerised environments mount the repository so the script can reuse the same PHP binary as the app, or call the artisan command directly via docker compose exec app php artisan storage:check-upload-queues.

The dashboard becomes available at /horizon and is protected by the Filament super-admin auth guard.

6. Persistent data & volumes

  • app-code — contains the synced application, including the storage directory and generated assets.
  • mysql-data — MySQL data files.
  • redis-data — Redis persistence (disabled by default; change the Redis command if you want AOF snapshots).

Back up the volumes before upgrades to maintain tenant media and database state.

7. Updating the stack

  1. git pull the repository (or deploy your release branch).
  2. docker compose build app.
  3. docker compose up -d.
  4. Run migrations + seeders if required.
  5. Check logs: docker compose logs -f app queue media-storage-worker.

Because the app image keeps the authoritative copy of the code, each container restart rsyncs fresh sources into the shared volume ensuring reliable updates without lingering artefacts.

8. Production hardening

  • Terminate TLS with a dedicated reverse proxy (Traefik, Caddy, AWS ALB, etc.) in front of the web container.
  • Point APP_URL to your public domain and enable trusted proxies.
  • Externalize MySQL/Redis to managed services for better resilience.
  • Configure backups for the storage directories and database dumps.
  • Hook into your observability stack (e.g., ship container logs to Loki or ELK).

With the provided configuration you can bootstrap a consistent Docker-based deployment across environments while keeping queue workers, migrations, and asset builds manageable. Adjust service definitions as needed for staging vs. production.