# ---------------------------------- # Projekt: michaelschiemer.de # Docker & Ansible Makefile # ---------------------------------- PROJECT_NAME = michaelschiemer ENV ?= dev # Docker Compose Konfiguration COMPOSE_BASE = docker-compose.base.yml COMPOSE_LOCAL = docker-compose.local.yml COMPOSE_STAGING = docker-compose.staging.yml COMPOSE_PRODUCTION = docker-compose.production.yml COMPOSE_FILES = -f $(COMPOSE_BASE) -f $(COMPOSE_LOCAL) # Standart Docker Compose Befehle (Lokale Entwicklung) up: ## Startet alle Docker-Container (lokale Entwicklung) docker compose $(COMPOSE_FILES) up -d down: ## Stoppt alle Container docker compose $(COMPOSE_FILES) down build: ## Baut alle Docker-Images docker compose $(COMPOSE_FILES) build restart: ## Neustart aller Container ./bin/restart logs: ## Zeigt Logs aus Docker docker compose $(COMPOSE_FILES) logs -f ps: ## Docker PS docker compose $(COMPOSE_FILES) ps reload: ## Dump Autoload & Restart PHP docker compose $(COMPOSE_FILES) exec php composer dump-autoload -o docker compose $(COMPOSE_FILES) restart php # Staging Environment up-staging: ## Startet Staging-Container docker compose -f $(COMPOSE_BASE) -f $(COMPOSE_STAGING) up -d down-staging: ## Stoppt Staging-Container docker compose -f $(COMPOSE_BASE) -f $(COMPOSE_STAGING) down logs-staging: ## Zeigt Staging-Logs docker compose -f $(COMPOSE_BASE) -f $(COMPOSE_STAGING) logs -f # Production Environment up-production: ## Startet Production-Container (nur auf Server) docker compose -f $(COMPOSE_BASE) -f $(COMPOSE_PRODUCTION) up -d down-production: ## Stoppt Production-Container (nur auf Server) docker compose -f $(COMPOSE_BASE) -f $(COMPOSE_PRODUCTION) down logs-production: ## Zeigt Production-Logs (nur auf Server) docker compose -f $(COMPOSE_BASE) -f $(COMPOSE_PRODUCTION) logs -f flush-redis: ## Clear Redis cache (FLUSHALL) docker exec redis redis-cli FLUSHALL # Wähle dev- oder prod-PHP-Konfig je nach ENV phpinfo: @echo "Aktive PHP-Konfiguration: php.$(ENV).ini" # Ansible Deployment setup: ## Führt Ansible Setup aus ./bin/setup deploy: ## Führt Ansible Deploy aus ./bin/deploy test: ## Führt alle Tests mit PHP 8.4 aus @echo "🧪 Running tests with PHP 8.4..." docker compose $(COMPOSE_FILES) --profile test run --rm php-test ./vendor/bin/pest test-php85: ## Führt alle Tests mit PHP 8.5 aus (Development) @echo "🧪 Running tests with PHP 8.5..." docker exec php ./vendor/bin/pest test-coverage: ## Führt Tests mit Coverage-Report aus (PHP 8.4) docker compose $(COMPOSE_FILES) --profile test run --rm php-test ./vendor/bin/pest --coverage test-coverage-html: ## Generiert HTML Coverage-Report (PHP 8.4) docker compose $(COMPOSE_FILES) --profile test run --rm php-test ./vendor/bin/pest --coverage-html coverage-html @echo "📊 Coverage-Report verfügbar unter: coverage-html/index.html" test-unit: ## Führt nur Unit-Tests aus (PHP 8.4) docker compose $(COMPOSE_FILES) --profile test run --rm php-test ./vendor/bin/pest tests/Unit/ test-framework: ## Führt nur Framework-Tests aus (PHP 8.4) docker compose $(COMPOSE_FILES) --profile test run --rm php-test ./vendor/bin/pest tests/Framework/ test-domain: ## Führt nur Domain-Tests aus (PHP 8.4) docker compose $(COMPOSE_FILES) --profile test run --rm php-test ./vendor/bin/pest tests/Domain/ test-watch: ## Führt Tests im Watch-Modus aus (PHP 8.4) docker compose $(COMPOSE_FILES) --profile test run --rm php-test ./vendor/bin/pest --watch test-parallel: ## Führt Tests parallel aus (PHP 8.4) docker compose $(COMPOSE_FILES) --profile test run --rm php-test ./vendor/bin/pest --parallel test-profile: ## Profiling der langsamsten Tests (PHP 8.4) docker compose $(COMPOSE_FILES) --profile test run --rm php-test ./vendor/bin/pest --profile test-filter: ## Führt spezifische Tests aus (PHP 8.4) (Usage: make test-filter FILTER="EventDispatcher") docker compose $(COMPOSE_FILES) --profile test run --rm php-test ./vendor/bin/pest --filter="$(FILTER)" # Security Checks security-check: ## Führt Composer Security Audit aus docker exec php composer security:audit security-audit-json: ## Führt Security Audit mit JSON-Output aus docker exec php composer security:audit-json security-check-prod: ## Prüft nur Production-Dependencies auf Schwachstellen docker exec php composer security:check # Cleanup temporärer/metadaten-Dateien clean: ## Entfernt temporäre Dateien find . -type f -name "*Zone.Identifier" -delete find . -type f -name "*.retry" -delete clean-coverage: ## Entfernt Coverage-Reports rm -rf coverage-html/ coverage-xml/ coverage.txt @echo "🧹 Coverage-Reports entfernt" static: ## Generate Static Files ./bin/generate-static.php # Projektstatus status: ## Zeigt Container-Status @echo "Aktuelles Projekt: $(PROJECT_NAME)" @echo "Umgebung: $(ENV)" doctor: ## Prüft ob Komponenten installiert sind @echo "🔍 Prüfe Voraussetzungen..." @which docker > /dev/null || echo "❌ Docker fehlt" @which ansible-playbook > /dev/null || echo "❌ Ansible fehlt" @test -f .env || echo "⚠️ .env-Datei fehlt" # Helfer: Automatische Zielübersicht help: ## Zeigt diese Hilfe an @echo "" @echo "🛠 Verfügbare Make-Befehle:" @grep -E '^[a-zA-Z_-]+:.*?## ' Makefile | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-16s\033[0m %s\n", $$1, $$2}' @echo "" console: ## Run console commands (Usage: make console ARGS="command arguments") docker exec -it php php console.php $(ARGS) composer: ## Use Composer docker compose $(COMPOSE_FILES) exec php composer $(ARGS) fix-perms: ## Fix permissions sudo chown -R $(USER):$(USER) . cs: @$(MAKE) composer ARGS="cs" cs-fix-file: ## Fix code style for a specific file docker compose $(COMPOSE_FILES) exec -e PHP_CS_FIXER_IGNORE_ENV=1 php ./vendor/bin/php-cs-fixer fix $(subst \,/,$(FILE)) cs-fix: ## Fix code style for all PHP files docker compose $(COMPOSE_FILES) exec -e PHP_CS_FIXER_IGNORE_ENV=1 php ./vendor/bin/php-cs-fixer fix phpstan: ## Run PHPStan static analysis @$(MAKE) composer ARGS="phpstan" phpstan-baseline: ## Generate PHPStan baseline @$(MAKE) composer ARGS="phpstan-baseline" ssh: ## SSH-Verbindung zum Production-Server öffnen (nutzt ~/.ssh/config 'production') @echo "🔌 Verbinde zum Production-Server..." ssh production ssh-production: ## SSH-Verbindung zum Production-Server öffnen @echo "🔌 Verbinde zum Production-Server..." ssh production ssh-git: ## SSH-Verbindung zum Git-Server öffnen @echo "🔌 Verbinde zum Git-Server..." ssh git.michaelschiemer.de ssh-status: ## Status der autossh-Services prüfen @echo "📊 Prüfe autossh Service-Status..." @systemctl --user status autossh-production.service --no-pager || echo "⚠️ autossh-production.service nicht aktiv" @echo "" @ps aux | grep autossh | grep -v grep || echo "⚠️ Keine autossh-Prozesse gefunden" ssh-logs: ## Logs der autossh-Services anzeigen @echo "📋 Zeige autossh Logs..." @journalctl --user -u autossh-production.service -n 20 --no-pager || echo "⚠️ Keine Logs verfügbar" setup-ssh: ## SSH-Schlüssel korrekt einrichten mkdir -p ~/.ssh cp /mnt/c/Users/Mike/.ssh/test.michaelschiemer.de ~/.ssh/staging chmod 600 ~/.ssh/staging @echo "SSH-Schlüssel für Staging korrekt eingerichtet" setup-autossh: ## Autossh für persistente SSH-Verbindungen einrichten @echo "🔧 Richte autossh für persistente SSH-Verbindungen ein..." @bash scripts/setup-autossh.sh both fix-ssh-perms: ## Korrigiert SSH-Schlüsselberechtigungen (veraltet) chmod 600 /mnt/c/Users/Mike/.ssh/test.michaelschiemer.de @echo "SSH-Schlüsselberechtigungen korrigiert" health: ansible-playbook ansible/check.yml # Ansible Konfiguration ANSIBLE_INVENTORY=deployment/ansible/inventory/production.yml PLAYBOOK_DIR=deployment/ansible/playbooks/deploy TAGS= .PHONY: dev staging production setup-server check # Deployment-Ziele dev: ## Lokales Deployment (Development) cd deployment/ansible && ansible-playbook -i inventory/production.yml playbooks/deploy/dev.yml --ask-become-pass $(if $(TAGS),--tags="$(TAGS)",) staging: ## Staging-Deployment cd deployment/ansible && ansible-playbook -i inventory/production.yml playbooks/deploy/staging.yml $(if $(TAGS),--tags="$(TAGS)",) production: ## Produktions-Deployment cd deployment/ansible && ansible-playbook -i inventory/production.yml playbooks/deploy/production.yml $(if $(TAGS),--tags="$(TAGS)",) setup-server: ## Server-Grundkonfiguration cd deployment/ansible && ansible-playbook -i inventory/production.yml playbooks/setup-infrastructure.yml $(if $(LIMIT),--limit="$(LIMIT)",) $(if $(TAGS),--tags="$(TAGS)",) check: ## Serververbindung prüfen cd deployment/ansible && ansible -i inventory/production.yml all -m ping $(if $(LIMIT),--limit="$(LIMIT)",) # Beispielaufrufe: # make staging TAGS="deploy,check" # make setup-server LIMIT="staging" TAGS="docker" # Production Update Commands update-production: ## Update PHP files on production server @echo "🚀 Updating PHP files on production server..." @cd deployment && make application ENV=production @echo "✅ Production update completed" restart-production: ## Restart production PHP container only @echo "🔄 Restarting production PHP container..." @ssh -i ~/.ssh/production deploy@94.16.110.151 "cd /var/www/html && docker compose restart php" @echo "✅ Production PHP container restarted" deploy-production-quick: ## Quick production deployment via deployment Makefile @echo "⚡ Quick production deployment..." @cd deployment && make deploy-quick ENV=production @echo "✅ Quick production deployment completed" status-production: ## Check production deployment status @echo "📊 Checking production status..." @cd deployment && make status ENV=production logs-production: ## Show production logs @echo "📋 Showing production logs..." @cd deployment && make logs-prod-php logs-staging: ## Show staging-app container logs via SSH (container stdout/stderr) @echo "📋 Showing staging-app container logs..." @ssh -i ~/.ssh/production deploy@94.16.110.151 "cd ~/deployment/stacks/staging && docker compose logs -f staging-app" logs-staging-php: ## Show PHP application logs from staging-app (log files) @echo "📋 Showing PHP application logs from staging-app..." @ssh -i ~/.ssh/production deploy@94.16.110.151 "docker exec -i staging-app tail -f /var/www/html/storage/logs/*.log 2>/dev/null || docker exec -i staging-app ls -la /var/www/html/storage/logs/ 2>/dev/null || echo 'Log directory /var/www/html/storage/logs/ not accessible'" cache-clear-staging: ## Clear cache on staging server @echo "🗑️ Clearing cache on staging server..." @ssh -i ~/.ssh/production deploy@94.16.110.151 "cd ~/deployment/stacks/staging && docker compose exec staging-app php console.php cache:clear" @echo "✅ Cache cleared on staging server" cache-clear: ## Clear cache locally @echo "🗑️ Clearing cache locally..." docker exec php php console.php cache:clear @echo "✅ Cache cleared locally" # SSL Certificate Management (PHP Framework Integration) ssl-init: ## Initialize Let's Encrypt certificates @echo "🔒 Initializing SSL certificates..." docker exec php php console.php ssl:init ssl-init-staging: ## Initialize Let's Encrypt certificates (Staging/Testing) @echo "🔒 Initializing SSL certificates (Staging Mode)..." @echo "💡 Hint: Set LETSENCRYPT_STAGING=1 in .env for staging mode" docker exec php php console.php ssl:init ssl-test: ## Test SSL configuration @echo "🔍 Testing SSL configuration..." docker exec php php console.php ssl:test ssl-renew: ## Manually renew certificates @echo "🔄 Renewing SSL certificates..." docker exec php php console.php ssl:renew ssl-status: ## Check certificate status and expiry @echo "📋 Certificate status:" docker exec php php console.php ssl:status ssl-backup: ## Backup Let's Encrypt certificates @echo "💾 Backing up SSL certificates..." @mkdir -p backups docker run --rm \ -v certbot-conf:/etc/letsencrypt \ -v $(PWD)/backups:/backup \ alpine tar czf /backup/letsencrypt-$(shell date +%Y%m%d-%H%M%S).tar.gz /etc/letsencrypt @echo "✅ Backup created in backups/" push-staging: ## Pusht den aktuellen Stand nach origin/staging git push origin HEAD:staging # ENV File Management env-base: ## Erstellt .env.base aus .env.example (gemeinsame Variablen) @if [ ! -f .env.example ]; then \ echo "❌ .env.example nicht gefunden"; \ exit 1; \ fi @if [ -f .env.base ]; then \ echo "⚠️ .env.base existiert bereits. Überschreiben? (j/n)"; \ read confirm; \ if [ "$$confirm" != "j" ]; then \ echo "❌ Abgebrochen"; \ exit 1; \ fi fi @echo "📝 Erstelle .env.base aus .env.example..." @cp .env.example .env.base @echo "✅ .env.base erstellt" @echo "💡 Bearbeite .env.base und entferne environment-spezifische Variablen" @echo "💡 Siehe ENV_SETUP.md für Details" env-local: ## Erstellt .env.local für lokale Development-Overrides @if [ -f .env.local ]; then \ echo "⚠️ .env.local existiert bereits. Überschreiben? (j/n)"; \ read confirm; \ if [ "$$confirm" != "j" ]; then \ echo "❌ Abgebrochen"; \ exit 1; \ fi fi @echo "📝 Erstelle .env.local..." @if [ -f .env ]; then \ cp .env .env.local; \ echo "✅ .env.local erstellt aus .env"; \ else \ echo "APP_ENV=development" > .env.local; \ echo "APP_DEBUG=true" >> .env.local; \ echo "✅ .env.local erstellt (Minimal-Version)"; \ fi @echo "💡 Bearbeite .env.local mit deinen lokalen Overrides" @echo "💡 Siehe ENV_SETUP.md für Details" env-check: ## Prüft .env.base auf Secrets (sollte keine enthalten) @echo "🔍 Prüfe .env.base auf Secrets..." @if [ ! -f .env.base ]; then \ echo "✅ .env.base existiert nicht (optional)"; \ exit 0; \ fi @if grep -E "(PASSWORD|KEY|SECRET|TOKEN)" .env.base | grep -v "^#" | grep -v "=" | grep -v "^$$" > /dev/null; then \ echo "⚠️ Warnung: .env.base könnte Secrets enthalten:"; \ grep -E "(PASSWORD|KEY|SECRET|TOKEN)" .env.base | grep -v "^#" | grep -v "=" || true; \ echo "💡 Secrets sollten in .env.local oder Docker Secrets sein"; \ exit 1; \ else \ echo "✅ .env.base enthält keine Secrets"; \ fi @echo "" @echo "🔍 Prüfe docker-compose.base.yml auf hardcodierte Passwörter..." @if grep -E "(PASSWORD|SECRET|TOKEN).*:-[^}]*[^}]}" docker-compose.base.yml | grep -v "^#" | grep -v "FILE=" > /dev/null 2>&1; then \ echo "⚠️ Warnung: docker-compose.base.yml enthält möglicherweise hardcodierte Passwörter:"; \ grep -E "(PASSWORD|SECRET|TOKEN).*:-[^}]*[^}]}" docker-compose.base.yml | grep -v "^#" | grep -v "FILE=" || true; \ echo "💡 Passwörter müssen explizit gesetzt werden, keine Fallbacks in Base-Datei"; \ exit 1; \ else \ echo "✅ docker-compose.base.yml enthält keine hardcodierten Passwörter"; \ fi env-validate: ## Validiert ENV-Files (Base+Override Pattern) @echo "🔍 Validiere ENV-Files..." @if [ -f .env.base ]; then \ echo "✅ .env.base existiert"; \ else \ echo "⚠️ .env.base nicht gefunden (optional für Migration)"; \ fi @if [ -f .env.local ]; then \ echo "✅ .env.local existiert"; \ else \ echo "⚠️ .env.local nicht gefunden"; \ fi @if [ -f .env ] && [ ! -f .env.base ]; then \ echo "✅ Legacy .env verwendet (Fallback)"; \ fi @echo "💡 Framework lädt: .env.base → .env.local → System ENV" .PHONY: up down build restart logs ps phpinfo deploy setup clean clean-coverage status fix-ssh-perms setup-ssh setup-autossh ssh ssh-production ssh-git ssh-status ssh-logs test test-coverage test-coverage-html test-unit test-framework test-domain test-watch test-parallel test-profile test-filter security-check security-audit-json security-check-prod update-production restart-production deploy-production-quick status-production logs-production logs-staging logs-staging-php cache-clear-staging cache-clear ssl-init ssl-init-staging ssl-test ssl-renew ssl-status ssl-backup push-staging env-base env-local env-check env-validate