From 94d02736f7444c288f9e96660dc2a3fd1054d028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Fr=C3=B6hlich?= Date: Wed, 17 Dec 2025 13:02:38 +0100 Subject: [PATCH] ci: add automated Gitea Actions deployment workflow for Synology NAS - Add Gitea Actions workflow for automated build and deployment - Add deployment script for Synology NAS - Add Docker Compose configurations for production deployment - Add Gitea runner setup - Add comprehensive documentation for CI/CD setup - Add health check endpoint for deployment verification - Update .gitignore for CI/CD artifacts --- .env.gitea-runner.example | 29 ++ .env.synology.example | 75 +++++ .gitea/workflows/deploy-synology.yml | 233 ++++++++++++++ .gitignore | 8 + CI_CD_README.md | 281 +++++++++++++++++ DEPLOYMENT_FILES_OVERVIEW.md | 210 +++++++++++++ GITEA_RUNNER_SETUP.md | 411 +++++++++++++++++++++++++ SYNOLOGY_DEPLOYMENT.md | 435 +++++++++++++++++++++++++++ docker-compose.gitea-runner.yml | 74 +++++ docker-compose.synology.yml | 91 ++++++ routes/web.php | 9 + scripts/deploy-synology.sh | 258 ++++++++++++++++ 12 files changed, 2114 insertions(+) create mode 100644 .env.gitea-runner.example create mode 100644 .env.synology.example create mode 100644 .gitea/workflows/deploy-synology.yml create mode 100644 CI_CD_README.md create mode 100644 DEPLOYMENT_FILES_OVERVIEW.md create mode 100644 GITEA_RUNNER_SETUP.md create mode 100644 SYNOLOGY_DEPLOYMENT.md create mode 100644 docker-compose.gitea-runner.yml create mode 100644 docker-compose.synology.yml create mode 100755 scripts/deploy-synology.sh diff --git a/.env.gitea-runner.example b/.env.gitea-runner.example new file mode 100644 index 0000000..3e61c7e --- /dev/null +++ b/.env.gitea-runner.example @@ -0,0 +1,29 @@ +# Gitea Runner Configuration +# Kopiere diese Datei zu .env.gitea-runner und passe die Werte an + +# ============================================ +# Gitea Instance +# ============================================ +# URL deiner Gitea-Installation +# Wenn Gitea auf der gleichen NAS läuft: +GITEA_URL=http://your-synology-ip:3000 + +# Wenn Gitea in Docker läuft und im gleichen Netzwerk: +# GITEA_URL=http://gitea:3000 + +# ============================================ +# Runner Configuration +# ============================================ +# Runner Registration Token +# Generiere diesen Token in Gitea: +# Repository → Settings → Actions → Runners → Create new Runner +RUNNER_TOKEN=your_gitea_runner_registration_token_here + +# Runner Name (wird in Gitea angezeigt) +RUNNER_NAME=synology-runner + +# Maximale Anzahl gleichzeitiger Jobs +RUNNER_CAPACITY=1 + +# Log Level: trace, debug, info, warn, error, fatal +LOG_LEVEL=info diff --git a/.env.synology.example b/.env.synology.example new file mode 100644 index 0000000..f8fa9d5 --- /dev/null +++ b/.env.synology.example @@ -0,0 +1,75 @@ +# Laravel Application Configuration für Synology NAS Deployment +# Kopiere diese Datei zu .env.synology und passe die Werte an + +# ============================================ +# Application Settings +# ============================================ +APP_NAME=Laravel +APP_ENV=production +APP_KEY=base64:L9RVZ3pNFyAvTbMqicT1rL5GbgE+7lJerkU9wyc95H8= +APP_DEBUG=false +APP_URL=http://your-synology-ip:8080 + +APP_LOCALE=en +APP_FALLBACK_LOCALE=en +APP_FAKER_LOCALE=en_US + +APP_MAINTENANCE_DRIVER=file + +BCRYPT_ROUNDS=12 + +# ============================================ +# Logging +# ============================================ +LOG_CHANNEL=stack +LOG_STACK=single +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=info + +# ============================================ +# Database - PostgreSQL (Haupt-Datenbank) +# ============================================ +DB_CONNECTION2=pgsql +DB_HOST2=postgres +DB_PORT2=5432 +DB_DATABASE2=ingest_db +DB_USERNAME2=ingest_user +DB_PASSWORD2=ingest_pwd + +# ============================================ +# Session & Cache +# ============================================ +SESSION_DRIVER=file +SESSION_LIFETIME=120 +SESSION_ENCRYPT=false +SESSION_PATH=/ +SESSION_DOMAIN=null + +# ============================================ +# Broadcasting & Queues +# ============================================ +BROADCAST_CONNECTION=log +QUEUE_CONNECTION=sync + +# ============================================ +# Cache +# ============================================ +CACHE_STORE=file +FILESYSTEM_DISK=local + +# ============================================ +# Mail Configuration +# ============================================ +MAIL_MAILER=log +MAIL_SCHEME=null +MAIL_HOST=127.0.0.1 +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_FROM_ADDRESS="hello@example.com" +MAIL_FROM_NAME="${APP_NAME}" + +# ============================================ +# Vite +# ============================================ +VITE_APP_NAME="${APP_NAME}" diff --git a/.gitea/workflows/deploy-synology.yml b/.gitea/workflows/deploy-synology.yml new file mode 100644 index 0000000..2725e8f --- /dev/null +++ b/.gitea/workflows/deploy-synology.yml @@ -0,0 +1,233 @@ +name: Build and Deploy to Synology NAS + +on: + push: + branches: + - main + - develop + pull_request: + branches: + - main + +env: + DOCKER_IMAGE: laravel-app + DOCKER_REGISTRY: ${{ secrets.SYNOLOGY_HOST }}:5000 # Synology Docker Registry Port + +jobs: + # Job 1: Run Tests + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Validate Conventional Commit (subject line only) + id: validate + run: | + SUBJECT="$(git log -1 --pretty=%s)" + echo "Commit subject: $SUBJECT" + if echo "$SUBJECT" | grep -Eq '^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\(.+\))?: .+'; then + echo "valid=true" >> "$GITHUB_OUTPUT" + else + echo "valid=false" >> "$GITHUB_OUTPUT" + fi + + - name: Setup PHP + if: ${{ steps.validate.outputs.valid == 'true' }} + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + extensions: mbstring, xml, ctype, json, bcmath, pdo, pdo_sqlite + coverage: none + + - name: Install Composer Dependencies + if: ${{ steps.validate.outputs.valid == 'true' }} + run: composer install --prefer-dist --no-progress --no-suggest + + - name: Setup Node.js + if: ${{ steps.validate.outputs.valid == 'true' }} + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install NPM Dependencies + if: ${{ steps.validate.outputs.valid == 'true' }} + run: npm ci + + - name: Build Frontend Assets + if: ${{ steps.validate.outputs.valid == 'true' }} + run: npm run build + + - name: Run Tests + if: ${{ steps.validate.outputs.valid == 'true' }} + run: php artisan test + + # Job 2: Build and Push Docker Image + build: + runs-on: ubuntu-latest + needs: test + if: github.event_name == 'push' + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Validate Conventional Commit + id: validate + run: | + SUBJECT="$(git log -1 --pretty=%s)" + echo "Commit subject: $SUBJECT" + if echo "$SUBJECT" | grep -Eq '^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\(.+\))?: .+'; then + echo "valid=true" >> "$GITHUB_OUTPUT" + else + echo "valid=false" >> "$GITHUB_OUTPUT" + fi + + - name: Stop if not a Conventional Commit + if: ${{ steps.validate.outputs.valid != 'true' }} + run: | + echo "Latest commit is not a valid Conventional Commit. Skipping build." + exit 0 + + - name: Set up Docker Buildx + if: ${{ steps.validate.outputs.valid == 'true' }} + uses: docker/setup-buildx-action@v3 + + - name: Determine Docker Tag + id: docker_tag + if: ${{ steps.validate.outputs.valid == 'true' }} + run: | + if [ "${{ github.ref_name }}" == "main" ]; then + echo "tag=latest" >> "$GITHUB_OUTPUT" + echo "env=production" >> "$GITHUB_OUTPUT" + else + echo "tag=${{ github.ref_name }}" >> "$GITHUB_OUTPUT" + echo "env=staging" >> "$GITHUB_OUTPUT" + fi + + - name: Build Docker Image + if: ${{ steps.validate.outputs.valid == 'true' }} + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: false + load: true + tags: ${{ env.DOCKER_IMAGE }}:${{ steps.docker_tag.outputs.tag }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Save Docker Image + if: ${{ steps.validate.outputs.valid == 'true' }} + run: | + docker save ${{ env.DOCKER_IMAGE }}:${{ steps.docker_tag.outputs.tag }} | gzip > laravel-app.tar.gz + + - name: Upload Docker Image Artifact + if: ${{ steps.validate.outputs.valid == 'true' }} + uses: actions/upload-artifact@v4 + with: + name: docker-image + path: laravel-app.tar.gz + retention-days: 1 + + # Job 3: Deploy to Synology NAS + deploy: + runs-on: ubuntu-latest + needs: build + if: github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'develop') + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Download Docker Image Artifact + uses: actions/download-artifact@v4 + with: + name: docker-image + + - name: Determine Environment + id: env + run: | + if [ "${{ github.ref_name }}" == "main" ]; then + echo "env=production" >> "$GITHUB_OUTPUT" + else + echo "env=staging" >> "$GITHUB_OUTPUT" + fi + + - name: Setup SSH + run: | + mkdir -p ~/.ssh + echo "${{ secrets.SYNOLOGY_SSH_KEY }}" > ~/.ssh/synology_key + chmod 600 ~/.ssh/synology_key + ssh-keyscan -H ${{ secrets.SYNOLOGY_HOST }} >> ~/.ssh/known_hosts + + - name: Copy Files to Synology + run: | + # Transfer Docker Image + scp -i ~/.ssh/synology_key laravel-app.tar.gz \ + ${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }}:/volume1/docker/laravel-app/ + + # Transfer Docker Compose file + scp -i ~/.ssh/synology_key docker-compose.synology.yml \ + ${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }}:/volume1/docker/laravel-app/ + + # Transfer deployment script + scp -i ~/.ssh/synology_key scripts/deploy-synology.sh \ + ${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }}:/volume1/docker/laravel-app/ + + - name: Deploy on Synology + run: | + ssh -i ~/.ssh/synology_key \ + ${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }} \ + "cd /volume1/docker/laravel-app && chmod +x deploy-synology.sh && ./deploy-synology.sh" + + - name: Health Check + run: | + sleep 10 # Wait for container to start + + # Check if the app is responding + SYNOLOGY_IP="${{ secrets.SYNOLOGY_HOST }}" + MAX_RETRIES=30 + RETRY_COUNT=0 + + while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do + if curl -f -s http://$SYNOLOGY_IP:8080/health > /dev/null 2>&1; then + echo "✅ Application is healthy!" + exit 0 + fi + + echo "⏳ Waiting for application to be ready... ($RETRY_COUNT/$MAX_RETRIES)" + sleep 5 + RETRY_COUNT=$((RETRY_COUNT + 1)) + done + + echo "❌ Health check failed after $MAX_RETRIES attempts" + exit 1 + + - name: Cleanup + if: always() + run: | + rm -f ~/.ssh/synology_key + ssh -i ~/.ssh/synology_key \ + ${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }} \ + "rm -f /volume1/docker/laravel-app/laravel-app.tar.gz" || true + + # Job 4: Notify on Success/Failure (optional) + notify: + runs-on: ubuntu-latest + needs: [test, build, deploy] + if: always() + + steps: + - name: Deployment Status + run: | + if [ "${{ needs.deploy.result }}" == "success" ]; then + echo "✅ Deployment to Synology NAS successful!" + echo "🌐 Application available at: http://${{ secrets.SYNOLOGY_HOST }}:8080" + else + echo "❌ Deployment failed. Check the logs for details." + exit 1 + fi diff --git a/.gitignore b/.gitignore index 168bbd5..8017ef9 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,14 @@ yarn-error.log /database/*.sqlite /database/*.sqlite-journal *.sql.gz +/backups + +# CI/CD & Deployment +.env.synology +.env.gitea-runner +kubeconfig +*.tar.gz +laravel-app.tar.gz # Backup & Temporary Files *.bak diff --git a/CI_CD_README.md b/CI_CD_README.md new file mode 100644 index 0000000..090da77 --- /dev/null +++ b/CI_CD_README.md @@ -0,0 +1,281 @@ +# CI/CD Automatisierung für Synology NAS + +Dieses Projekt ist vollständig für automatisches Deployment auf deiner Synology NAS mit Gitea Actions vorbereitet. + +## 🚀 Schnellstart + +### 1. Gitea Runner einrichten (einmalig) + +```bash +# Auf der Synology NAS +cd /volume1/docker +mkdir gitea-runner +cd gitea-runner + +# Environment Datei erstellen +cat > .env << 'EOF' +GITEA_URL=http://your-synology-ip:3000 +RUNNER_TOKEN=your_token_from_gitea +RUNNER_NAME=synology-runner +EOF + +# Runner starten +docker-compose -f /path/to/docker-compose.gitea-runner.yml up -d +``` + +**Runner Token generieren:** +1. Gitea öffnen +2. Repository → Settings → Actions → Runners +3. "Create new Runner" klicken +4. Token kopieren und in `.env` einfügen + +📖 Detaillierte Anleitung: [GITEA_RUNNER_SETUP.md](GITEA_RUNNER_SETUP.md) + +### 2. Repository Secrets konfigurieren (einmalig) + +In Gitea: **Repository → Settings → Secrets** + +| Secret Name | Wert | Beschreibung | +|------------|------|--------------| +| `SYNOLOGY_HOST` | `192.168.1.100` | IP deiner Synology | +| `SYNOLOGY_USER` | `admin` | SSH-Benutzername | +| `SYNOLOGY_SSH_KEY` | `-----BEGIN...` | Private SSH-Key | +| `APP_KEY` | `base64:...` | Laravel APP_KEY | + +**SSH-Key erstellen:** + +```bash +# Auf der Synology NAS +ssh-keygen -t ed25519 -C "gitea-deploy" -f ~/.ssh/gitea_deploy +cat ~/.ssh/gitea_deploy.pub >> ~/.ssh/authorized_keys +cat ~/.ssh/gitea_deploy # Diesen Key als Secret verwenden +``` + +### 3. Code pushen und automatisch deployen! 🎉 + +```bash +git add . +git commit -m "feat: meine neue Funktion" +git push origin main +``` + +Das wars! Der Rest läuft automatisch: +- ✅ Tests werden ausgeführt +- ✅ Docker Image wird gebaut +- ✅ Deployment auf NAS +- ✅ Health Check +- ✅ Benachrichtigung bei Erfolg/Fehler + +## 📁 Wichtige Dateien + +| Datei | Beschreibung | +|-------|--------------| +| [`.gitea/workflows/deploy-synology.yml`](.gitea/workflows/deploy-synology.yml) | Gitea Actions Workflow | +| [`docker-compose.synology.yml`](docker-compose.synology.yml) | Docker Compose für Deployment | +| [`scripts/deploy-synology.sh`](scripts/deploy-synology.sh) | Deployment-Script | +| [`.env.synology.example`](.env.synology.example) | Environment-Beispiel | +| [`SYNOLOGY_DEPLOYMENT.md`](SYNOLOGY_DEPLOYMENT.md) | Vollständige Deployment-Doku | +| [`GITEA_RUNNER_SETUP.md`](GITEA_RUNNER_SETUP.md) | Gitea Runner Setup-Anleitung | + +## 🔄 Workflow-Prozess + +``` +1. Developer pushed Code zu Gitea + ↓ +2. Gitea Actions Workflow startet + ↓ +3. Tests laufen (Pest) + ↓ +4. Docker Image wird gebaut + ↓ +5. Image wird zur Synology NAS übertragen + ↓ +6. Deployment-Script läuft auf NAS + ↓ +7. Container werden aktualisiert + ↓ +8. Migrationen & Cache-Optimierung + ↓ +9. Health Check + ↓ +10. ✅ Deployment erfolgreich! +``` + +## 🎯 Features + +### Automatisierte Tests +- PHP-Tests mit Pest +- Frontend-Build-Validierung +- Nur erfolgreiche Builds werden deployed + +### Intelligentes Deployment +- Automatisches Backup vor Deployment +- Rollback bei Fehlern +- Health Checks nach Deployment +- Zero-Downtime durch Docker + +### Branch-spezifisches Deployment +- `main` → Production (Port 8080) +- `develop` → Staging (Port 8081) +- Feature-Branches → Nur Tests + +### Conventional Commits +Der Workflow akzeptiert nur Conventional Commits: +- `feat:` - Neue Features +- `fix:` - Bugfixes +- `docs:` - Dokumentation +- `chore:` - Wartung +- `refactor:` - Code-Refactoring +- `test:` - Tests +- `ci:` - CI/CD Änderungen + +**Beispiel:** +```bash +git commit -m "feat: add user authentication" +git commit -m "fix: resolve database connection issue" +``` + +## 🔍 Monitoring + +### Workflow Status prüfen + +**In Gitea:** +1. Repository öffnen +2. Tab "Actions" anklicken +3. Alle Runs mit Status sehen + +**Logs ansehen:** +- Klicke auf einen Run +- Klicke auf einen Job (test/build/deploy) +- Sieh detaillierte Logs + +### Container Logs + +```bash +# Auf der Synology NAS via SSH +docker logs -f laravel_app +docker logs -f laravel_postgres +``` + +### Health Endpoint + +```bash +curl http://your-synology-ip:8080/health +``` + +Response: +```json +{ + "status": "healthy", + "timestamp": "2025-12-17T10:30:00Z", + "app": "Laravel", + "env": "production" +} +``` + +## 🛠 Manuelle Befehle + +### Manuelles Deployment + +```bash +# Auf der Synology NAS +cd /volume1/docker/laravel-app +./scripts/deploy-synology.sh +``` + +### Container verwalten + +```bash +# Status prüfen +docker-compose -f docker-compose.synology.yml ps + +# Logs ansehen +docker-compose -f docker-compose.synology.yml logs -f + +# Neustart +docker-compose -f docker-compose.synology.yml restart + +# Stoppen +docker-compose -f docker-compose.synology.yml down +``` + +### Laravel Artisan + +```bash +# Migrationen +docker exec laravel_app php artisan migrate + +# Cache leeren +docker exec laravel_app php artisan cache:clear + +# Shell öffnen +docker exec -it laravel_app sh +``` + +## 🐛 Troubleshooting + +### Workflow startet nicht + +**Prüfen:** +1. Runner Status in Gitea → Settings → Actions → Runners +2. Commit-Message ist Conventional Commit Format +3. Branch ist `main` oder `develop` + +**Lösung:** +```bash +# Runner neu starten +docker restart gitea-runner + +# Runner Logs prüfen +docker logs gitea-runner +``` + +### Deployment schlägt fehl + +**Prüfen:** +1. SSH-Verbindung zur NAS funktioniert +2. Alle Secrets sind korrekt gesetzt +3. Deployment-Script ist executable + +**Lösung:** +```bash +# SSH-Key testen +ssh -i ~/.ssh/gitea_deploy admin@your-synology-ip + +# Permissions prüfen +chmod +x scripts/deploy-synology.sh +``` + +### Health Check fehlschlägt + +**Prüfen:** +1. Container läuft: `docker ps | grep laravel_app` +2. Logs: `docker logs laravel_app` +3. Netzwerk: `curl http://localhost:8080/health` + +**Lösung:** +```bash +# Container neu starten +docker-compose -f docker-compose.synology.yml restart + +# .env prüfen +docker exec laravel_app cat .env.synology +``` + +## 📚 Weitere Dokumentation + +- **Deployment Details:** [SYNOLOGY_DEPLOYMENT.md](SYNOLOGY_DEPLOYMENT.md) +- **Gitea Runner Setup:** [GITEA_RUNNER_SETUP.md](GITEA_RUNNER_SETUP.md) +- **Workflow Konfiguration:** [.gitea/workflows/deploy-synology.yml](.gitea/workflows/deploy-synology.yml) +- **Deployment Script:** [scripts/deploy-synology.sh](scripts/deploy-synology.sh) + +## 🎉 Das wars! + +Nach der einmaligen Einrichtung läuft alles automatisch: + +1. Code schreiben +2. Commit & Push +3. Warten bis Deployment fertig ist +4. Anwendung ist live! 🚀 + +**Happy Deploying!** 🎊 diff --git a/DEPLOYMENT_FILES_OVERVIEW.md b/DEPLOYMENT_FILES_OVERVIEW.md new file mode 100644 index 0000000..690b94a --- /dev/null +++ b/DEPLOYMENT_FILES_OVERVIEW.md @@ -0,0 +1,210 @@ +# Deployment Files Übersicht + +Diese Datei gibt einen Überblick über alle Dateien, die für das automatisierte Deployment auf deiner Synology NAS erstellt wurden. + +## 📋 Erstelle Dateien + +### 1. CI/CD Workflow +- **`.gitea/workflows/deploy-synology.yml`** + - Gitea Actions Workflow für automatisches Build & Deployment + - Führt Tests aus, baut Docker Image, deployt auf NAS + - Triggert bei Push auf `main` oder `develop` + +### 2. Docker Konfiguration +- **`docker-compose.synology.yml`** + - Docker Compose für Synology NAS Deployment + - Definiert Laravel App + PostgreSQL Datenbank + - Mit persistenten Volumes und Health Checks + +- **`docker-compose.gitea-runner.yml`** + - Docker Compose für Gitea Runner + - Ermöglicht automatische Workflows + +- **`Dockerfile`** + - Bereits vorhanden, wird verwendet für Image-Build + - Multi-stage Build für optimale Image-Größe + +### 3. Environment Konfiguration +- **`.env.synology.example`** + - Beispiel-Environment für Synology Deployment + - Muss kopiert werden zu `.env.synology` + - Enthält alle notwendigen Variablen + +- **`.env.gitea-runner.example`** + - Beispiel-Environment für Gitea Runner + - Muss kopiert werden zu `.env.gitea-runner` + +### 4. Deployment Scripts +- **`scripts/deploy-synology.sh`** + - Automatisches Deployment-Script + - Läuft auf der Synology NAS + - Handhabt Backup, Deployment, Rollback, Health Checks + +### 5. Dokumentation +- **`SYNOLOGY_DEPLOYMENT.md`** + - Vollständige Anleitung für manuelles Deployment + - Inklusive CI/CD Setup Abschnitt + - Troubleshooting Tipps + +- **`GITEA_RUNNER_SETUP.md`** + - Detaillierte Anleitung für Gitea Runner Setup + - Secrets-Konfiguration + - Monitoring & Troubleshooting + +- **`CI_CD_README.md`** + - Schnellstart-Anleitung für CI/CD + - Übersicht über alle Features + - Wichtige Befehle + +- **`DEPLOYMENT_FILES_OVERVIEW.md`** (diese Datei) + - Übersicht über alle erstellten Dateien + +### 6. Application Code +- **`routes/web.php`** + - Health Check Endpoint hinzugefügt (`/health`) + - Wird für automatische Health Checks verwendet + +### 7. Git Konfiguration +- **`.gitignore`** + - Erweitert um CI/CD spezifische Dateien + - `.env.synology` und `.env.gitea-runner` ignoriert + - Build-Artefakte ignoriert + +## 🔧 Verwendung der Dateien + +### Einmalige Einrichtung + +1. **Gitea Runner deployen:** + ```bash + # Auf Synology NAS + cp .env.gitea-runner.example .env.gitea-runner + # Bearbeite .env.gitea-runner mit deinen Werten + docker-compose -f docker-compose.gitea-runner.yml up -d + ``` + +2. **Repository Secrets in Gitea setzen:** + - `SYNOLOGY_HOST` + - `SYNOLOGY_USER` + - `SYNOLOGY_SSH_KEY` + - `APP_KEY` + +3. **Workflow-Dateien committen:** + ```bash + git add .gitea/ + git commit -m "ci: add automated deployment" + git push origin main + ``` + +### Manuelles Deployment + +Falls du manuell deployen möchtest (ohne CI/CD): + +```bash +# Auf Synology NAS +cd /volume1/docker/laravel-app +cp .env.synology.example .env.synology +# Bearbeite .env.synology +docker-compose -f docker-compose.synology.yml up -d --build +``` + +## 📊 Datei-Abhängigkeiten + +``` +.gitea/workflows/deploy-synology.yml +├── docker-compose.synology.yml +├── scripts/deploy-synology.sh +├── .env.synology (zu erstellen) +└── Dockerfile + +docker-compose.gitea-runner.yml +└── .env.gitea-runner (zu erstellen) +``` + +## ✅ Checkliste für Deployment + +### Vor dem ersten Deployment: + +- [ ] Gitea Runner deployed (`docker-compose.gitea-runner.yml`) +- [ ] Runner in Gitea registriert +- [ ] Repository Secrets gesetzt +- [ ] `.env.synology` auf NAS erstellt und konfiguriert +- [ ] SSH-Keys für Deployment eingerichtet +- [ ] Projekt-Verzeichnis auf NAS: `/volume1/docker/laravel-app` + +### Vor jedem Push: + +- [ ] Tests lokal ausgeführt (`php artisan test`) +- [ ] Conventional Commit Message verwendet +- [ ] Code reviewed + +### Nach dem Deployment: + +- [ ] Workflow Status in Gitea Actions überprüft +- [ ] Health Check erfolgreich: `curl http://nas-ip:8080/health` +- [ ] Anwendung erreichbar: `http://nas-ip:8080` +- [ ] Logs prüfen: `docker logs laravel_app` + +## 🔐 Sicherheit + +### Dateien die NICHT committet werden sollten: + +- `.env.synology` - Enthält Produktions-Secrets +- `.env.gitea-runner` - Enthält Runner-Token +- `kubeconfig` - Falls verwendet +- `*.tar.gz` - Build-Artefakte +- SSH Private Keys + +Diese Dateien sind bereits in `.gitignore` eingetragen! + +### Dateien die committet werden sollten: + +- `.env.synology.example` - Template für andere Entwickler +- `.env.gitea-runner.example` - Template für Runner +- Alle `docker-compose*.yml` Dateien +- Alle Dokumentations-Dateien +- Workflow-Dateien in `.gitea/workflows/` +- Deployment-Scripts in `scripts/` + +## 🚀 Nächste Schritte + +1. **Lies die Dokumentation:** + - Start mit [CI_CD_README.md](CI_CD_README.md) für Schnellstart + - Dann [GITEA_RUNNER_SETUP.md](GITEA_RUNNER_SETUP.md) für Runner-Setup + - Bei Problemen: [SYNOLOGY_DEPLOYMENT.md](SYNOLOGY_DEPLOYMENT.md) + +2. **Setup durchführen:** + - Folge der Anleitung in [GITEA_RUNNER_SETUP.md](GITEA_RUNNER_SETUP.md) + - Konfiguriere Secrets in Gitea + - Teste mit einem Push + +3. **Deployment testen:** + - Mache eine kleine Änderung + - Committe mit Conventional Commit + - Push und beobachte Workflow in Gitea Actions + +4. **Optional: Erweitere Workflow:** + - Füge Notifications hinzu (Email, Telegram, Discord) + - Konfiguriere mehrere Environments (Staging, Production) + - Füge weitere Tests hinzu + +## 📝 Hinweise + +- Alle Scripts sind für **Synology DSM 7.x** optimiert +- Docker und Docker Compose müssen auf der NAS installiert sein +- Gitea Actions muss in Gitea aktiviert sein +- PHP 8.4 und Laravel 12 werden verwendet + +## 🆘 Support + +Bei Fragen oder Problemen: + +1. Prüfe die Troubleshooting-Sektionen in den Dokumentations-Dateien +2. Prüfe Logs: `docker logs gitea-runner` und `docker logs laravel_app` +3. Verifiziere alle Secrets und Environment-Variablen +4. Stelle sicher, dass alle Ports verfügbar sind + +--- + +**Erstellt am:** 2025-12-17 +**Version:** 1.0 +**Für:** Synology NAS Deployment mit Gitea Actions diff --git a/GITEA_RUNNER_SETUP.md b/GITEA_RUNNER_SETUP.md new file mode 100644 index 0000000..2795898 --- /dev/null +++ b/GITEA_RUNNER_SETUP.md @@ -0,0 +1,411 @@ +# Gitea Runner Setup auf Synology NAS + +Diese Anleitung erklärt, wie du einen Gitea Actions Runner auf deiner Synology NAS einrichtest, um automatische Deployments durchzuführen. + +## Voraussetzungen + +- Gitea läuft auf deiner Synology NAS +- Docker ist auf der Synology NAS installiert +- SSH-Zugriff auf die Synology NAS +- Portainer läuft (optional, aber empfohlen für Container-Management) + +## Option 1: Gitea Runner mit Docker Compose (empfohlen) + +### 1. Runner Docker Compose Datei erstellen + +Erstelle eine Datei `/volume1/docker/gitea-runner/docker-compose.yml`: + +```yaml +version: "3.9" + +services: + runner: + image: gitea/act_runner:latest + container_name: gitea-runner + restart: unless-stopped + + environment: + - GITEA_INSTANCE_URL=http://your-gitea-url:3000 + - GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_TOKEN} + - GITEA_RUNNER_NAME=synology-runner + - GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:20-bullseye + + volumes: + - ./data:/data + - /var/run/docker.sock:/var/run/docker.sock + + networks: + - gitea-network + +networks: + gitea-network: + external: true +``` + +### 2. Runner Token generieren + +1. Öffne deine Gitea-Instanz im Browser +2. Navigiere zu deinem Repository +3. Gehe zu **Settings** → **Actions** → **Runners** +4. Klicke auf **Create new Runner** +5. Kopiere den generierten Token + +### 3. Environment Variables setzen + +Erstelle eine `.env` Datei im selben Verzeichnis: + +```env +RUNNER_TOKEN=dein_gitea_runner_token_hier +``` + +### 4. Runner starten + +```bash +cd /volume1/docker/gitea-runner +docker-compose up -d +``` + +### 5. Runner verifizieren + +```bash +# Logs anschauen +docker logs -f gitea-runner + +# Status prüfen +docker ps | grep gitea-runner +``` + +In Gitea solltest du nun unter **Settings** → **Actions** → **Runners** deinen registrierten Runner sehen. + +## Option 2: Runner direkt in Portainer deployen + +### 1. In Portainer einloggen + +Öffne Portainer: `http://your-synology-ip:9000` + +### 2. Stack erstellen + +1. Gehe zu **Stacks** → **+ Add stack** +2. Name: `gitea-runner` +3. Wähle **Web editor** +4. Füge die obige docker-compose.yml ein + +### 3. Environment Variables + +Füge folgende Environment Variable hinzu: +- **RUNNER_TOKEN**: Dein Gitea Runner Token + +### 4. Deploy + +Klicke auf **Deploy the stack** + +## Runner Konfiguration + +### Custom Runner Labels + +Um spezifische Workflows auszuführen, kannst du Custom Labels hinzufügen: + +```yaml +environment: + - GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:20-bullseye,ubuntu-22.04:docker://ubuntu:22.04,php-8.4:docker://php:8.4-cli +``` + +### Mehrere Runner + +Für parallele Builds kannst du mehrere Runner starten: + +```yaml +services: + runner-1: + image: gitea/act_runner:latest + container_name: gitea-runner-1 + # ... config ... + + runner-2: + image: gitea/act_runner:latest + container_name: gitea-runner-2 + # ... config ... +``` + +## Repository Secrets konfigurieren + +Um das automatische Deployment zu ermöglichen, musst du Secrets in deinem Gitea-Repository hinterlegen: + +### 1. In Gitea Repository Settings + +1. Gehe zu deinem Repository +2. Klicke auf **Settings** → **Secrets** +3. Füge folgende Secrets hinzu: + +| Secret Name | Beschreibung | Beispiel | +|------------|--------------|----------| +| `SYNOLOGY_HOST` | IP oder Hostname deiner Synology | `192.168.1.100` | +| `SYNOLOGY_USER` | SSH-Benutzername | `admin` | +| `SYNOLOGY_SSH_KEY` | Privater SSH-Key für Zugriff | `-----BEGIN OPENSSH PRIVATE KEY-----...` | +| `APP_KEY` | Laravel Application Key | `base64:xyz...` | + +### 2. SSH-Key generieren (falls nicht vorhanden) + +Auf deiner Synology NAS: + +```bash +# SSH-Key-Pair generieren +ssh-keygen -t ed25519 -C "gitea-runner@synology" -f ~/.ssh/gitea_deploy + +# Public Key zum authorized_keys hinzufügen +cat ~/.ssh/gitea_deploy.pub >> ~/.ssh/authorized_keys +chmod 600 ~/.ssh/authorized_keys + +# Private Key anzeigen (für Secret) +cat ~/.ssh/gitea_deploy +``` + +Kopiere den **gesamten** Private Key (inklusive `-----BEGIN` und `-----END` Zeilen) und füge ihn als `SYNOLOGY_SSH_KEY` Secret hinzu. + +### 3. Secrets verifizieren + +Stelle sicher, dass alle benötigten Secrets gesetzt sind: + +```bash +# In Gitea Repository Settings → Secrets +✅ SYNOLOGY_HOST +✅ SYNOLOGY_USER +✅ SYNOLOGY_SSH_KEY +✅ APP_KEY +``` + +## Workflow aktivieren + +### 1. Workflow-Datei pushen + +```bash +# Lokal im Projekt +git add .gitea/workflows/deploy-synology.yml +git commit -m "ci: add automated deployment workflow" +git push origin main +``` + +### 2. Workflow ausführen + +Gitea Actions wird automatisch bei jedem Push auf `main` oder `develop` ausgelöst. + +### 3. Workflow Status prüfen + +1. Gehe zu deinem Repository in Gitea +2. Klicke auf **Actions** +3. Du siehst alle Workflow-Runs mit Status (Success/Failure) +4. Klicke auf einen Run, um Details und Logs zu sehen + +## Workflow manuell auslösen + +Falls du den Workflow manuell starten möchtest: + +### 1. Workflow-Datei erweitern + +Füge in `.gitea/workflows/deploy-synology.yml` hinzu: + +```yaml +on: + push: + branches: + - main + - develop + workflow_dispatch: # Ermöglicht manuelles Auslösen +``` + +### 2. Manuell auslösen + +1. Gehe zu **Actions** in deinem Repository +2. Wähle den Workflow aus +3. Klicke auf **Run workflow** + +## Monitoring & Logs + +### Runner Logs + +```bash +# Live Logs +docker logs -f gitea-runner + +# Letzte 100 Zeilen +docker logs --tail 100 gitea-runner +``` + +### Workflow Logs + +In Gitea UI: +1. **Actions** Tab +2. Wähle einen Workflow Run +3. Klicke auf die einzelnen Jobs, um Logs zu sehen + +### Deployment Logs auf Synology + +```bash +# Laravel App Logs +docker logs -f laravel_app + +# Deployment Script Logs +# Diese werden in der Workflow-Ausgabe angezeigt +``` + +## Troubleshooting + +### Problem: Runner verbindet sich nicht + +```bash +# Logs prüfen +docker logs gitea-runner + +# Runner neu registrieren +docker-compose down +docker-compose up -d +``` + +### Problem: Workflow startet nicht + +1. **Runner Status prüfen**: Gehe zu Repository → Settings → Actions → Runners +2. **Runner Labels prüfen**: Stelle sicher, dass `runs-on: ubuntu-latest` mit den Runner Labels übereinstimmt +3. **Secrets prüfen**: Alle benötigten Secrets müssen gesetzt sein + +### Problem: SSH-Verbindung fehlschlägt + +```bash +# SSH-Key Permissions prüfen +chmod 600 ~/.ssh/gitea_deploy +chmod 644 ~/.ssh/gitea_deploy.pub +chmod 700 ~/.ssh +chmod 600 ~/.ssh/authorized_keys + +# SSH-Verbindung testen (lokal auf der NAS) +ssh -i ~/.ssh/gitea_deploy admin@localhost +``` + +### Problem: Deployment schlägt fehl + +```bash +# Prüfe deployment script permissions +cd /volume1/docker/laravel-app +ls -la deploy-synology.sh + +# Mache es executable +chmod +x deploy-synology.sh + +# Teste deployment script manuell +./deploy-synology.sh +``` + +### Problem: Health Check fehlschlägt + +```bash +# Prüfe ob Container läuft +docker ps | grep laravel_app + +# Prüfe Logs +docker logs laravel_app + +# Teste Health Endpoint manuell +curl http://localhost:8080/health +``` + +## Best Practices + +### 1. Separate Runner für Production und Staging + +```yaml +services: + runner-production: + environment: + - GITEA_RUNNER_LABELS=production:docker://ubuntu:22.04 + + runner-staging: + environment: + - GITEA_RUNNER_LABELS=staging:docker://ubuntu:22.04 +``` + +Im Workflow: +```yaml +jobs: + deploy-production: + runs-on: production + if: github.ref == 'refs/heads/main' +``` + +### 2. Workflow nur für Conventional Commits + +Der aktuelle Workflow filtert bereits nach Conventional Commits: +- `feat:` - Neue Features +- `fix:` - Bugfixes +- `docs:` - Dokumentation +- `chore:` - Wartungsarbeiten +- etc. + +### 3. Notifications + +Erweitere den Workflow um Benachrichtigungen: + +```yaml +- name: Send Notification + if: always() + run: | + # Telegram, Discord, Email, etc. + curl -X POST https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage \ + -d chat_id=${{ secrets.TELEGRAM_CHAT_ID }} \ + -d text="Deployment status: ${{ job.status }}" +``` + +### 4. Rollback-Strategie + +Im deployment script ist bereits ein Backup-Mechanismus implementiert: +- Datenbank-Backups vor jedem Deployment +- Letzte 5 Backups werden aufbewahrt +- Automatischer Rollback bei Fehlern + +## Erweiterte Konfiguration + +### Multi-Stage Deployments + +Für staging und production environments: + +```yaml +jobs: + deploy-staging: + if: github.ref == 'refs/heads/develop' + # ... deploy to staging ... + + deploy-production: + if: github.ref == 'refs/heads/main' + needs: [test, deploy-staging] + # ... deploy to production ... +``` + +### Caching + +Um Build-Zeiten zu verkürzen: + +```yaml +- name: Cache Composer + uses: actions/cache@v3 + with: + path: vendor + key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }} + +- name: Cache NPM + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }} +``` + +## Weitere Ressourcen + +- [Gitea Actions Dokumentation](https://docs.gitea.com/usage/actions/overview) +- [Act Runner Dokumentation](https://gitea.com/gitea/act_runner) +- [Docker Compose Dokumentation](https://docs.docker.com/compose/) + +## Support + +Bei Problemen: +1. Prüfe Runner Logs: `docker logs gitea-runner` +2. Prüfe Workflow Logs in Gitea Actions Tab +3. Verifiziere alle Secrets sind korrekt gesetzt +4. Teste SSH-Verbindung zur Synology manuell diff --git a/SYNOLOGY_DEPLOYMENT.md b/SYNOLOGY_DEPLOYMENT.md new file mode 100644 index 0000000..b8e3baf --- /dev/null +++ b/SYNOLOGY_DEPLOYMENT.md @@ -0,0 +1,435 @@ +# Synology NAS Deployment Anleitung + +Diese Anleitung beschreibt, wie du diese Laravel-Anwendung auf deiner Synology NAS mit Portainer deployen kannst. + +## 📋 Inhaltsverzeichnis + +1. [Voraussetzungen](#voraussetzungen) +2. [Manuelles Deployment](#-vorbereitung) +3. [Automatisches CI/CD Deployment](#-automatisches-deployment-mit-gitea-actions) +4. [Monitoring & Wartung](#-monitoring--wartung) +5. [Troubleshooting](#-troubleshooting) + +## Voraussetzungen + +- Synology NAS mit Docker-Unterstützung +- Portainer läuft bereits auf deiner NAS +- SSH-Zugriff auf die Synology NAS (optional, aber empfohlen) +- Mindestens 2GB freier RAM +- Mindestens 5GB freier Speicherplatz +- (Optional) Gitea für automatisches CI/CD Deployment + +## 📦 Vorbereitung + +### 1. Projekt-Dateien auf die NAS übertragen + +Es gibt mehrere Möglichkeiten, die Dateien auf deine Synology zu übertragen: + +#### Option A: Via Git (empfohlen) +```bash +# SSH auf die Synology NAS +ssh admin@your-synology-ip + +# Navigiere zu einem geeigneten Verzeichnis (z.B. /volume1/docker/laravel) +cd /volume1/docker +git clone laravel-app +cd laravel-app +``` + +#### Option B: Via File Station +1. Öffne die Synology File Station +2. Erstelle einen Ordner: `/docker/laravel-app` +3. Lade alle Projekt-Dateien in diesen Ordner hoch + +#### Option C: Via rsync/scp +```bash +# Vom lokalen Rechner aus +rsync -avz --exclude 'node_modules' --exclude 'vendor' \ + /Users/sebastianfrohlich/Herd/frontend/ \ + admin@your-synology-ip:/volume1/docker/laravel-app/ +``` + +### 2. Umgebungsvariablen konfigurieren + +```bash +# SSH auf der NAS +cd /volume1/docker/laravel-app + +# Kopiere die Synology-Beispiel-Datei +cp .env.synology.example .env.synology + +# Bearbeite die Datei mit deinen spezifischen Einstellungen +nano .env.synology +``` + +**Wichtige Anpassungen in `.env.synology`:** + +```env +# Ersetze mit deiner Synology IP-Adresse +APP_URL=http://192.168.1.100:8080 + +# Setze APP_DEBUG auf false für Produktion +APP_DEBUG=false + +# Generiere einen neuen APP_KEY (wichtig für Sicherheit!) +# Dies kann später mit: docker exec laravel_app php artisan key:generate gemacht werden + +# PostgreSQL Passwort - ändere dies! +DB_PASSWORD2=dein_sicheres_passwort_hier +``` + +## 🚀 Deployment mit Portainer + +### Methode 1: Docker Compose Stack (empfohlen) + +1. **Öffne Portainer** in deinem Browser: `http://your-synology-ip:9000` + +2. **Navigiere zu "Stacks"**: + - Klicke auf "Stacks" im linken Menü + - Klicke auf "+ Add stack" + +3. **Stack konfigurieren**: + - **Name**: `laravel-app` + - **Build method**: Wähle "Repository" + - **Repository URL**: Gib deine Git-Repository-URL ein (falls vorhanden) + - Oder wähle "Upload" und lade `docker-compose.synology.yml` hoch + - Oder wähle "Web editor" und kopiere den Inhalt von `docker-compose.synology.yml` + +4. **Umgebungsvariablen setzen**: + Klicke auf "Add an environment variable" und füge folgende Variablen hinzu: + + ``` + APP_NAME=Laravel + APP_ENV=production + APP_KEY=base64:L9RVZ3pNFyAvTbMqicT1rL5GbgE+7lJerkU9wyc95H8= + APP_DEBUG=false + APP_URL=http://your-synology-ip:8080 + DB_CONNECTION2=pgsql + DB_HOST2=postgres + DB_PORT2=5432 + DB_DATABASE2=ingest_db + DB_USERNAME2=ingest_user + DB_PASSWORD2=dein_sicheres_passwort + ``` + +5. **Stack deployen**: + - Klicke auf "Deploy the stack" + - Warte, bis der Build-Prozess abgeschlossen ist (kann 5-10 Minuten dauern) + +### Methode 2: Build und Deploy manuell via SSH + +```bash +# SSH auf die Synology +ssh admin@your-synology-ip + +# Navigiere zum Projekt-Verzeichnis +cd /volume1/docker/laravel-app + +# Baue das Docker Image +docker build -t laravel-app:latest . + +# Starte die Services mit docker-compose +docker-compose -f docker-compose.synology.yml up -d +``` + +## 🔍 Verifikation + +### 1. Überprüfe den Container-Status + +In Portainer: +- Gehe zu "Containers" +- Du solltest zwei laufende Container sehen: + - `laravel_app` (Status: running, Port: 0.0.0.0:8080->80/tcp) + - `laravel_postgres` (Status: running, Port: 5432/tcp) + +Via SSH: +```bash +docker ps +``` + +### 2. Überprüfe die Logs + +In Portainer: +- Klicke auf den Container `laravel_app` +- Wähle "Logs" +- Du solltest keine Fehler sehen + +Via SSH: +```bash +# Laravel App Logs +docker logs laravel_app + +# PostgreSQL Logs +docker logs laravel_postgres +``` + +### 3. Teste die Anwendung + +Öffne deinen Browser und navigiere zu: +``` +http://your-synology-ip:8080 +``` + +Du solltest die Laravel-Anwendung sehen! + +## 🔧 Nützliche Befehle + +### Artisan-Befehle ausführen + +```bash +# Laravel Cache leeren +docker exec laravel_app php artisan cache:clear + +# Neuen APP_KEY generieren +docker exec laravel_app php artisan key:generate + +# Migrationen ausführen +docker exec laravel_app php artisan migrate + +# Seeder ausführen +docker exec laravel_app php artisan db:seed +``` + +### Container neustarten + +Via Portainer: +- Gehe zu "Containers" +- Wähle den Container aus +- Klicke auf "Restart" + +Via SSH: +```bash +docker-compose -f docker-compose.synology.yml restart +``` + +### Container stoppen und entfernen + +Via Portainer: +- Gehe zu "Stacks" +- Wähle den Stack "laravel-app" +- Klicke auf "Stop" oder "Delete" + +Via SSH: +```bash +docker-compose -f docker-compose.synology.yml down + +# Mit Volumes löschen (Achtung: Löscht die Datenbank!) +docker-compose -f docker-compose.synology.yml down -v +``` + +### Logs live verfolgen + +```bash +# Alle Container +docker-compose -f docker-compose.synology.yml logs -f + +# Nur Laravel App +docker logs -f laravel_app + +# Nur PostgreSQL +docker logs -f laravel_postgres +``` + +## 🔐 Sicherheitshinweise + +1. **APP_KEY ändern**: Generiere einen neuen APP_KEY für die Produktion: + ```bash + docker exec laravel_app php artisan key:generate + ``` + +2. **Datenbank-Passwort**: Ändere das Standard-PostgreSQL-Passwort in `.env.synology` + +3. **APP_DEBUG**: Stelle sicher, dass `APP_DEBUG=false` in der Produktion + +4. **Firewall**: Konfiguriere die Synology-Firewall, um nur benötigte Ports zu öffnen + +5. **SSL/HTTPS**: Für den Produktionsbetrieb solltest du einen Reverse Proxy (z.B. Synology DSM Reverse Proxy) mit SSL-Zertifikat einrichten + +## 🌐 Reverse Proxy einrichten (optional, aber empfohlen) + +Für den Zugriff über eine Domain mit HTTPS: + +1. **In Synology DSM**: + - Gehe zu "Systemsteuerung" → "Anmeldungsportal" → "Erweitert" + - Klicke auf "Reverse Proxy" → "Erstellen" + +2. **Konfiguration**: + - **Protokoll**: HTTPS + - **Hostname**: your-domain.com + - **Port**: 443 + - **Zielprotokoll**: HTTP + - **Zielhost**: localhost + - **Zielport**: 8080 + +3. **SSL-Zertifikat**: + - Gehe zu "Systemsteuerung" → "Sicherheit" → "Zertifikat" + - Füge ein Let's Encrypt-Zertifikat hinzu + +## 📊 Monitoring & Wartung + +### Container-Ressourcen überwachen + +In Portainer: +- Gehe zu "Containers" +- Wähle einen Container +- Klicke auf "Stats" für Echtzeit-Metriken (CPU, RAM, Netzwerk) + +### Backup + +```bash +# PostgreSQL Datenbank sichern +docker exec laravel_postgres pg_dump -U ingest_user ingest_db > backup_$(date +%Y%m%d).sql + +# Gesamten Stack sichern (inkl. Volumes) +docker run --rm \ + -v laravel-app_postgres-data:/data \ + -v /volume1/docker/backups:/backup \ + alpine tar czf /backup/postgres-backup-$(date +%Y%m%d).tar.gz /data +``` + +### Updates + +```bash +# Projekt-Code aktualisieren (wenn via Git) +cd /volume1/docker/laravel-app +git pull + +# Neu bauen und deployen +docker-compose -f docker-compose.synology.yml up -d --build + +# Migrationen ausführen +docker exec laravel_app php artisan migrate --force +``` + +## ❓ Troubleshooting + +### Problem: Container startet nicht + +```bash +# Logs prüfen +docker logs laravel_app + +# Container interaktiv starten für Debugging +docker exec -it laravel_app sh +``` + +### Problem: Datenbank-Verbindung fehlgeschlagen + +```bash +# PostgreSQL-Container prüfen +docker exec laravel_postgres pg_isready -U ingest_user + +# Umgebungsvariablen prüfen +docker exec laravel_app env | grep DB_ +``` + +### Problem: Permissions-Fehler + +```bash +# Storage-Permissions korrigieren +docker exec laravel_app chmod -R 775 storage bootstrap/cache +docker exec laravel_app chown -R nginx:nginx storage bootstrap/cache +``` + +### Problem: Port bereits belegt + +Wenn Port 8080 bereits verwendet wird: +1. Öffne `docker-compose.synology.yml` +2. Ändere die Port-Mapping: `"8081:80"` statt `"8080:80"` +3. Aktualisiere `APP_URL` in `.env.synology` entsprechend + +## 🤖 Automatisches Deployment mit Gitea Actions + +Wenn du Gitea auf deiner Synology NAS verwendest, kannst du den gesamten Build- und Deployment-Prozess automatisieren! + +### Vorteile von CI/CD + +- ✅ Automatischer Build bei jedem Git Push +- ✅ Automatische Tests vor Deployment +- ✅ Automatisches Deployment auf die NAS +- ✅ Rollback bei Fehlern +- ✅ Keine manuellen Schritte mehr nötig + +### Quick Start + +1. **Gitea Runner einrichten** + - Siehe detaillierte Anleitung: [GITEA_RUNNER_SETUP.md](GITEA_RUNNER_SETUP.md) + - Kurz: Runner Docker Container auf NAS deployen + - Runner in Gitea registrieren + +2. **Repository Secrets konfigurieren** + + Gehe in Gitea zu: **Repository → Settings → Secrets** + + Füge folgende Secrets hinzu: + ``` + SYNOLOGY_HOST=192.168.1.100 + SYNOLOGY_USER=admin + SYNOLOGY_SSH_KEY= + APP_KEY= + ``` + +3. **Workflow pushen** + + Der Workflow in [`.gitea/workflows/deploy-synology.yml`](.gitea/workflows/deploy-synology.yml) ist bereits vorkonfiguriert. + + ```bash + git add .gitea/workflows/deploy-synology.yml + git commit -m "ci: add automated deployment workflow" + git push origin main + ``` + +4. **Automatisches Deployment genießen! 🎉** + + Bei jedem Push auf `main` oder `develop`: + - Tests werden ausgeführt + - Docker Image wird gebaut + - Deployment auf NAS erfolgt automatisch + - Health Check verifiziert Deployment + +### Workflow-Ablauf + +```mermaid +graph LR + A[Git Push] --> B[Run Tests] + B --> C{Tests OK?} + C -->|Ja| D[Build Docker Image] + C -->|Nein| E[Abbruch] + D --> F[Transfer zu NAS] + F --> G[Deploy auf NAS] + G --> H[Health Check] + H --> I{Healthy?} + I -->|Ja| J[✅ Success] + I -->|Nein| K[Rollback] +``` + +### Workflow überwachen + +1. Gehe zu deinem Repository in Gitea +2. Klicke auf **Actions** +3. Siehe alle Workflow-Runs mit Status +4. Klicke auf einen Run für Details und Logs + +### Erweiterte Konfiguration + +Weitere Details zur CI/CD-Konfiguration findest du in: +- [GITEA_RUNNER_SETUP.md](GITEA_RUNNER_SETUP.md) - Detaillierte Runner-Setup Anleitung +- [`.gitea/workflows/deploy-synology.yml`](.gitea/workflows/deploy-synology.yml) - Workflow-Konfiguration +- [`scripts/deploy-synology.sh`](scripts/deploy-synology.sh) - Deployment-Script + +## 📝 Weitere Ressourcen + +- [Laravel Dokumentation](https://laravel.com/docs) +- [Docker Dokumentation](https://docs.docker.com/) +- [Portainer Dokumentation](https://docs.portainer.io/) +- [Synology Docker Anleitung](https://www.synology.com/en-us/dsm/packages/Docker) +- [Gitea Actions Dokumentation](https://docs.gitea.com/usage/actions/overview) + +## 🆘 Support + +Bei Problemen: +1. Prüfe die Container-Logs +2. Überprüfe die Umgebungsvariablen +3. Stelle sicher, dass alle Ports verfügbar sind +4. Prüfe die Synology-Firewall-Einstellungen +5. Bei CI/CD: Prüfe Gitea Actions Logs und Runner Status diff --git a/docker-compose.gitea-runner.yml b/docker-compose.gitea-runner.yml new file mode 100644 index 0000000..efba262 --- /dev/null +++ b/docker-compose.gitea-runner.yml @@ -0,0 +1,74 @@ +version: "3.9" + +# Gitea Runner für automatische CI/CD Deployments +# Dieses Compose-File wird auf der Synology NAS deployed + +services: + gitea-runner: + image: gitea/act_runner:latest + container_name: gitea-runner + restart: unless-stopped + + environment: + # Gitea Instance URL - Passe dies an deine Gitea-Installation an + - GITEA_INSTANCE_URL=${GITEA_URL:-http://gitea:3000} + + # Runner Registration Token - Wird aus Gitea UI generiert + - GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_TOKEN} + + # Runner Name - Wird in Gitea angezeigt + - GITEA_RUNNER_NAME=${RUNNER_NAME:-synology-runner} + + # Runner Labels - Definiert welche Workflows dieser Runner ausführen kann + # Format: label:docker://image + - GITEA_RUNNER_LABELS=ubuntu-latest:docker://catthehacker/ubuntu:act-latest,ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04,ubuntu-20.04:docker://catthehacker/ubuntu:act-20.04 + + # Runner Capacity - Maximale Anzahl gleichzeitiger Jobs + - GITEA_RUNNER_CAPACITY=${RUNNER_CAPACITY:-1} + + # Log Level + - GITEA_RUNNER_LOG_LEVEL=${LOG_LEVEL:-info} + + volumes: + # Runner Daten (Config, Cache, etc.) + - runner-data:/data + + # Docker Socket - Ermöglicht dem Runner Docker-Container zu starten + - /var/run/docker.sock:/var/run/docker.sock + + # Optional: Workspace für Job-Artefakte + - runner-workspace:/workspace + + networks: + - gitea-network + + # Health Check + healthcheck: + test: ["CMD", "pgrep", "-f", "act_runner"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + # Resource Limits (optional, aber empfohlen) + deploy: + resources: + limits: + cpus: '2' + memory: 2G + reservations: + cpus: '1' + memory: 512M + +volumes: + runner-data: + driver: local + runner-workspace: + driver: local + +networks: + gitea-network: + # Wenn Gitea in einem separaten Netzwerk läuft, verwende: + # external: true + # Ansonsten: + driver: bridge diff --git a/docker-compose.synology.yml b/docker-compose.synology.yml new file mode 100644 index 0000000..3277e53 --- /dev/null +++ b/docker-compose.synology.yml @@ -0,0 +1,91 @@ +version: "3.9" + +services: + app: + build: + context: . + dockerfile: Dockerfile + image: laravel-app:latest + container_name: laravel_app + restart: unless-stopped + + ports: + - "8080:80" # Angepasst für Synology (Port 81 oft belegt) + + environment: + # Laravel Environment + - APP_NAME=${APP_NAME:-Laravel} + - APP_ENV=${APP_ENV:-production} + - APP_KEY=${APP_KEY} + - APP_DEBUG=${APP_DEBUG:-false} + - APP_URL=${APP_URL:-http://localhost:8080} + + # Database - PostgreSQL + - DB_CONNECTION2=${DB_CONNECTION2:-pgsql} + - DB_HOST2=${DB_HOST2:-postgres} + - DB_PORT2=${DB_PORT2:-5432} + - DB_DATABASE2=${DB_DATABASE2:-ingest_db} + - DB_USERNAME2=${DB_USERNAME2:-ingest_user} + - DB_PASSWORD2=${DB_PASSWORD2:-ingest_pwd} + + # Session & Cache + - SESSION_DRIVER=${SESSION_DRIVER:-file} + - CACHE_STORE=${CACHE_STORE:-file} + - QUEUE_CONNECTION=${QUEUE_CONNECTION:-sync} + + # Logging + - LOG_CHANNEL=${LOG_CHANNEL:-stack} + - LOG_LEVEL=${LOG_LEVEL:-info} + + # Mail + - MAIL_MAILER=${MAIL_MAILER:-log} + + volumes: + - app-storage:/var/www/html/storage + - app-bootstrap-cache:/var/www/html/bootstrap/cache + - ./database:/var/www/html/database + + networks: + - laravel-network + + depends_on: + postgres: + condition: service_healthy + + postgres: + image: postgres:16-alpine + container_name: laravel_postgres + restart: unless-stopped + + environment: + - POSTGRES_DB=${DB_DATABASE2:-ingest_db} + - POSTGRES_USER=${DB_USERNAME2:-ingest_user} + - POSTGRES_PASSWORD=${DB_PASSWORD2:-ingest_pwd} + - PGDATA=/var/lib/postgresql/data/pgdata + + volumes: + - postgres-data:/var/lib/postgresql/data + + ports: + - "5432:5432" # Optional: Direktzugriff auf PostgreSQL + + networks: + - laravel-network + + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME2:-ingest_user}"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + postgres-data: + driver: local + app-storage: + driver: local + app-bootstrap-cache: + driver: local + +networks: + laravel-network: + driver: bridge diff --git a/routes/web.php b/routes/web.php index dac815a..37dad86 100644 --- a/routes/web.php +++ b/routes/web.php @@ -8,6 +8,15 @@ Route::get('/', function () { return view('welcome'); })->name('home'); +Route::get('/health', function () { + return response()->json([ + 'status' => 'healthy', + 'timestamp' => now()->toIso8601String(), + 'app' => config('app.name'), + 'env' => config('app.env'), + ]); +})->name('health'); + Route::view('dashboard', 'dashboard') ->middleware(['auth', 'verified']) ->name('dashboard'); diff --git a/scripts/deploy-synology.sh b/scripts/deploy-synology.sh new file mode 100755 index 0000000..8a2504d --- /dev/null +++ b/scripts/deploy-synology.sh @@ -0,0 +1,258 @@ +#!/bin/bash +# Deployment Script für Synology NAS +# Dieses Script wird auf der Synology NAS ausgeführt + +set -e # Exit on error + +# ============================================ +# Configuration +# ============================================ +PROJECT_DIR="/volume1/docker/laravel-app" +DOCKER_IMAGE="laravel-app" +COMPOSE_FILE="docker-compose.synology.yml" +ENV_FILE=".env.synology" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# ============================================ +# Helper Functions +# ============================================ +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# ============================================ +# Pre-deployment Checks +# ============================================ +log_info "Starting deployment process..." + +# Check if running on Synology +if [ ! -d "/volume1" ]; then + log_error "This script should be run on Synology NAS" + exit 1 +fi + +# Navigate to project directory +cd "$PROJECT_DIR" || { + log_error "Project directory not found: $PROJECT_DIR" + exit 1 +} + +# Check if Docker is installed +if ! command -v docker &> /dev/null; then + log_error "Docker is not installed" + exit 1 +fi + +# Check if docker-compose is installed +if ! command -v docker-compose &> /dev/null; then + log_error "docker-compose is not installed" + exit 1 +fi + +# ============================================ +# Load Docker Image +# ============================================ +if [ -f "laravel-app.tar.gz" ]; then + log_info "Loading Docker image from artifact..." + gunzip -c laravel-app.tar.gz | docker load + + # Tag the image appropriately + LOADED_IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep laravel-app | head -n1) + if [ -n "$LOADED_IMAGE" ]; then + docker tag "$LOADED_IMAGE" "${DOCKER_IMAGE}:latest" + log_info "Tagged image as ${DOCKER_IMAGE}:latest" + fi +else + log_warn "No Docker image artifact found. Using existing image or building..." + + # Check if Dockerfile exists and build if necessary + if [ -f "Dockerfile" ]; then + log_info "Building Docker image..." + docker build -t "${DOCKER_IMAGE}:latest" . + else + log_error "Neither Docker artifact nor Dockerfile found" + exit 1 + fi +fi + +# ============================================ +# Environment Configuration +# ============================================ +if [ ! -f "$ENV_FILE" ]; then + log_warn "Environment file not found: $ENV_FILE" + + if [ -f ".env.synology.example" ]; then + log_info "Copying from .env.synology.example..." + cp .env.synology.example "$ENV_FILE" + log_warn "⚠️ Please configure $ENV_FILE with your settings!" + else + log_error "No environment configuration found" + exit 1 + fi +fi + +# ============================================ +# Backup Current Deployment +# ============================================ +log_info "Creating backup of current deployment..." + +BACKUP_DIR="/volume1/docker/backups/laravel-app" +mkdir -p "$BACKUP_DIR" + +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +BACKUP_FILE="$BACKUP_DIR/backup_${TIMESTAMP}.tar.gz" + +# Backup database if container is running +if docker ps --format '{{.Names}}' | grep -q "laravel_postgres"; then + log_info "Backing up PostgreSQL database..." + docker exec laravel_postgres pg_dump -U ingest_user ingest_db > "$BACKUP_DIR/db_${TIMESTAMP}.sql" +fi + +# Keep only last 5 backups +log_info "Cleaning old backups (keeping last 5)..." +ls -t "$BACKUP_DIR"/db_*.sql 2>/dev/null | tail -n +6 | xargs -r rm + +# ============================================ +# Stop Current Containers +# ============================================ +log_info "Stopping current containers..." + +if [ -f "$COMPOSE_FILE" ]; then + docker-compose -f "$COMPOSE_FILE" down || log_warn "No containers to stop" +else + log_warn "Compose file not found: $COMPOSE_FILE" +fi + +# ============================================ +# Clean up old images (optional) +# ============================================ +log_info "Cleaning up old Docker images..." +docker image prune -f + +# ============================================ +# Start New Deployment +# ============================================ +log_info "Starting new deployment..." + +if [ ! -f "$COMPOSE_FILE" ]; then + log_error "Docker Compose file not found: $COMPOSE_FILE" + exit 1 +fi + +# Pull/use latest images and start services +docker-compose -f "$COMPOSE_FILE" up -d --build + +# ============================================ +# Wait for Services to Start +# ============================================ +log_info "Waiting for services to start..." +sleep 10 + +# Check if containers are running +if ! docker ps --format '{{.Names}}' | grep -q "laravel_app"; then + log_error "Laravel app container failed to start" + + # Show logs + log_info "Container logs:" + docker-compose -f "$COMPOSE_FILE" logs --tail=50 + + # Rollback + log_warn "Attempting rollback..." + docker-compose -f "$COMPOSE_FILE" down + exit 1 +fi + +# ============================================ +# Post-deployment Tasks +# ============================================ +log_info "Running post-deployment tasks..." + +# Wait for database to be ready +log_info "Waiting for database to be ready..." +sleep 5 + +# Run migrations +log_info "Running database migrations..." +docker exec laravel_app php artisan migrate --force || log_warn "Migrations failed" + +# Clear caches +log_info "Clearing caches..." +docker exec laravel_app php artisan cache:clear || log_warn "Cache clear failed" +docker exec laravel_app php artisan config:clear || log_warn "Config clear failed" +docker exec laravel_app php artisan view:clear || log_warn "View clear failed" + +# Optimize +log_info "Optimizing application..." +docker exec laravel_app php artisan config:cache || log_warn "Config cache failed" +docker exec laravel_app php artisan route:cache || log_warn "Route cache failed" +docker exec laravel_app php artisan view:cache || log_warn "View cache failed" + +# ============================================ +# Health Check +# ============================================ +log_info "Performing health check..." + +MAX_RETRIES=30 +RETRY_COUNT=0 +HEALTH_CHECK_URL="http://localhost:8080" + +while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do + if curl -f -s "$HEALTH_CHECK_URL" > /dev/null 2>&1; then + log_info "✅ Application is healthy!" + break + fi + + log_info "⏳ Waiting for application... ($RETRY_COUNT/$MAX_RETRIES)" + sleep 5 + RETRY_COUNT=$((RETRY_COUNT + 1)) +done + +if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then + log_error "Health check failed after $MAX_RETRIES attempts" + + # Show recent logs + log_info "Recent application logs:" + docker-compose -f "$COMPOSE_FILE" logs --tail=100 + + exit 1 +fi + +# ============================================ +# Display Status +# ============================================ +log_info "Deployment completed successfully! 🚀" +log_info "Container status:" +docker-compose -f "$COMPOSE_FILE" ps + +log_info "" +log_info "===================================" +log_info "Application URL: http://$(hostname -I | awk '{print $1}'):8080" +log_info "===================================" +log_info "" +log_info "Useful commands:" +log_info " - View logs: docker-compose -f $COMPOSE_FILE logs -f" +log_info " - Restart: docker-compose -f $COMPOSE_FILE restart" +log_info " - Stop: docker-compose -f $COMPOSE_FILE down" +log_info " - Shell access: docker exec -it laravel_app sh" + +# ============================================ +# Cleanup +# ============================================ +log_info "Cleaning up deployment artifacts..." +rm -f laravel-app.tar.gz + +log_info "Deployment script completed!" +exit 0