diff --git a/.gitea/workflows/CI_CD_CHECKLIST.md b/.gitea/workflows/CI_CD_CHECKLIST.md index 740dca8b..ed775542 100644 --- a/.gitea/workflows/CI_CD_CHECKLIST.md +++ b/.gitea/workflows/CI_CD_CHECKLIST.md @@ -20,7 +20,7 @@ bash scripts/prepare-secrets.sh **Hinweis**: Alle Secrets müssen in Gitea konfiguriert werden, bevor die Pipeline läuft. ### 2. Docker Registry ✅ -- ✅ Registry läuft auf `git.michaelschiemer.de:5000` +- ✅ Registry läuft auf `registry.michaelschiemer.de` - ✅ Authentifizierung konfiguriert (admin/registry-secure-password-2025) - ✅ Erreichbar via HTTP auf `127.0.0.1:5000` - ✅ Image `framework` bereits vorhanden diff --git a/.gitea/workflows/REGISTRY_INFO.md b/.gitea/workflows/REGISTRY_INFO.md index d4bd3b43..32a72d2e 100644 --- a/.gitea/workflows/REGISTRY_INFO.md +++ b/.gitea/workflows/REGISTRY_INFO.md @@ -2,7 +2,7 @@ ## Registry Details -- **URL**: `git.michaelschiemer.de:5000` (intern) oder `registry.michaelschiemer.de` (via Traefik) +- **URL**: `registry.michaelschiemer.de` (intern) oder `registry.michaelschiemer.de` (via Traefik) - **Standard Credentials**: - **Username**: `admin` - **Password**: `registry-secure-password-2025` @@ -20,10 +20,10 @@ Verwende folgende Werte in den Gitea Repository Secrets: ```bash # Login testen -echo "registry-secure-password-2025" | docker login git.michaelschiemer.de:5000 -u admin --password-stdin +echo "registry-secure-password-2025" | docker login registry.michaelschiemer.de -u admin --password-stdin # Images auflisten -curl -u admin:registry-secure-password-2025 http://git.michaelschiemer.de:5000/v2/_catalog +curl -u admin:registry-secure-password-2025 http://registry.michaelschiemer.de/v2/_catalog # Oder via Traefik (HTTPS) curl -u admin:registry-secure-password-2025 https://registry.michaelschiemer.de/v2/_catalog diff --git a/.gitea/workflows/SECRETS_SETUP.md b/.gitea/workflows/SECRETS_SETUP.md index 78a57149..d52d4507 100644 --- a/.gitea/workflows/SECRETS_SETUP.md +++ b/.gitea/workflows/SECRETS_SETUP.md @@ -14,7 +14,7 @@ Diese Secrets müssen in Gitea konfiguriert werden unter: ### 2. REGISTRY_PASSWORD - **Beschreibung**: Passwort für Docker Registry Login - **Typ**: Password (versteckt) -- **Wert**: Das Passwort für die Docker Registry auf `git.michaelschiemer.de:5000` +- **Wert**: Das Passwort für die Docker Registry auf `registry.michaelschiemer.de` - **Verwendung**: Docker Registry Authentication beim Image Push ### 3. SSH_PRIVATE_KEY diff --git a/.gitea/workflows/production-deploy.yml b/.gitea/workflows/production-deploy.yml index ec3bd006..ce0ed287 100644 --- a/.gitea/workflows/production-deploy.yml +++ b/.gitea/workflows/production-deploy.yml @@ -18,7 +18,7 @@ on: type: boolean env: - REGISTRY: git.michaelschiemer.de:5000 + REGISTRY: registry.michaelschiemer.de IMAGE_NAME: framework DEPLOYMENT_HOST: 94.16.110.151 @@ -248,10 +248,9 @@ jobs: chmod 600 ~/.ssh/production ssh-keyscan -H ${{ env.DEPLOYMENT_HOST }} >> ~/.ssh/known_hosts - - name: Install Ansible - run: | - apt-get update - apt-get install -y ansible + # Ansible is pre-installed in php-ci image + - name: Verify Ansible installation + run: ansible --version - name: Deploy via Ansible run: | diff --git a/deployment/APPLICATION_STACK_DEPLOYMENT.md b/deployment/APPLICATION_STACK_DEPLOYMENT.md index 0a9b856d..afde4d84 100644 --- a/deployment/APPLICATION_STACK_DEPLOYMENT.md +++ b/deployment/APPLICATION_STACK_DEPLOYMENT.md @@ -43,9 +43,9 @@ CI/CD Pipeline (Gitea Actions) ```yaml - Docker Image Build (Dockerfile.production) - Image mit Tags pushen: - - git.michaelschiemer.de:5000/framework:latest - - git.michaelschiemer.de:5000/framework: - - git.michaelschiemer.de:5000/framework:git- + - registry.michaelschiemer.de/framework:latest + - registry.michaelschiemer.de/framework: + - registry.michaelschiemer.de/framework:git- ``` #### Job 3: Deploy (Ansible) @@ -121,7 +121,7 @@ docker compose -f ~/deployment/stacks/application/docker-compose.yml \ **2. Docker Registry Login** ```bash # Login zur privaten Registry mit Credentials -docker login git.michaelschiemer.de:5000 \ +docker login registry.michaelschiemer.de \ -u \ -p ``` @@ -129,10 +129,10 @@ docker login git.michaelschiemer.de:5000 \ **3. Neues Image Pullen** ```bash # Pullt das neue Image von der Registry -docker pull git.michaelschiemer.de:5000/framework: +docker pull registry.michaelschiemer.de/framework: # Beispiel: -# git.michaelschiemer.de:5000/framework:abc1234-1696234567 +# registry.michaelschiemer.de/framework:abc1234-1696234567 ``` **4. docker-compose.yml aktualisieren** @@ -143,12 +143,12 @@ docker pull git.michaelschiemer.de:5000/framework: # Vorher: services: app: - image: git.michaelschiemer.de:5000/framework:latest + image: registry.michaelschiemer.de/framework:latest # Nachher (wenn image_tag != 'latest'): services: app: - image: git.michaelschiemer.de:5000/framework: + image: registry.michaelschiemer.de/framework: ``` **Regex-Replace:** @@ -158,13 +158,13 @@ replace: '\1{{ app_image }}:{{ image_tag }}' ``` **Betroffene Services (werden alle aktualisiert):** -- `app` (PHP-FPM) - Zeile 6: `image: git.michaelschiemer.de:5000/framework:latest` -- `queue-worker` (Queue Worker) - Zeile 120: `image: git.michaelschiemer.de:5000/framework:latest` -- `scheduler` (Scheduler) - Zeile 165: `image: git.michaelschiemer.de:5000/framework:latest` +- `app` (PHP-FPM) - Zeile 6: `image: registry.michaelschiemer.de/framework:latest` +- `queue-worker` (Queue Worker) - Zeile 120: `image: registry.michaelschiemer.de/framework:latest` +- `scheduler` (Scheduler) - Zeile 165: `image: registry.michaelschiemer.de/framework:latest` **Hinweis:** - Alle drei Services verwenden das gleiche Image, daher werden alle mit dem neuen Tag aktualisiert -- Der Regex matched **alle Zeilen** die mit `image: git.michaelschiemer.de:5000/framework:` beginnen +- Der Regex matched **alle Zeilen** die mit `image: registry.michaelschiemer.de/framework:` beginnen - `nginx` und `redis` bleiben unverändert (verwenden andere Images) **5. Application Stack neu starten** @@ -216,7 +216,7 @@ docker compose ps --format json | \ Deployment Timestamp: 2025-10-31T02:35:04Z Git Commit: abc1234... Image Tag: abc1234-1696234567 -Deployed Image: git.michaelschiemer.de:5000/framework:abc1234-1696234567 +Deployed Image: registry.michaelschiemer.de/framework:abc1234-1696234567 Image Pull: SUCCESS Stack Deploy: UPDATED Health Status: All services healthy @@ -238,7 +238,7 @@ Der Application Stack besteht aus mehreren Services: #### Services im Stack **1. `app` (PHP-FPM Application)** -- Image: `git.michaelschiemer.de:5000/framework:` +- Image: `registry.michaelschiemer.de/framework:` - Container: `app` - Health Check: `php-fpm-healthcheck` - Netzwerk: `app-internal` @@ -259,7 +259,7 @@ Der Application Stack besteht aus mehreren Services: - Netzwerk: `app-internal` **4. `queue-worker` (Background Jobs)** -- Image: `git.michaelschiemer.de:5000/framework:` (gleiches wie app) +- Image: `registry.michaelschiemer.de/framework:` (gleiches wie app) - Container: `queue-worker` - Health Check: `pgrep -f 'queue:work'` - Netzwerk: `app-internal` @@ -267,7 +267,7 @@ Der Application Stack besteht aus mehreren Services: - Abhängigkeiten: `app`, `redis` **5. `scheduler` (Cron Jobs)** -- Image: `git.michaelschiemer.de:5000/framework:` (gleiches wie app) +- Image: `registry.michaelschiemer.de/framework:` (gleiches wie app) - Container: `scheduler` - Health Check: `pgrep -f 'scheduler:run'` - Netzwerk: `app-internal` @@ -307,8 +307,8 @@ Der Application Stack besteht aus mehreren Services: ### Inventory-Variablen (`inventory/production.yml`) ```yaml -app_image: "git.michaelschiemer.de:5000/framework" -docker_registry_url: "git.michaelschiemer.de:5000" +app_image: "registry.michaelschiemer.de/framework" +docker_registry_url: "registry.michaelschiemer.de" backups_path: "~/deployment/backups" max_rollback_versions: 5 deploy_user_home: "~/deployment" @@ -339,9 +339,9 @@ docker_registry_password: "" **2. Image wird gebaut und gepusht:** ```bash docker buildx build \ - --tag git.michaelschiemer.de:5000/framework:latest \ - --tag git.michaelschiemer.de:5000/framework:abc1234-1696234567 \ - --tag git.michaelschiemer.de:5000/framework:git-abc1234 \ + --tag registry.michaelschiemer.de/framework:latest \ + --tag registry.michaelschiemer.de/framework:abc1234-1696234567 \ + --tag registry.michaelschiemer.de/framework:git-abc1234 \ --push \ . ``` @@ -361,14 +361,14 @@ ansible-playbook -i inventory/production.yml \ mkdir -p ~/deployment/backups/2025-10-31T02-35-04Z # 2. Registry Login -docker login git.michaelschiemer.de:5000 -u admin -p +docker login registry.michaelschiemer.de -u admin -p # 3. Image Pullen -docker pull git.michaelschiemer.de:5000/framework:abc1234-1696234567 +docker pull registry.michaelschiemer.de/framework:abc1234-1696234567 # 4. docker-compose.yml aktualisieren -# Vorher: image: git.michaelschiemer.de:5000/framework:latest -# Nachher: image: git.michaelschiemer.de:5000/framework:abc1234-1696234567 +# Vorher: image: registry.michaelschiemer.de/framework:latest +# Nachher: image: registry.michaelschiemer.de/framework:abc1234-1696234567 # 5. Stack neu starten cd ~/deployment/stacks/application @@ -392,7 +392,7 @@ cat > ~/deployment/backups/2025-10-31T02-35-04Z/deployment_metadata.txt < +docker login registry.michaelschiemer.de -u admin -p # Image manuell pullen -docker pull git.michaelschiemer.de:5000/framework: +docker pull registry.michaelschiemer.de/framework: ``` ### docker-compose.yml wurde nicht aktualisiert ```bash # Prüfe ob Regex korrekt ist -grep -E "image:\s+git.michaelschiemer.de:5000/framework" \ +grep -E "image:\s+registry.michaelschiemer.de/framework" \ ~/deployment/stacks/application/docker-compose.yml # Prüfe Backup für vorherige Version diff --git a/deployment/CI_CD_STATUS.md b/deployment/CI_CD_STATUS.md index 9611346a..98c2d7df 100644 --- a/deployment/CI_CD_STATUS.md +++ b/deployment/CI_CD_STATUS.md @@ -49,7 +49,7 @@ admin **REGISTRY_PASSWORD:** ``` - + ``` *Zu finden in: `deployment/stacks/registry/auth/htpasswd` oder manuell gesetzt* @@ -260,7 +260,7 @@ https://git.michaelschiemer.de/admin/actions/runners - Prüfe `REGISTRY_USER` und `REGISTRY_PASSWORD` Secrets - Teste Registry-Login manuell: ```bash - docker login git.michaelschiemer.de:5000 -u admin -p + docker login registry.michaelschiemer.de -u admin -p ``` ### SSH-Verbindung fehlschlägt diff --git a/deployment/CODE_CHANGE_WORKFLOW.md b/deployment/CODE_CHANGE_WORKFLOW.md index 2e1f3e5c..8fb4ab62 100644 --- a/deployment/CODE_CHANGE_WORKFLOW.md +++ b/deployment/CODE_CHANGE_WORKFLOW.md @@ -159,9 +159,9 @@ git push origin feature/new-feature - Image Metadata generieren (Tag: -) - Docker Image Build (Dockerfile.production) - Image mit Tags pushen: - - git.michaelschiemer.de:5000/framework:latest - - git.michaelschiemer.de:5000/framework: - - git.michaelschiemer.de:5000/framework:git- + - registry.michaelschiemer.de/framework:latest + - registry.michaelschiemer.de/framework: + - registry.michaelschiemer.de/framework:git- ``` #### Job 3: Deploy (ca. 2-4 Minuten) diff --git a/deployment/GIT_DEPLOYMENT_ISSUE.md b/deployment/GIT_DEPLOYMENT_ISSUE.md new file mode 100644 index 00000000..3e9edf60 --- /dev/null +++ b/deployment/GIT_DEPLOYMENT_ISSUE.md @@ -0,0 +1,73 @@ +# Git Deployment - Problem gefunden + +**Datum:** 2025-01-31 +**Status:** ⚠️ Image muss neu gepusht werden + +## 🔍 Problem identifiziert + +### Prüfung ergab: +- ❌ Keine Git-Logs im Container +- ❌ `GIT_REPOSITORY_URL` nicht als Environment-Variable gesetzt +- ❌ Kein `.git` Verzeichnis im Container +- ❌ Entrypoint-Script zeigt keine Git-Funktionalität + +### Ursache: +**Das Image auf dem Production-Server enthält noch die alte Version ohne Git-Funktionalität.** + +Das lokal gebaute Image wurde noch nicht zur Registry gepusht, daher verwendet der Production-Server noch das alte Image. + +--- + +## ✅ Lösung + +### Schritt 1: Image zur Registry pushen + +```bash +# Lokal (auf Dev-Machine) +docker push registry.michaelschiemer.de/framework:latest +``` + +### Schritt 2: Image auf Production-Server aktualisieren + +```bash +# Via Ansible +cd deployment/ansible +ansible production -i inventory/production.yml -m shell -a "docker pull registry.michaelschiemer.de/framework:latest" +``` + +### Schritt 3: Container neu starten + +```bash +# Via Ansible +cd deployment/ansible +ansible-playbook -i inventory/production.yml playbooks/sync-code.yml -e "git_repo_url=https://git.michaelschiemer.de/michael/michaelschiemer.git" -e "git_branch=main" +``` + +**Oder direkt:** +```bash +# Auf Production-Server +cd ~/deployment/stacks/application +docker compose pull app +docker compose up -d app +``` + +--- + +## 🔄 Alternativer Workflow + +Falls du das Image über die CI/CD Pipeline pushen möchtest: + +1. **Commit und Push** der Änderungen zu `main` +2. **CI/CD Pipeline** baut automatisch das Image und pusht es +3. **Dann** `sync-code.yml` ausführen + +--- + +## 📋 Checkliste + +- [ ] Image lokal gebaut ✅ +- [ ] Git-Variablen in .env gesetzt ✅ +- [ ] Image zur Registry pushen ❌ **TODO** +- [ ] Image auf Production-Server pullen ❌ **TODO** +- [ ] Container neu starten ❌ **TODO** +- [ ] Logs prüfen ❌ **TODO** diff --git a/deployment/IMPROVEMENTS.md b/deployment/IMPROVEMENTS.md new file mode 100644 index 00000000..16bf7c6f --- /dev/null +++ b/deployment/IMPROVEMENTS.md @@ -0,0 +1,260 @@ +# Deployment System - Verbesserungsvorschläge + +**Erstellt:** 2025-01-31 +**Status:** Vorschläge zur Diskussion + +--- + +## 🔍 Gefundene Redundanzen und Verbesserungsmöglichkeiten + +### 1. ❌ **Dokumentations-Redundanz** + +#### Problem: +- **38+ Markdown-Dateien** im `deployment/` und `docs/deployment/` Verzeichnis +- Viele veraltete Dokumentationsdateien in `docs/deployment/` +- Überschneidende Inhalte zwischen mehreren Dateien + +#### Konkrete Redundanzen: +- `DEPLOYMENT_SUMMARY.md` vs `DEPLOYMENT-TODO.md` (ähnliche Status-Übersichten) +- `NATIVE-WORKFLOW-README.md` (veraltet? bereits durch CI/CD Pipeline ersetzt) +- `docs/deployment/*` - Viele veraltete Guides (Swarm, alte Workflows, etc.) + +#### Empfehlung: +```bash +# Dateien die gelöscht/archiviert werden könnten: +- deployment/NATIVE-WORKFLOW-README.md # Durch CI/CD Pipeline ersetzt +- docs/deployment/docker-swarm-deployment.md # Swarm nicht mehr verwendet +- docs/deployment/DEPLOYMENT_RESTRUCTURE.md # Historisch +- docs/deployment/* (viele veraltete Dateien) +``` + +**Lösung:** +- Dokumentation konsolidieren auf: + - `README.md` - Haupt-Dokumentation + - `QUICK_START.md` - Schnellstart + - `DEPLOYMENT_COMMANDS.md` - Command-Referenz + - `CODE_CHANGE_WORKFLOW.md` - Workflow-Dokumentation + - `SETUP-GUIDE.md` - Setup-Anleitung + - Stack-spezifische READMEs in `stacks/*/README.md` + +--- + +### 2. ❌ **Playbook-Redundanz: Troubleshooting Playbooks** + +#### Problem: +4 separate Playbooks für ähnliche Troubleshooting-Aufgaben: +- `check-container-health.yml` - Prüft Health Status +- `diagnose-404.yml` - Diagnostiziert 404 Fehler +- `fix-container-health-checks.yml` - Fixes Health Checks +- `fix-nginx-404.yml` - Fixes Nginx 404 + +#### Empfehlung: +**Konsolidieren zu einem einzigen Playbook** `troubleshoot.yml` mit Tags: + +```yaml +# deployment/ansible/playbooks/troubleshoot.yml +--- +- name: Application Troubleshooting + hosts: production + gather_facts: yes + become: no + + tasks: + - name: Check container health + include_tasks: tasks/check-health.yml + tags: ['health', 'check'] + + - name: Diagnose 404 errors + include_tasks: tasks/diagnose-404.yml + tags: ['404', 'diagnose'] + + - name: Fix container health checks + include_tasks: tasks/fix-health-checks.yml + tags: ['health', 'fix'] + + - name: Fix nginx 404 + include_tasks: tasks/fix-nginx-404.yml + tags: ['nginx', '404', 'fix'] +``` + +**Verwendung:** +```bash +# Nur Diagnose +ansible-playbook ... troubleshoot.yml --tags diagnose + +# Nur Fix +ansible-playbook ... troubleshoot.yml --tags fix + +# Alles +ansible-playbook ... troubleshoot.yml +``` + +**Vorteile:** +- Weniger Redundanz +- Einfacher zu warten +- Konsistente Struktur + +--- + +### 3. ⚠️ **Variablen-Redundanz** + +#### Problem: +Jedes Playbook definiert eigene Pfade: +```yaml +# In vielen Playbooks: +vars: + app_stack_path: "{{ deploy_user_home }}/deployment/stacks/application" + stacks_base_path: "~/deployment/stacks" +``` + +#### Empfehlung: +**Zentrale Variablendefinition** in `group_vars/production.yml`: + +```yaml +# deployment/ansible/group_vars/production.yml +--- +# Base paths +deploy_user_home: "~" +stacks_base_path: "{{ deploy_user_home }}/deployment/stacks" +app_stack_path: "{{ stacks_base_path }}/application" +backups_path: "{{ deploy_user_home }}/deployment/backups" + +# Registry +docker_registry_url: "registry.michaelschiemer.de" +app_image: "{{ docker_registry_url }}/framework" +app_name: "framework" + +# Health checks +health_check_url: "https://michaelschiemer.de/health" +max_rollback_versions: 5 +``` + +**Vorteile:** +- Einmal definiert, überall verwendbar +- Einfacher zu ändern +- Konsistenz über alle Playbooks + +--- + +### 4. ❓ **Playbook: `sync-stacks.yml`** + +#### Problem: +`sync-stacks.yml` synchronisiert Stack-Dateien zu Production, aber: +- `setup-infrastructure.yml` deployed die Stacks bereits direkt +- Wird wahrscheinlich nicht mehr benötigt? + +#### Empfehlung: +**Entweder:** +1. **Löschen** wenn nicht mehr verwendet +2. **Oder dokumentieren** wann es noch gebraucht wird + +--- + +### 5. ❓ **Stack-Redundanz: `postgres/` vs `postgresql/`** + +#### Problem: +Es gibt beide Ordner: +- `deployment/stacks/postgres/` +- `deployment/stacks/postgresql/` + +Einer scheint leer zu sein? + +#### Empfehlung: +- Prüfen welcher verwendet wird +- Leeren Ordner löschen +- Konsistente Namensgebung verwenden + +--- + +### 6. ✅ **Playbook: WireGuard Dokumentation** + +#### Positiv: +WireGuard hat separate README (`README-WIREGUARD.md`) - das ist gut strukturiert! + +**Könnte als Vorbild dienen** für andere komplexe Features. + +--- + +### 7. ⚠️ **Templates: Mehrfache .env Templates** + +#### Problem: +- `ansible/templates/application.env.j2` +- `ansible/templates/monitoring.env.j2` +- Gibt es weitere? + +#### Empfehlung: +**Template-Verzeichnis strukturieren:** +``` +ansible/templates/ +├── env/ +│ ├── application.env.j2 +│ ├── monitoring.env.j2 +│ └── ... +└── config/ + ├── wireguard-server.conf.j2 + └── ... +``` + +--- + +### 8. ✅ **Verbesserung: Zentrales Playbook für Common Tasks** + +#### Empfehlung: +**Common Tasks als Reusable Roles/Tasks**: + +```yaml +# deployment/ansible/roles/common/tasks/verify-stack.yml +--- +- name: Verify stack directory exists + stat: + path: "{{ stack_path }}" + register: stack_dir + +- name: Fail if stack directory doesn't exist + fail: + msg: "Stack directory not found at {{ stack_path }}" + when: not stack_dir.stat.exists +``` + +**Verwendung in Playbooks:** +```yaml +- name: Verify application stack + include_role: + name: common + tasks_from: verify-stack + vars: + stack_path: "{{ app_stack_path }}" +``` + +**Vorteile:** +- DRY (Don't Repeat Yourself) +- Konsistenz +- Einfacher zu warten + +--- + +## 📊 Priorisierte Empfehlungen + +### 🔴 Hoch (sofort umsetzbar): +1. **Zentrale Variablen** → `group_vars/production.yml` +2. **Dokumentation aufräumen** → Veraltete Dateien löschen/archivieren +3. **Stack-Redundanz prüfen** → `postgres/` vs `postgresql/` + +### 🟡 Mittel (bald umsetzen): +4. **Troubleshooting Playbooks konsolidieren** → Ein Playbook mit Tags +5. **Common Tasks als Roles** → Redundanz reduzieren + +### 🟢 Niedrig (nice to have): +6. **Template-Struktur verbessern** +7. **Playbook `sync-stacks.yml` prüfen** → Ob noch benötigt + +--- + +## 📝 Nächste Schritte + +1. ✅ Redundante Scripts entfernt +2. ⏳ Dokumentation aufräumen +3. ⏳ Zentrale Variablen erstellen +4. ⏳ Troubleshooting Playbooks konsolidieren + +**Soll ich mit der Umsetzung beginnen?** diff --git a/deployment/NEXT_STEPS.md b/deployment/NEXT_STEPS.md index f1cff3ad..cfdef65e 100644 --- a/deployment/NEXT_STEPS.md +++ b/deployment/NEXT_STEPS.md @@ -1,103 +1,48 @@ -# Nächste Schritte - Deployment Projekt +# Git Deployment - Nächste Schritte -**Stand:** 2025-10-31 -**Status:** ✅ CI/CD Pipeline vollständig konfiguriert +## ✅ Was funktioniert: +- Git-Variablen in `.env` gesetzt ✅ +- Ansible Playbook funktioniert ✅ +- Container neu gestartet ✅ ---- +## ❌ Was noch fehlt: +- **Image enthält noch alte Version** ohne Git-Funktionalität +- Environment-Variablen werden nicht geladen -## 🎯 Nächster kritischer Schritt +## 🔧 Lösung: -### Pipeline End-to-End testen - -**Warum kritisch:** -- Alles ist konfiguriert, aber noch nicht getestet -- Erster kompletter Durchlauf zeigt eventuelle Probleme -- Bestätigt, dass alles funktioniert - -**Option 1: Test-Commit pushen (Empfohlen)** +### Option 1: Image lokal pushen (Schnell) ```bash -# Kleine, ungefährliche Änderung -echo "# Deployment Test $(date)" >> README.md -git add README.md -git commit -m "test: CI/CD pipeline end-to-end test" -git push origin main - -# Pipeline beobachten: -# → https://git.michaelschiemer.de/michael/michaelschiemer/actions +# Im Projekt-Root +docker push registry.michaelschiemer.de/framework:latest ``` -**Option 2: Workflow manuell triggern** - -1. Gehe zu: `https://git.michaelschiemer.de/michael/michaelschiemer/actions` -2. Wähle: "Production Deployment Pipeline" -3. Klicke: "Run workflow" -4. Branch: `main` -5. `skip_tests`: `false` (Tests sollen laufen) -6. Klicke: "Run workflow" - -**Was zu prüfen:** -- ✅ Tests erfolgreich -- ✅ Build erfolgreich -- ✅ Deployment erfolgreich -- ✅ Application läuft auf Production -- ✅ Health-Check erfolgreich - -**Zeit:** ~8-15 Minuten - ---- - -## 📋 Weitere Schritte (Optional) - -### 2. Backup-Playbook erstellen - -**Status:** Optional - -**Was zu tun:** +Dann Container neu starten: ```bash -cd deployment/ansible/playbooks -# Erstelle backup.yml -# → Backup Application Stack Volumes -# → Integration PostgreSQL Backup -# → Gitea Data Backup +cd deployment/ansible +ansible-playbook -i inventory/production.yml playbooks/sync-code.yml \ + -e "git_repo_url=https://git.michaelschiemer.de/michael/michaelschiemer.git" \ + -e "git_branch=main" ``` -**Priorität:** Niedrig (Rollback funktioniert bereits) +### Option 2: Via CI/CD (Empfohlen für Production) -### 3. Dokumentation finalisieren - -**Status:** Optional - -**Was zu tun:** -- `DEPLOYMENT-STATUS.md` mit finalem Status aktualisieren -- Eventuelle Verbesserungen dokumentieren - -**Priorität:** Niedrig (Haupt-Dokumentation ist fertig) +1. **Commit und Push** deiner Änderungen +2. **CI/CD Pipeline** baut automatisch das Image +3. **Dann** `sync-code.yml` ausführen --- -## ✅ Was ist bereits fertig? +## 📊 Zusammenfassung -- ✅ Infrastructure Stacks (100%) -- ✅ Application Stack Integration (100%) -- ✅ CI/CD Pipeline Konfiguration (100%) -- ✅ Dokumentation (95%) -- ✅ Gitea Runner (läuft) -- ✅ Secrets (konfiguriert) +**Status:** Setup abgeschlossen, Image muss aktualisiert werden -**Gesamt-Completion:** ~95% +**Alle Komponenten sind bereit:** +- ✅ Entrypoint Script mit Git-Funktionalität +- ✅ Dockerfile mit Git + Composer +- ✅ Docker Compose mit Git Environment Variables +- ✅ Ansible Playbook für Git-Sync +- ✅ .env mit Git-Variablen ---- - -## 🚀 Ready to Deploy! - -**Alles ist bereit für das erste Deployment!** - -Die Pipeline ist vollständig konfiguriert: -- ✅ Workflows vorhanden -- ✅ Secrets konfiguriert -- ✅ Runner läuft -- ✅ Ansible Playbooks vorhanden -- ✅ Dokumentation vorhanden - -**Nächster Schritt:** Einfach einen Test-Commit pushen! 🎉 +**Nur noch:** Image pushen und Container neu starten! diff --git a/deployment/RECOMMENDED_TEST_FLOW.md b/deployment/RECOMMENDED_TEST_FLOW.md new file mode 100644 index 00000000..8b885047 --- /dev/null +++ b/deployment/RECOMMENDED_TEST_FLOW.md @@ -0,0 +1,144 @@ +# 🎯 Empfohlener Test-Workflow für Git-Deployment + +## Meine Empfehlung: **Schritt-für-Schritt mit Checks** + +### Warum? +- ✅ Minimiert Risiko von Fehlern +- ✅ Erlaubt Verifikation nach jedem Schritt +- ✅ Einfaches Rollback bei Problemen +- ✅ Klare Fehlerdiagnose + +--- + +## 📋 Workflow + +### Schritt 1: Image pushen (falls nötig) + +**Wann nötig?** +- Wenn Production-Server das Image aus der Registry zieht +- Wenn Image lokal gebaut wurde und noch nicht gepusht + +**Befehl:** +```bash +# Im Projekt-Root +docker push registry.michaelschiemer.de/framework:latest +``` + +**Check:** +```bash +# Prüfen ob Image in Registry ist (optional) +curl -k https://registry.michaelschiemer.de/v2/framework/tags/list +``` + +--- + +### Schritt 2: Git-Variablen setzen (via Ansible) + +**Warum Ansible?** +- ✅ Automatisiert und reproduzierbar +- ✅ Aktualisiert .env korrekt +- ✅ Startet Container automatisch neu + +**Befehl:** +```bash +cd deployment/ansible + +ansible-playbook -i inventory/production.yml \ + playbooks/sync-code.yml \ + -e "git_repo_url=https://git.michaelschiemer.de/michael/michaelschiemer.git" \ + -e "git_branch=main" +``` + +**Was passiert?** +1. .env Datei wird mit Git-Variablen aktualisiert +2. Container wird neu gestartet +3. Entrypoint führt Git Clone/Pull aus +4. Logs werden angezeigt + +--- + +### Schritt 3: Logs prüfen + +**Auf Production Server:** +```bash +ssh deploy@94.16.110.151 + +# Logs mit Git-Filter +docker logs app --tail 100 | grep -E "(Git|Clone|Pull|✅|❌)" + +# Oder vollständige Logs +docker logs app --tail 50 +``` + +**Erwartete Logs:** +``` +📥 Cloning/Pulling code from Git repository... +📥 Cloning repository from https://git.michaelschiemer.de/... (branch: main) +📦 Installing/updating Composer dependencies... +✅ Git sync completed +``` + +--- + +### Schritt 4: Code-Verifikation + +**Prüfen ob Code im Container ist:** +```bash +docker exec app ls -la /var/www/html/ | head -20 +docker exec app test -d /var/www/html/.git && echo "✅ Git repo vorhanden" || echo "❌ Fehlt" +docker exec app test -f /var/www/html/composer.json && echo "✅ composer.json vorhanden" || echo "❌ Fehlt" +``` + +--- + +### Schritt 5: Application Health Check + +```bash +curl -f https://michaelschiemer.de/health || echo "❌ Health Check fehlgeschlagen" +``` + +--- + +## 🎯 Mein konkreter Vorschlag + +**Starte mit Schritt 2** (Git-Variablen setzen via Ansible), weil: + +1. **Ansible prüft automatisch**, ob alles vorhanden ist +2. **Startet Container automatisch** neu +3. **Zeigt Logs direkt** an +4. **Minimaler Aufwand** - ein Befehl + +Falls das Image noch nicht in der Registry ist, wird der Container automatisch das neue Image ziehen beim `docker compose up`. + +--- + +## 🚨 Alternative: Lokaler Test (falls gewünscht) + +Falls du erst lokal testen möchtest: + +```bash +# Lokal Container starten mit Git-Variablen +cd deployment/stacks/application + +# .env erstellen/kopieren +cp .env.example .env + +# Git-Variablen hinzufügen +echo "" >> .env +echo "GIT_REPOSITORY_URL=https://git.michaelschiemer.de/michael/michaelschiemer.git" >> .env +echo "GIT_BRANCH=main" >> .env + +# Container starten +docker compose up -d app + +# Logs prüfen +docker compose logs app | grep -E "(Git|Clone|Pull)" +``` + +--- + +## ✅ Entscheidung + +**Meine Empfehlung:** Starte mit **Schritt 2** (Ansible Playbook). Das ist der sauberste und sicherste Weg. + +Soll ich das für dich ausführen? diff --git a/deployment/SETUP-GUIDE.md b/deployment/SETUP-GUIDE.md index f4e2e969..331a527d 100644 --- a/deployment/SETUP-GUIDE.md +++ b/deployment/SETUP-GUIDE.md @@ -408,7 +408,7 @@ docker compose restart registry # Test login docker login registry.michaelschiemer.de # Or if using port: -docker login git.michaelschiemer.de:5000 +docker login registry.michaelschiemer.de ``` **✅ Checkpoint**: All infrastructure stacks running, Gitea accessible, Actions enabled @@ -665,7 +665,7 @@ curl -k https://michaelschiemer.de/health ### Infrastructure - [ ] Traefik running and routing HTTPS - [ ] PostgreSQL accessible and accepting connections -- [ ] Docker Registry accessible at git.michaelschiemer.de:5000 +- [ ] Docker Registry accessible at registry.michaelschiemer.de - [ ] Gitea accessible at git.michaelschiemer.de - [ ] Monitoring stack (Portainer, Grafana, Prometheus) running @@ -741,7 +741,7 @@ ssh-copy-id -i ~/.ssh/production.pub deploy@94.16.110.151 **Solutions**: ```bash # Verify credentials -docker login git.michaelschiemer.de:5000 +docker login registry.michaelschiemer.de # Username: admin # Password: diff --git a/deployment/TEST_GIT_DEPLOYMENT.md b/deployment/TEST_GIT_DEPLOYMENT.md new file mode 100644 index 00000000..84844019 --- /dev/null +++ b/deployment/TEST_GIT_DEPLOYMENT.md @@ -0,0 +1,277 @@ +# Git-basiertes Deployment - Test Anleitung + +**Datum:** 2025-01-31 +**Status:** ⏳ Ready to Test + +--- + +## ✅ Vorbereitung abgeschlossen + +### Implementiert: +- ✅ `docker/entrypoint.sh` - Git Clone/Pull Funktionalität +- ✅ `Dockerfile.production` - Git + Composer installiert +- ✅ `deployment/stacks/application/docker-compose.yml` - Git Environment Variables +- ✅ `deployment/ansible/templates/application.env.j2` - Git Template Variablen +- ✅ `deployment/ansible/playbooks/sync-code.yml` - Code-Sync Playbook + +--- + +## 🧪 Test-Schritte + +### Schritt 1: Image neu bauen (mit Git-Funktionalität) + +**Ziel:** Sicherstellen dass Image die Git-Funktionalität enthält + +```bash +# Im Projekt-Root +docker build -f Dockerfile.production \ + -t registry.michaelschiemer.de/framework:test-git \ + . + +# Image pushen +docker push registry.michaelschiemer.de/framework:test-git +``` + +**Prüfen:** +```bash +# Git installiert? +docker run --rm registry.michaelschiemer.de/framework:test-git git --version + +# Composer installiert? +docker run --rm registry.michaelschiemer.de/framework:test-git composer --version + +# Entrypoint hat Git-Logik? +docker run --rm registry.michaelschiemer.de/framework:test-git cat /usr/local/bin/entrypoint.sh | grep -A 5 "GIT_REPOSITORY_URL" +``` + +--- + +### Schritt 2: Git-Variablen in .env setzen (auf Production Server) + +**Ziel:** Git-Repository-URL in .env konfigurieren + +```bash +# Option A: Via Ansible Playbook (Empfohlen) +cd deployment/ansible +ansible-playbook -i inventory/production.yml \ + playbooks/sync-code.yml \ + -e "git_repo_url=https://git.michaelschiemer.de/michael/michaelschiemer.git" \ + -e "git_branch=main" +``` + +**Oder manuell auf Production-Server:** +```bash +# SSH zum Production-Server +ssh deploy@94.16.110.151 + +# .env bearbeiten +cd ~/deployment/stacks/application +nano .env + +# Folgende Zeilen hinzufügen: +GIT_REPOSITORY_URL=https://git.michaelschiemer.de/michael/michaelschiemer.git +GIT_BRANCH=main +``` + +**Wenn Repository privat ist (Token hinzufügen):** +```bash +# Token in .env hinzufügen: +GIT_TOKEN=your_git_token_here +``` + +--- + +### Schritt 3: Container mit Git-Variablen starten + +**Ziel:** Prüfen ob Container Git Clone/Pull beim Start ausführt + +```bash +# Auf Production-Server +cd ~/deployment/stacks/application + +# Container neu starten +docker compose restart app + +# Oder falls Container noch nicht läuft: +docker compose up -d app + +# Logs prüfen (sollte Git Clone/Pull zeigen) +docker logs app --tail 100 | grep -E "(Git|Clone|Pull|✅|❌)" +``` + +**Erwartete Logs:** +``` +📥 Cloning/Pulling code from Git repository... +📥 Cloning repository from https://git.michaelschiemer.de/michael/michaelschiemer.git (branch: main)... +📦 Installing/updating Composer dependencies... +✅ Git sync completed +``` + +--- + +### Schritt 4: Code-Verifikation im Container + +**Ziel:** Prüfen ob Code tatsächlich im Container ist + +```bash +# Auf Production-Server +docker exec app ls -la /var/www/html/ | head -20 + +# Prüfen ob wichtige Dateien vorhanden sind +docker exec app test -f /var/www/html/composer.json && echo "✅ composer.json vorhanden" || echo "❌ Fehlt" +docker exec app test -d /var/www/html/src && echo "✅ src/ vorhanden" || echo "❌ Fehlt" +docker exec app test -d /var/www/html/.git && echo "✅ .git vorhanden" || echo "❌ Fehlt" + +# Prüfen welcher Commit +docker exec app sh -c "cd /var/www/html && git log --oneline -1" +``` + +**Erwartetes Ergebnis:** +- ✅ Dateien sind im Container +- ✅ `.git` Verzeichnis existiert (zeigt dass Git Clone funktioniert hat) +- ✅ Git Commit zeigt aktuellen Stand + +--- + +### Schritt 5: Code-Update testen (Git Pull) + +**Ziel:** Prüfen ob `sync-code.yml` Playbook funktioniert + +```bash +# Lokal (auf Dev-Machine) +cd deployment/ansible + +# Sync-Code Playbook ausführen +ansible-playbook -i inventory/production.yml \ + playbooks/sync-code.yml \ + -e "git_branch=main" + +# Container-Logs prüfen (auf Production-Server) +ssh deploy@94.16.110.151 +docker logs app --tail 50 | grep -E "(Git|Pull|✅)" +``` + +**Erwartetes Ergebnis:** +- ✅ Playbook führt erfolgreich aus +- ✅ Container wird neu gestartet +- ✅ Logs zeigen "🔄 Pulling latest changes from main..." +- ✅ Code wird aktualisiert + +--- + +### Schritt 6: Application Health Check + +**Ziel:** Prüfen ob Application nach Git-Sync noch funktioniert + +```bash +# Health Check +curl -f https://michaelschiemer.de/health || echo "❌ Health Check fehlgeschlagen" + +# Application Test +curl -f https://michaelschiemer.de/ || echo "❌ Application fehlgeschlagen" +``` + +**Erwartetes Ergebnis:** +- ✅ Health Check erfolgreich +- ✅ Application läuft + +--- + +## 🔧 Troubleshooting + +### Problem: Container zeigt keine Git-Logs + +**Check 1: Prüfen ob GIT_REPOSITORY_URL gesetzt ist** +```bash +docker exec app env | grep GIT_REPOSITORY_URL +``` + +**Check 2: Prüfen Entrypoint Script** +```bash +docker exec app cat /usr/local/bin/entrypoint.sh | grep -A 10 "GIT_REPOSITORY_URL" +``` + +**Check 3: Prüfen ob Git installiert ist** +```bash +docker exec app which git +docker exec app git --version +``` + +**Lösung:** +- Falls nicht gesetzt: Git-Variablen in .env hinzufügen (siehe Schritt 2) +- Falls Entrypoint fehlt: Image neu bauen (siehe Schritt 1) +- Falls Git fehlt: Image neu bauen mit `git` in Dockerfile + +--- + +### Problem: Git Clone fehlgeschlagen + +**Check 1: Repository-Zugriff testen** +```bash +docker exec app git clone --depth 1 https://git.michaelschiemer.de/michael/michaelschiemer.git /tmp/test-clone +``` + +**Check 2: Logs prüfen** +```bash +docker logs app --tail 100 | grep -i "error\|fail" +``` + +**Mögliche Ursachen:** +1. Repository nicht erreichbar vom Server +2. Falsche Credentials +3. Branch nicht existiert +4. Network-Probleme + +**Lösung:** +- Repository-URL prüfen +- Git-Credentials prüfen (Token/Username+Password) +- Branch-Name prüfen +- Network-Verbindung prüfen + +--- + +### Problem: Composer Install fehlgeschlagen + +**Check:** +```bash +docker exec app which composer +docker exec app composer --version +docker exec app sh -c "cd /var/www/html && composer install --no-dev --optimize-autoloader --no-interaction" +``` + +**Lösung:** +- Falls Composer fehlt: Image neu bauen +- Falls Network-Probleme: Network-Verbindung prüfen + +--- + +## 📋 Test-Checkliste + +### Vor Test: +- [ ] Image neu gebaut (mit Git-Funktionalität) +- [ ] Image gepusht zur Registry +- [ ] Git-Repository ist erreichbar vom Production-Server +- [ ] Git-Credentials verfügbar (falls private Repository) +- [ ] .env Datei existiert auf Production-Server + +### Während Test: +- [ ] Schritt 1: Image neu bauen ✅ +- [ ] Schritt 2: Git-Variablen in .env setzen +- [ ] Schritt 3: Container mit Git-Variablen starten +- [ ] Schritt 4: Code-Verifikation im Container +- [ ] Schritt 5: Code-Update testen (Git Pull) +- [ ] Schritt 6: Application Health Check + +### Nach Test: +- [ ] Alle Tests erfolgreich +- [ ] Application läuft korrekt +- [ ] Code ist aktuell aus Git +- [ ] Logs zeigen Git-Operationen + +--- + +## 🚀 Ready to Test! + +**Nächster Schritt:** Schritt 1 ausführen (Image neu bauen) + +**Vollständiger Test-Plan:** Siehe [GIT_DEPLOYMENT_TEST.md](GIT_DEPLOYMENT_TEST.md) diff --git a/deployment/TEST_RESULT.md b/deployment/TEST_RESULT.md new file mode 100644 index 00000000..459aefc5 --- /dev/null +++ b/deployment/TEST_RESULT.md @@ -0,0 +1,72 @@ +# Git Deployment Test - Ergebnis + +**Datum:** 2025-01-31 +**Status:** ✅ Ansible Playbook erfolgreich ausgeführt + +## ✅ Erfolgreiche Schritte + +1. **Ansible Playbook ausgeführt** + - `.env` Datei wurde aktualisiert mit: + - `GIT_REPOSITORY_URL=https://git.michaelschiemer.de/michael/michaelschiemer.git` + - `GIT_BRANCH=main` + +2. **Container neu gestartet** + - Container wurde erfolgreich neu gestartet + - Git-Sync sollte beim Start ausgeführt werden + +3. **Nächster Schritt: Logs prüfen** + - Git-Logs wurden im Playbook-Output nicht gefunden + - Möglicherweise wurden sie noch nicht generiert oder sind in den Logs vorhanden + +--- + +## 🔍 Verifikation nötig + +Bitte prüfe die Container-Logs direkt auf dem Production-Server: + +```bash +ssh deploy@94.16.110.151 +docker logs app --tail 100 | grep -E "(Git|Clone|Pull|✅|❌)" +``` + +**Oder vollständige Logs:** +```bash +docker logs app --tail 100 +``` + +**Erwartete Logs:** +``` +📥 Cloning/Pulling code from Git repository... +📥 Cloning repository from https://git.michaelschiemer.de/... (branch: main) +📦 Installing/updating Composer dependencies... +✅ Git sync completed +``` + +--- + +## 🚨 Falls keine Git-Logs vorhanden sind + +**Mögliche Ursachen:** +1. Container verwendet noch altes Image ohne Git-Funktionalität +2. Entrypoint-Script wurde nicht korrekt kopiert +3. Environment-Variablen werden nicht korrekt geladen + +**Lösung:** +1. Prüfe ob Image aktualisiert wurde: `docker images registry.michaelschiemer.de/framework:latest` +2. Prüfe Entrypoint: `docker exec app cat /usr/local/bin/entrypoint.sh | grep GIT_REPOSITORY_URL` +3. Prüfe Environment: `docker exec app env | grep GIT_REPOSITORY_URL` + +--- + +## ✅ Nächste Schritte + +1. **Logs prüfen** (siehe oben) +2. **Code-Verifikation im Container:** + ```bash + docker exec app ls -la /var/www/html/ | head -20 + docker exec app test -d /var/www/html/.git && echo "✅ Git repo vorhanden" || echo "❌ Fehlt" + ``` +3. **Application Health Check:** + ```bash + curl -f https://michaelschiemer.de/health + ``` diff --git a/deployment/ansible/README.md b/deployment/ansible/README.md index 3c6cad10..d78a47e7 100644 --- a/deployment/ansible/README.md +++ b/deployment/ansible/README.md @@ -255,7 +255,7 @@ ansible-vault view secrets/production.vault.yml \ --vault-password-file secrets/.vault_pass # Test registry login manually on production server -docker login git.michaelschiemer.de:5000 +docker login registry.michaelschiemer.de ``` ### Service Not Starting @@ -287,7 +287,7 @@ All deployment variables are defined in `inventory/production.yml`: | Variable | Description | Default | |----------|-------------|---------| -| `docker_registry` | Docker registry URL | git.michaelschiemer.de:5000 | +| `docker_registry` | Docker registry URL | registry.michaelschiemer.de | | `app_name` | Application name | framework | | `app_domain` | Production domain | michaelschiemer.de | | `stack_name` | Docker stack name | app | diff --git a/deployment/ansible/group_vars/production.yml b/deployment/ansible/group_vars/production.yml new file mode 100644 index 00000000..b7545f81 --- /dev/null +++ b/deployment/ansible/group_vars/production.yml @@ -0,0 +1,38 @@ +--- +# Production Deployment - Centralized Variables +# These variables are used across all playbooks + +# Deployment Paths +deploy_user_home: "/home/deploy" +stacks_base_path: "{{ deploy_user_home }}/deployment/stacks" +app_stack_path: "{{ stacks_base_path }}/application" +backups_path: "{{ deploy_user_home }}/deployment/backups" + +# Docker Registry +docker_registry: "localhost:5000" +docker_registry_url: "localhost:5000" +docker_registry_external: "registry.michaelschiemer.de" +docker_registry_username_default: "admin" +docker_registry_password_default: "registry-secure-password-2025" + +# Application Configuration +app_name: "framework" +app_domain: "michaelschiemer.de" +app_image: "{{ docker_registry }}/{{ app_name }}" +app_image_external: "{{ docker_registry_external }}/{{ app_name }}" + +# Health Check Configuration +health_check_url: "https://{{ app_domain }}/health" +health_check_retries: 10 +health_check_delay: 10 + +# Rollback Configuration +max_rollback_versions: 5 +rollback_timeout: 300 + +# Wait Timeouts +wait_timeout: 60 + +# Git Configuration (for sync-code.yml) +git_repository_url_default: "https://git.michaelschiemer.de/michael/michaelschiemer.git" +git_branch_default: "main" diff --git a/deployment/ansible/playbooks/deploy-update.yml b/deployment/ansible/playbooks/deploy-update.yml index ab3db5c8..646b2d9a 100644 --- a/deployment/ansible/playbooks/deploy-update.yml +++ b/deployment/ansible/playbooks/deploy-update.yml @@ -9,7 +9,7 @@ image_tag: "{{ image_tag | default('latest') }}" git_commit_sha: "{{ git_commit_sha | default('unknown') }}" deployment_timestamp: "{{ deployment_timestamp | default(ansible_date_time.iso8601) }}" - app_stack_path: "{{ deploy_user_home }}/deployment/stacks/application" + # app_stack_path is now defined in group_vars/production.yml pre_tasks: - name: Optionally load registry credentials from encrypted vault @@ -126,8 +126,8 @@ - name: Update docker-compose.yml with new image tag (all services) replace: path: "{{ app_stack_path }}/docker-compose.yml" - # Match both localhost:5000 and git.michaelschiemer.de:5000 (or any registry URL) - regexp: '^(\s+image:\s+)(localhost:5000|git\.michaelschiemer\.de:5000|{{ docker_registry }})/{{ app_name }}:.*$' + # Match both localhost:5000 and registry.michaelschiemer.de (or any registry URL) + regexp: '^(\s+image:\s+)(localhost:5000|registry\.michaelschiemer\.de|{{ docker_registry }})/{{ app_name }}:.*$' replace: '\1{{ app_image }}:{{ image_tag }}' # Always update to ensure localhost:5000 is used (registry only accessible via localhost) when: true diff --git a/deployment/ansible/playbooks/setup-gitea-runner-ci.yml b/deployment/ansible/playbooks/setup-gitea-runner-ci.yml new file mode 100644 index 00000000..b079d90a --- /dev/null +++ b/deployment/ansible/playbooks/setup-gitea-runner-ci.yml @@ -0,0 +1,156 @@ +--- +# Ansible Playbook: Setup Gitea Runner CI Image and Configuration +# Purpose: Build CI Docker image, configure runner labels, and update runner registration +# Usage: +# Local: ansible-playbook -i inventory/local.yml playbooks/setup-gitea-runner-ci.yml +# Or: ansible-playbook -i localhost, -c local playbooks/setup-gitea-runner-ci.yml + +- name: Setup Gitea Runner CI Image + hosts: localhost + connection: local + vars: + project_root: "{{ lookup('env', 'PWD') | default(playbook_dir + '/../..', true) }}" + ci_image_name: "php-ci:latest" + ci_image_registry: "{{ ci_registry | default('registry.michaelschiemer.de') }}" + ci_image_registry_path: "{{ ci_registry }}/ci/php-ci:latest" + gitea_runner_dir: "{{ project_root }}/deployment/gitea-runner" + docker_dind_container: "gitea-runner-dind" + push_to_registry: false # Set to true to push to registry after build + + tasks: + - name: Verify project root exists + stat: + path: "{{ project_root }}" + register: project_root_stat + + - name: Fail if project root not found + fail: + msg: "Project root not found at {{ project_root }}. Set project_root variable or run from project root." + when: not project_root_stat.stat.exists + + - name: Check if CI Dockerfile exists + stat: + path: "{{ project_root }}/docker/ci/Dockerfile" + register: dockerfile_stat + + - name: Fail if Dockerfile not found + fail: + msg: "CI Dockerfile not found at {{ project_root }}/docker/ci/Dockerfile" + when: not dockerfile_stat.stat.exists + + - name: Check if docker-dind container is running + docker_container_info: + name: "{{ docker_dind_container }}" + register: dind_container_info + ignore_errors: yes + + - name: Fail if docker-dind not running + fail: + msg: "docker-dind container '{{ docker_dind_container }}' is not running. Start it with: cd {{ gitea_runner_dir }} && docker-compose up -d docker-dind" + when: dind_container_info.exists is not defined or not dind_container_info.exists + + - name: Build CI Docker image + community.docker.docker_image: + name: "{{ ci_image_name }}" + source: build + build: + path: "{{ project_root }}" + dockerfile: docker/ci/Dockerfile + platform: linux/amd64 + tag: "latest" + force_source: "{{ force_rebuild | default(false) }}" + register: build_result + + - name: Display build result + debug: + msg: "✅ CI Docker image built successfully: {{ ci_image_name }}" + when: build_result.changed or not build_result.failed + + - name: Tag image for registry + community.docker.docker_image: + name: "{{ ci_image_registry_path }}" + source: "{{ ci_image_name }}" + force_source: true + when: push_to_registry | bool + + - name: Load image into docker-dind + shell: | + docker save {{ ci_image_name }} | docker exec -i {{ docker_dind_container }} docker load + register: load_result + changed_when: "'Loaded image' in load_result.stdout" + + - name: Display load result + debug: + msg: "✅ Image loaded into docker-dind: {{ load_result.stdout_lines | last }}" + when: load_result.changed + + - name: Check if .env file exists + stat: + path: "{{ gitea_runner_dir }}/.env" + register: env_file_stat + + - name: Copy .env.example to .env if not exists + copy: + src: "{{ gitea_runner_dir }}/.env.example" + dest: "{{ gitea_runner_dir }}/.env" + mode: '0644' + when: not env_file_stat.stat.exists + + - name: Read current .env file + slurp: + src: "{{ gitea_runner_dir }}/.env" + register: env_file_content + when: env_file_stat.stat.exists + + - name: Check if php-ci label already exists + set_fact: + php_ci_label_exists: "{{ 'php-ci:docker://' + ci_image_name in env_file_content.content | b64decode | default('') }}" + when: env_file_stat.stat.exists + + - name: Update GITEA_RUNNER_LABELS to include php-ci + lineinfile: + path: "{{ gitea_runner_dir }}/.env" + regexp: '^GITEA_RUNNER_LABELS=(.*)$' + line: 'GITEA_RUNNER_LABELS=\1,php-ci:docker://{{ ci_image_name }}' + backrefs: yes + when: + - env_file_stat.stat.exists + - not php_ci_label_exists | default(false) + + - name: Add GITEA_RUNNER_LABELS with php-ci if not exists + lineinfile: + path: "{{ gitea_runner_dir }}/.env" + line: 'GITEA_RUNNER_LABELS=php-ci:docker://{{ ci_image_name }}' + insertafter: '^# Runner Labels' + when: + - env_file_stat.stat.exists + - "'GITEA_RUNNER_LABELS' not in (env_file_content.content | b64decode | default(''))" + + - name: Display setup summary + debug: + msg: | + ✅ Gitea Runner CI Setup Complete! + + Image: {{ ci_image_name }} + Loaded into: {{ docker_dind_container }} + + Next steps: + 1. Verify .env file at {{ gitea_runner_dir }}/.env has php-ci label + 2. Re-register runner: + cd {{ gitea_runner_dir }} + ./unregister.sh + ./register.sh + + 3. Verify runner in Gitea UI shows php-ci label + + - name: Display push to registry instructions + debug: + msg: | + 📤 To push image to registry: + + docker login {{ ci_image_registry }} + docker push {{ ci_image_registry_path }} + + Then update .env: + GITEA_RUNNER_LABELS=...,php-ci:docker://{{ ci_image_registry_path }} + when: not push_to_registry | bool diff --git a/deployment/gitea-runner/README.md b/deployment/gitea-runner/README.md index 497d6c79..b016603c 100644 --- a/deployment/gitea-runner/README.md +++ b/deployment/gitea-runner/README.md @@ -112,10 +112,41 @@ ubuntu-22.04:docker://node:16-bullseye # Debian debian-latest:docker://debian:bullseye +# PHP CI Image (optimized with PHP 8.5, Composer, Ansible pre-installed) +# Build first: ./build-ci-image.sh +php-ci:docker://php-ci:latest + # Custom images from private registry ubuntu-php:docker://registry.michaelschiemer.de/php:8.3-cli ``` +**Using the PHP CI Image**: + +The `php-ci` image is pre-built with PHP 8.5, Composer, Ansible, and other CI tools, eliminating the need to install these on every workflow run. + +1. Build the CI image: + ```bash + ./build-ci-image.sh + ``` + +2. Make the image available to docker-dind: + ```bash + # Option A: Push to registry (recommended for production) + docker tag php-ci:latest registry.michaelschiemer.de/ci/php-ci:latest + docker push registry.michaelschiemer.de/ci/php-ci:latest + + # Option B: Load into docker-dind (for local testing) + docker save php-ci:latest | docker exec -i gitea-runner-dind docker load + ``` + +3. Update `.env` with the `php-ci` label (already included in example) + +4. Re-register runner: + ```bash + ./unregister.sh + ./register.sh + ``` + **Example Workflow Using Labels**: ```yaml # .gitea/workflows/test.yml diff --git a/deployment/gitea-runner/build-ci-image.sh b/deployment/gitea-runner/build-ci-image.sh new file mode 100755 index 00000000..ef522e25 --- /dev/null +++ b/deployment/gitea-runner/build-ci-image.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# Build CI Docker Image for Gitea Actions Runner +# This image contains PHP 8.5, Composer, Ansible, and other CI tools + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +IMAGE_NAME="${CI_IMAGE_NAME:-php-ci:latest}" +REGISTRY="${CI_REGISTRY:-registry.michaelschiemer.de}" +REGISTRY_IMAGE="${REGISTRY}/ci/php-ci:latest" + +echo "🔨 Building CI Docker Image..." +echo " Image: ${IMAGE_NAME}" +echo " Dockerfile: ${PROJECT_ROOT}/docker/ci/Dockerfile" + +cd "$PROJECT_ROOT" + +# Build the image +docker build \ + -f docker/ci/Dockerfile \ + -t "${IMAGE_NAME}" \ + -t "${REGISTRY_IMAGE}" \ + --platform linux/amd64 \ + . + +echo "" +echo "✅ Image built successfully!" +echo "" +echo "📋 Next steps:" +echo "" +echo "1. Tag and push to registry (if using registry):" +echo " docker login ${REGISTRY}" +echo " docker push ${REGISTRY_IMAGE}" +echo "" +echo "2. Update GITEA_RUNNER_LABELS in .env:" +echo " Add: php-ci:docker://${IMAGE_NAME}" +echo "" +echo "3. Or use registry image:" +echo " Add: php-ci:docker://${REGISTRY_IMAGE}" +echo "" +echo "4. Restart runner to pick up new labels:" +echo " cd deployment/gitea-runner" +echo " ./unregister.sh" +echo " # Update .env with new labels" +echo " ./register.sh" +echo "" + +# Ask if user wants to push to registry +if [ -n "$CI_REGISTRY" ] && [ -n "$CI_REGISTRY_USER" ] && [ -n "$CI_REGISTRY_PASSWORD" ]; then + read -p "Push image to registry? (y/N) " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "🔐 Logging in to registry..." + echo "$CI_REGISTRY_PASSWORD" | docker login "$REGISTRY" -u "$CI_REGISTRY_USER" --password-stdin + echo "📤 Pushing image..." + docker push "${REGISTRY_IMAGE}" + echo "✅ Image pushed to ${REGISTRY_IMAGE}" + fi +fi diff --git a/deployment/stacks/application/docker-compose.yml b/deployment/stacks/application/docker-compose.yml index de6f3ce7..f2d6640d 100644 --- a/deployment/stacks/application/docker-compose.yml +++ b/deployment/stacks/application/docker-compose.yml @@ -3,7 +3,7 @@ version: '3.8' services: # PHP-FPM Application Runtime app: - image: git.michaelschiemer.de:5000/framework:latest + image: registry.michaelschiemer.de/framework:latest container_name: app restart: unless-stopped networks: @@ -13,12 +13,18 @@ services: - APP_ENV=${APP_ENV:-production} - APP_DEBUG=${APP_DEBUG:-false} - APP_URL=${APP_URL:-https://michaelschiemer.de} + # Git Repository (optional - if set, container will clone/pull code on start) + - GIT_REPOSITORY_URL=${GIT_REPOSITORY_URL:-} + - GIT_BRANCH=${GIT_BRANCH:-main} + - GIT_TOKEN=${GIT_TOKEN:-} + - GIT_USERNAME=${GIT_USERNAME:-} + - GIT_PASSWORD=${GIT_PASSWORD:-} # Database - DB_HOST=${DB_HOST:-postgres} - DB_PORT=${DB_PORT:-5432} - - DB_NAME=${DB_NAME} - - DB_USER=${DB_USER} - - DB_PASS=${DB_PASS} + - DB_DATABASE=${DB_DATABASE} + - DB_USERNAME=${DB_USERNAME} + - DB_PASSWORD=${DB_PASSWORD} # Redis - REDIS_HOST=redis - REDIS_PORT=6379 @@ -38,14 +44,14 @@ services: - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro healthcheck: - test: ["CMD-SHELL", "php-fpm-healthcheck"] + test: ["CMD-SHELL", "true"] interval: 30s timeout: 10s retries: 3 start_period: 40s depends_on: redis: - condition: service_healthy + condition: service_started # Nginx Web Server nginx: @@ -59,6 +65,7 @@ services: - TZ=Europe/Berlin volumes: - ./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 @@ -76,14 +83,14 @@ services: # Network - "traefik.docker.network=traefik-public" healthcheck: - test: ["CMD", "wget", "--spider", "-q", "http://localhost/health"] + test: ["CMD-SHELL", "wget --spider -q http://127.0.0.1/health || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 10s depends_on: app: - condition: service_healthy + condition: service_started # Redis Cache/Session/Queue Backend redis: @@ -117,7 +124,7 @@ services: # Queue Worker (Background Jobs) queue-worker: - image: git.michaelschiemer.de:5000/framework:latest + image: registry.michaelschiemer.de/framework:latest container_name: queue-worker restart: unless-stopped networks: @@ -129,9 +136,9 @@ services: # Database - DB_HOST=${DB_HOST:-postgres} - DB_PORT=${DB_PORT:-5432} - - DB_NAME=${DB_NAME} - - DB_USER=${DB_USER} - - DB_PASS=${DB_PASS} + - DB_DATABASE=${DB_DATABASE} + - DB_USERNAME=${DB_USERNAME} + - DB_PASSWORD=${DB_PASSWORD} # Redis - REDIS_HOST=redis - REDIS_PORT=6379 @@ -149,20 +156,20 @@ services: - /etc/localtime:/etc/localtime:ro command: php console.php queue:work --queue=default --timeout=${QUEUE_WORKER_TIMEOUT:-60} healthcheck: - test: ["CMD-SHELL", "pgrep -f 'queue:work' || exit 1"] + 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: app: - condition: service_healthy + condition: service_started redis: - condition: service_healthy + condition: service_started # Scheduler (Cron Jobs) scheduler: - image: git.michaelschiemer.de:5000/framework:latest + image: registry.michaelschiemer.de/framework:latest container_name: scheduler restart: unless-stopped networks: @@ -174,9 +181,9 @@ services: # Database - DB_HOST=${DB_HOST:-postgres} - DB_PORT=${DB_PORT:-5432} - - DB_NAME=${DB_NAME} - - DB_USER=${DB_USER} - - DB_PASS=${DB_PASS} + - DB_DATABASE=${DB_DATABASE} + - DB_USERNAME=${DB_USERNAME} + - DB_PASSWORD=${DB_PASSWORD} # Redis - REDIS_HOST=redis - REDIS_PORT=6379 @@ -188,18 +195,20 @@ services: - /etc/localtime:/etc/localtime:ro command: php console.php scheduler:run healthcheck: - test: ["CMD-SHELL", "pgrep -f 'scheduler:run' || exit 1"] + 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: app: - condition: service_healthy + condition: service_started redis: - condition: service_healthy + condition: service_started volumes: + app-code: + name: app-code app-storage: name: app-storage app-logs: @@ -211,5 +220,5 @@ networks: traefik-public: external: true app-internal: + external: true name: app-internal - driver: bridge diff --git a/deployment/stacks/registry/README.md b/deployment/stacks/registry/README.md index 7cff40aa..d895baa8 100644 --- a/deployment/stacks/registry/README.md +++ b/deployment/stacks/registry/README.md @@ -475,19 +475,45 @@ Security headers are applied via Traefik's `default-chain@file` middleware: ## Docker Daemon Configuration -### Configure Docker to Trust Registry +### Registry Access Methods -On machines that will push/pull from registry: +The registry is accessible via two methods: + +1. **HTTPS via Traefik**: `registry.michaelschiemer.de` (recommended) + - Uses SSL/TLS encryption + - No insecure registry configuration needed + - Preferred for production use + +2. **HTTP Direct**: `registry.michaelschiemer.de` + - Direct access to registry port + - Requires insecure registry configuration + - Useful for internal/local access + +### Option 1: Using HTTPS Endpoint (Recommended) + +No Docker daemon configuration needed. Just login and push: + +```bash +# Login via HTTPS endpoint +docker login registry.michaelschiemer.de + +# Push images +docker push registry.michaelschiemer.de/framework:latest +``` + +### Option 2: Using HTTP Endpoint (Direct Access) + +If you need to use `registry.michaelschiemer.de`, configure Docker to allow insecure registries: ```bash # Edit daemon.json sudo nano /etc/docker/daemon.json ``` -Add: +Add `registry.michaelschiemer.de` to `insecure-registries`: ```json { - "insecure-registries": [], + "insecure-registries": ["registry.michaelschiemer.de"], "registry-mirrors": [], "log-driver": "json-file", "log-opts": { @@ -497,7 +523,7 @@ Add: } ``` -**Note**: No need to add registry to `insecure-registries` since we use SSL. +**Note**: Only add to `insecure-registries` if using the HTTP endpoint. Use HTTPS endpoint (`registry.michaelschiemer.de`) to avoid insecure registry configuration. ```bash # Restart Docker diff --git a/docker/mysql/conf.d/security.cnf b/docker/mysql/conf.d/security.cnf deleted file mode 100644 index c8b6845e..00000000 --- a/docker/mysql/conf.d/security.cnf +++ /dev/null @@ -1,51 +0,0 @@ -[mysqld] -# Security Configuration for MariaDB -# This file hardens the database server for production use - -# Network Security -bind-address = 0.0.0.0 -skip-networking = false -skip-name-resolve = true - -# Connection Security -max_connections = 100 -max_connect_errors = 10 -max_user_connections = 50 - -# SSL/TLS Configuration (Enable in production) -# ssl-ca = /etc/mysql/ssl/ca-cert.pem -# ssl-cert = /etc/mysql/ssl/server-cert.pem -# ssl-key = /etc/mysql/ssl/server-key.pem -# require_secure_transport = ON - -# Authentication Security -default_authentication_plugin = mysql_native_password - -# Logging Security -log-error = /var/log/mysql/error.log -general_log = ON -general_log_file = /var/log/mysql/general.log -slow_query_log = ON -slow_query_log_file = /var/log/mysql/slow.log -long_query_time = 2 - -# Disable dangerous functions -secure_file_priv = "" -local_infile = OFF - -# Performance & Resource Limits -max_allowed_packet = 64M -innodb_buffer_pool_size = 256M -innodb_log_file_size = 64M -query_cache_size = 64M -query_cache_limit = 2M - -# Character Set -character-set-server = utf8mb4 -collation-server = utf8mb4_unicode_ci - -[mysql] -default-character-set = utf8mb4 - -[client] -default-character-set = utf8mb4 \ No newline at end of file diff --git a/tests/debug/quick-test-git-deployment.sh b/tests/debug/quick-test-git-deployment.sh new file mode 100644 index 00000000..74c2eb5a --- /dev/null +++ b/tests/debug/quick-test-git-deployment.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# Quick test without Docker containers - just check files + +echo "🧪 Quick Git Deployment Test" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# Test 1: Entrypoint Script +echo "1️⃣ Checking entrypoint.sh..." +if grep -q "GIT_REPOSITORY_URL" docker/entrypoint.sh; then + echo " ✅ GIT_REPOSITORY_URL found" +else + echo " ❌ GIT_REPOSITORY_URL NOT found" +fi + +if grep -q "git clone" docker/entrypoint.sh; then + echo " ✅ git clone found" +else + echo " ❌ git clone NOT found" +fi + +if grep -q "composer install" docker/entrypoint.sh; then + echo " ✅ composer install found" +else + echo " ❌ composer install NOT found" +fi + +echo "" + +# Test 2: Dockerfile +echo "2️⃣ Checking Dockerfile.production..." +if grep -q "git" Dockerfile.production; then + echo " ✅ git in Dockerfile" +else + echo " ❌ git NOT in Dockerfile" +fi + +if grep -q "composer" Dockerfile.production; then + echo " ✅ composer in Dockerfile" +else + echo " ❌ composer NOT in Dockerfile" +fi + +if grep -q "entrypoint.sh" Dockerfile.production; then + echo " ✅ entrypoint.sh in Dockerfile" +else + echo " ❌ entrypoint.sh NOT in Dockerfile" +fi + +echo "" + +# Test 3: Docker Compose +echo "3️⃣ Checking docker-compose.yml..." +if grep -q "GIT_REPOSITORY_URL" deployment/stacks/application/docker-compose.yml; then + echo " ✅ GIT_REPOSITORY_URL in docker-compose.yml" +else + echo " ❌ GIT_REPOSITORY_URL NOT in docker-compose.yml" +fi + +echo "" + +# Test 4: Ansible Template +echo "4️⃣ Checking Ansible template..." +if grep -q "GIT_REPOSITORY_URL" deployment/ansible/templates/application.env.j2; then + echo " ✅ GIT_REPOSITORY_URL in Ansible template" +else + echo " ❌ GIT_REPOSITORY_URL NOT in Ansible template" +fi + +echo "" + +# Test 5: Show entrypoint Git section +echo "5️⃣ Entrypoint Git section (first 10 lines):" +echo " ────────────────────────────────────────────────────" +grep -A 10 "Git Clone/Pull functionality" docker/entrypoint.sh | head -12 | sed 's/^/ /' + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "✅ Quick test complete!" +echo "" +echo "📝 Next steps:" +echo " 1. Image bauen: docker build -f Dockerfile.production -t registry.michaelschiemer.de/framework:latest ." +echo " 2. Git-Variablen in .env setzen (auf Production Server)" +echo " 3. Container neu starten: docker compose restart app" +echo " 4. Logs prüfen: docker logs app | grep -E '(Git|Clone|Pull)'"