chore: sync staging workspace
This commit is contained in:
8
Makefile
8
Makefile
@@ -187,7 +187,6 @@ setup-server: ## Server-Grundkonfiguration
|
|||||||
check: ## Serververbindung prüfen
|
check: ## Serververbindung prüfen
|
||||||
ansible -i $(ANSIBLE_INVENTORY) all -m ping $(if $(LIMIT),--limit="$(LIMIT)",)
|
ansible -i $(ANSIBLE_INVENTORY) all -m ping $(if $(LIMIT),--limit="$(LIMIT)",)
|
||||||
|
|
||||||
|
|
||||||
# Beispielaufrufe:
|
# Beispielaufrufe:
|
||||||
# make staging TAGS="deploy,check"
|
# make staging TAGS="deploy,check"
|
||||||
# make setup-server LIMIT="staging" TAGS="docker"
|
# make setup-server LIMIT="staging" TAGS="docker"
|
||||||
@@ -198,7 +197,7 @@ update-production: ## Update PHP files on production server
|
|||||||
@cd deployment && make application ENV=production
|
@cd deployment && make application ENV=production
|
||||||
@echo "✅ Production update completed"
|
@echo "✅ Production update completed"
|
||||||
|
|
||||||
restart-production: ## Restart production PHP container only
|
restart-production: ## Restart production PHP container only
|
||||||
@echo "🔄 Restarting production PHP container..."
|
@echo "🔄 Restarting production PHP container..."
|
||||||
@ssh -i ~/.ssh/production deploy@94.16.110.151 "cd /var/www/html && docker compose restart php"
|
@ssh -i ~/.ssh/production deploy@94.16.110.151 "cd /var/www/html && docker compose restart php"
|
||||||
@echo "✅ Production PHP container restarted"
|
@echo "✅ Production PHP container restarted"
|
||||||
@@ -247,4 +246,7 @@ ssl-backup: ## Backup Let's Encrypt certificates
|
|||||||
alpine tar czf /backup/letsencrypt-$(shell date +%Y%m%d-%H%M%S).tar.gz /etc/letsencrypt
|
alpine tar czf /backup/letsencrypt-$(shell date +%Y%m%d-%H%M%S).tar.gz /etc/letsencrypt
|
||||||
@echo "✅ Backup created in backups/"
|
@echo "✅ Backup created in backups/"
|
||||||
|
|
||||||
.PHONY: up down build restart logs ps phpinfo deploy setup clean clean-coverage status fix-ssh-perms setup-ssh test test-coverage test-coverage-html test-unit test-framework test-domain test-watch test-parallel test-profile test-filter security-check security-audit-json security-check-prod update-production restart-production deploy-production-quick status-production logs-production ssl-init ssl-init-staging ssl-test ssl-renew ssl-status ssl-backup
|
push-staging: ## Pusht den aktuellen Stand nach origin/staging
|
||||||
|
git push origin HEAD:staging
|
||||||
|
|
||||||
|
.PHONY: up down build restart logs ps phpinfo deploy setup clean clean-coverage status fix-ssh-perms setup-ssh test test-coverage test-coverage-html test-unit test-framework test-domain test-watch test-parallel test-profile test-filter security-check security-audit-json security-check-prod update-production restart-production deploy-production-quick status-production logs-production ssl-init ssl-init-staging ssl-test ssl-renew ssl-status ssl-backup push-staging
|
||||||
|
|||||||
@@ -1,169 +0,0 @@
|
|||||||
# Deployment Dokumentation - Index
|
|
||||||
|
|
||||||
**Stand:** 2025-10-31
|
|
||||||
**Status:** ✅ Vollständige Dokumentation vorhanden
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Schnellstart
|
|
||||||
|
|
||||||
### Für schnellen Einstieg
|
|
||||||
|
|
||||||
1. **[QUICK_START.md](QUICK_START.md)** ⭐
|
|
||||||
- Schnellstart-Guide
|
|
||||||
- Pipeline-Status prüfen
|
|
||||||
- Troubleshooting Quick Reference
|
|
||||||
|
|
||||||
2. **[CODE_CHANGE_WORKFLOW.md](CODE_CHANGE_WORKFLOW.md)**
|
|
||||||
- Wie Codeänderungen gepusht werden
|
|
||||||
- Automatisches vs. manuelles Deployment
|
|
||||||
- Branching-Strategien
|
|
||||||
- Beispiel-Workflows
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📚 Detaillierte Guides
|
|
||||||
|
|
||||||
### Deployment-Prozess
|
|
||||||
|
|
||||||
3. **[APPLICATION_STACK_DEPLOYMENT.md](APPLICATION_STACK_DEPLOYMENT.md)**
|
|
||||||
- Detaillierter Deployment-Ablauf Schritt für Schritt
|
|
||||||
- Was passiert bei jedem Deployment
|
|
||||||
- Container-Neustart Details
|
|
||||||
- Rollback-Prozess
|
|
||||||
- Troubleshooting
|
|
||||||
|
|
||||||
### CI/CD Pipeline
|
|
||||||
|
|
||||||
4. **[CI_CD_STATUS.md](CI_CD_STATUS.md)**
|
|
||||||
- Aktueller CI/CD Status
|
|
||||||
- Secrets-Übersicht
|
|
||||||
- Runner-Status
|
|
||||||
- Checkliste für Completion
|
|
||||||
- Troubleshooting
|
|
||||||
|
|
||||||
### Setup & Konfiguration
|
|
||||||
|
|
||||||
5. **[SETUP-GUIDE.md](SETUP-GUIDE.md)**
|
|
||||||
- Kompletter Setup-Guide von Anfang bis Ende
|
|
||||||
- Infrastructure Deployment
|
|
||||||
- Gitea Runner Setup
|
|
||||||
- Secrets Konfiguration
|
|
||||||
- Schritt-für-Schritt Anleitung
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Status & Übersicht
|
|
||||||
|
|
||||||
### Projekt-Status
|
|
||||||
|
|
||||||
6. **[DEPLOYMENT_SUMMARY.md](DEPLOYMENT_SUMMARY.md)**
|
|
||||||
- Was ist fertig?
|
|
||||||
- Was fehlt noch?
|
|
||||||
- Completion Rate
|
|
||||||
- Nächste Schritte
|
|
||||||
|
|
||||||
7. **[DEPLOYMENT-TODO.md](DEPLOYMENT_TODO.md)**
|
|
||||||
- Aktuelle TODO-Liste
|
|
||||||
- Priorisierte Reihenfolge
|
|
||||||
- Quick Checklist
|
|
||||||
|
|
||||||
8. **[DEPLOYMENT-STATUS.md](DEPLOYMENT-STATUS.md)**
|
|
||||||
- Detaillierter Status aller Phasen
|
|
||||||
- Phasen-basierte Übersicht
|
|
||||||
- Historischer Status
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔧 Stack-spezifische Dokumentation
|
|
||||||
|
|
||||||
### Infrastructure Stacks
|
|
||||||
|
|
||||||
- **[stacks/traefik/README.md](stacks/traefik/README.md)** - Reverse Proxy & SSL
|
|
||||||
- **[stacks/postgresql/README.md](stacks/postgresql/README.md)** - Database mit Backups
|
|
||||||
- **[stacks/registry/README.md](stacks/registry/README.md)** - Private Docker Registry
|
|
||||||
- **[stacks/gitea/README.md](stacks/gitea/README.md)** - Git Server & CI/CD
|
|
||||||
- **[stacks/monitoring/README.md](stacks/monitoring/README.md)** - Monitoring Tools
|
|
||||||
|
|
||||||
### Application Stack
|
|
||||||
|
|
||||||
- **[stacks/application/README.md](stacks/application/README.md)** - Application Stack Details
|
|
||||||
- **[ansible/README.md](ansible/README.md)** - Ansible Playbooks Dokumentation
|
|
||||||
|
|
||||||
### CI/CD
|
|
||||||
|
|
||||||
- **[gitea-runner/README.md](gitea-runner/README.md)** - Gitea Runner Setup
|
|
||||||
- **[.gitea/workflows/production-deploy.yml](../.gitea/workflows/production-deploy.yml)** - Haupt-Deployment-Pipeline
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔐 Security & VPN
|
|
||||||
|
|
||||||
- **[docs/WIREGUARD-SETUP.md](docs/WIREGUARD-SETUP.md)** - WireGuard VPN Setup
|
|
||||||
- **[ansible/playbooks/README-WIREGUARD.md](ansible/playbooks/README-WIREGUARD.md)** - WireGuard Ansible Playbooks
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🆘 Troubleshooting
|
|
||||||
|
|
||||||
### Workflow-Probleme
|
|
||||||
|
|
||||||
- **[WORKFLOW-TROUBLESHOOTING.md](WORKFLOW-TROUBLESHOOTING.md)** - Workflow Troubleshooting
|
|
||||||
- **[NATIVE-WORKFLOW-README.md](NATIVE-WORKFLOW-README.md)** - Native Workflow ohne GitHub Actions
|
|
||||||
|
|
||||||
### Allgemeine Hilfe
|
|
||||||
|
|
||||||
- **[QUICK_START.md](QUICK_START.md)** - Troubleshooting Quick Reference
|
|
||||||
- **[CI_CD_STATUS.md](CI_CD_STATUS.md)** - CI/CD Troubleshooting
|
|
||||||
- **[APPLICATION_STACK_DEPLOYMENT.md](APPLICATION_STACK_DEPLOYMENT.md)** - Deployment Troubleshooting
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📖 Haupt-Dokumentation
|
|
||||||
|
|
||||||
- **[README.md](README.md)** - Haupt-Dokumentation & Übersicht
|
|
||||||
- **[SETUP-GUIDE.md](SETUP-GUIDE.md)** - Kompletter Setup-Guide
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Empfohlene Lesereihenfolge
|
|
||||||
|
|
||||||
### Für neue Nutzer
|
|
||||||
|
|
||||||
1. **[QUICK_START.md](QUICK_START.md)** - Schneller Überblick
|
|
||||||
2. **[CODE_CHANGE_WORKFLOW.md](CODE_CHANGE_WORKFLOW.md)** - Code deployen lernen
|
|
||||||
3. **[DEPLOYMENT_SUMMARY.md](DEPLOYMENT_SUMMARY.md)** - Projekt-Status verstehen
|
|
||||||
|
|
||||||
### Für Deployment-Verständnis
|
|
||||||
|
|
||||||
1. **[APPLICATION_STACK_DEPLOYMENT.md](APPLICATION_STACK_DEPLOYMENT.md)** - Wie Deployment funktioniert
|
|
||||||
2. **[CI_CD_STATUS.md](CI_CD_STATUS.md)** - CI/CD Pipeline verstehen
|
|
||||||
3. **[SETUP-GUIDE.md](SETUP-GUIDE.md)** - Komplette Setup-Anleitung
|
|
||||||
|
|
||||||
### Für Troubleshooting
|
|
||||||
|
|
||||||
1. **[QUICK_START.md](QUICK_START.md)** - Quick Troubleshooting
|
|
||||||
2. **[WORKFLOW-TROUBLESHOOTING.md](WORKFLOW-TROUBLESHOOTING.md)** - Workflow-Probleme
|
|
||||||
3. Stack-spezifische READMEs für Details
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 Dokumentations-Standards
|
|
||||||
|
|
||||||
**Alle Dokumentationsdateien:**
|
|
||||||
- Verwenden Markdown-Format
|
|
||||||
- Haben klare Überschriften-Struktur
|
|
||||||
- Enthalten Code-Beispiele
|
|
||||||
- Haben Troubleshooting-Abschnitte (wenn relevant)
|
|
||||||
- Verlinken zu verwandten Dokumenten
|
|
||||||
|
|
||||||
**Standards:**
|
|
||||||
- ✅ Beispiele sind ausführbar
|
|
||||||
- ✅ Pfade sind absolut oder relativ klar
|
|
||||||
- ✅ Screenshots/Links sind aktuell
|
|
||||||
- ✅ Status ist klar markiert (✅/⚠️/❌)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Letzte Aktualisierung:** 2025-10-31
|
|
||||||
**Status:** ✅ Dokumentation vollständig
|
|
||||||
@@ -43,18 +43,24 @@ Developer → git push
|
|||||||
|
|
||||||
```
|
```
|
||||||
deployment/
|
deployment/
|
||||||
|
├── ansible/ # Ansible config, playbooks, inventory, templates
|
||||||
|
├── gitea-runner/ # Self-hosted Gitea Actions runner stack
|
||||||
├── stacks/ # Docker Compose stacks
|
├── stacks/ # Docker Compose stacks
|
||||||
│ ├── traefik/ # Reverse proxy with SSL
|
|
||||||
│ ├── gitea/ # Git server
|
|
||||||
│ ├── registry/ # Private Docker registry
|
|
||||||
│ ├── application/ # Main PHP application
|
│ ├── application/ # Main PHP application
|
||||||
│ ├── postgres/ # Database
|
│ ├── gitea/ # Git server
|
||||||
│ └── monitoring/ # Portainer + Grafana + Prometheus
|
│ ├── minio/ # Object storage
|
||||||
├── ansible/ # Automation playbooks
|
│ ├── monitoring/ # Portainer, Grafana, Prometheus
|
||||||
│ ├── playbooks/ # Deployment automation
|
│ ├── postgresql/ # PostgreSQL database
|
||||||
│ ├── inventory/ # Server inventory
|
│ ├── registry/ # Private Docker registry
|
||||||
│ └── secrets/ # Ansible Vault secrets
|
│ ├── staging/ # Optional staging stack
|
||||||
└── docs/ # Deployment documentation
|
│ └── traefik/ # Reverse proxy with SSL certificates
|
||||||
|
├── docs/ # 📚 Dokumentation (siehe docs/README.md)
|
||||||
|
│ ├── guides/ # Anleitungen & Guides
|
||||||
|
│ ├── reference/ # Referenz-Dokumentation
|
||||||
|
│ ├── status/ # Status & Tracking
|
||||||
|
│ ├── tests/ # Test-Dokumentation
|
||||||
|
│ └── history/ # Logs & Historie
|
||||||
|
└── README.md (dieses Dokument)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
@@ -70,7 +76,7 @@ git push origin main # → Automatisches Deployment!
|
|||||||
|
|
||||||
**Pipeline-Status:** `https://git.michaelschiemer.de/michael/michaelschiemer/actions`
|
**Pipeline-Status:** `https://git.michaelschiemer.de/michael/michaelschiemer/actions`
|
||||||
|
|
||||||
**📖 Vollständige Anleitung:** Siehe [QUICK_START.md](QUICK_START.md) oder [CODE_CHANGE_WORKFLOW.md](CODE_CHANGE_WORKFLOW.md)
|
**📖 Vollständige Anleitung:** Siehe [docs/guides/quick-start.md](docs/guides/quick-start.md) oder [docs/guides/code-change-workflow.md](docs/guides/code-change-workflow.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -113,7 +119,7 @@ Each stack has its own README with detailed configuration:
|
|||||||
- [Gitea](stacks/gitea/README.md) - Git server configuration
|
- [Gitea](stacks/gitea/README.md) - Git server configuration
|
||||||
- [Registry](stacks/registry/README.md) - Private registry setup
|
- [Registry](stacks/registry/README.md) - Private registry setup
|
||||||
- [Application](stacks/application/README.md) - Application deployment
|
- [Application](stacks/application/README.md) - Application deployment
|
||||||
- [PostgreSQL](stacks/postgres/README.md) - Database configuration
|
- [PostgreSQL](stacks/postgresql/README.md) - Database configuration
|
||||||
- [Monitoring](stacks/monitoring/README.md) - Monitoring stack
|
- [Monitoring](stacks/monitoring/README.md) - Monitoring stack
|
||||||
|
|
||||||
## Deployment Commands
|
## Deployment Commands
|
||||||
@@ -141,7 +147,7 @@ ansible-playbook -i inventory/production.yml \
|
|||||||
playbooks/rollback.yml
|
playbooks/rollback.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
**📖 Vollständige Command-Referenz:** Siehe [DEPLOYMENT_COMMANDS.md](DEPLOYMENT_COMMANDS.md)
|
**📖 Vollständige Command-Referenz:** Siehe [docs/guides/deployment-commands.md](docs/guides/deployment-commands.md)
|
||||||
|
|
||||||
### Update Specific Stack
|
### Update Specific Stack
|
||||||
```bash
|
```bash
|
||||||
@@ -183,11 +189,11 @@ git push origin main
|
|||||||
|
|
||||||
**📖 Vollständige Dokumentation:**
|
**📖 Vollständige Dokumentation:**
|
||||||
|
|
||||||
- **[QUICK_START.md](QUICK_START.md)** ⭐ - Schnellstart-Guide für Deployment
|
- **[docs/guides/quick-start.md](docs/guides/quick-start.md)** ⭐ - Schnellstart-Guide für Deployment
|
||||||
- **[CODE_CHANGE_WORKFLOW.md](CODE_CHANGE_WORKFLOW.md)** - Kompletter Guide für Codeänderungen
|
- **[docs/guides/code-change-workflow.md](docs/guides/code-change-workflow.md)** - Kompletter Guide für Codeänderungen
|
||||||
- **[APPLICATION_STACK_DEPLOYMENT.md](APPLICATION_STACK_DEPLOYMENT.md)** - Detaillierter Deployment-Ablauf
|
- **[docs/reference/application-stack.md](docs/reference/application-stack.md)** - Detaillierter Deployment-Ablauf
|
||||||
- **[CI_CD_STATUS.md](CI_CD_STATUS.md)** - CI/CD Pipeline Status & Checkliste
|
- **[docs/status/ci-cd-status.md](docs/status/ci-cd-status.md)** - CI/CD Pipeline Status & Checkliste
|
||||||
- **[DEPLOYMENT_SUMMARY.md](DEPLOYMENT_SUMMARY.md)** - Projekt-Status Übersicht
|
- **[docs/status/deployment-summary.md](docs/status/deployment-summary.md)** - Projekt-Status Übersicht
|
||||||
|
|
||||||
### Pipeline Details
|
### Pipeline Details
|
||||||
|
|
||||||
@@ -207,21 +213,13 @@ Access monitoring tools:
|
|||||||
|
|
||||||
## Backup & Recovery
|
## Backup & Recovery
|
||||||
|
|
||||||
### Automated Backups
|
### Current State
|
||||||
|
|
||||||
- **PostgreSQL**: Daily backups with 7-day retention
|
Infrastructure backups are handled per stack. The PostgreSQL stack ships helper scripts under `stacks/postgresql/scripts/` (see `backup.sh` and `restore.sh`). Registry and Gitea data snapshots are currently managed manually on the host.
|
||||||
- **Gitea Data**: Weekly backups
|
|
||||||
- **Registry Images**: On-demand backups
|
|
||||||
|
|
||||||
### Manual Backup
|
### Roadmap
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/production.yml playbooks/backup.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
### Restore from Backup
|
An Ansible-level backup/restore playbook is still planned. Track progress in `DEPLOYMENT-TODO.md` and update this section once the playbook is available.
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/production.yml playbooks/restore.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Security
|
## Security
|
||||||
|
|
||||||
@@ -248,7 +246,7 @@ docker network inspect traefik-public
|
|||||||
### View Logs
|
### View Logs
|
||||||
```bash
|
```bash
|
||||||
# Application logs
|
# Application logs
|
||||||
docker compose -f stacks/application/docker-compose.yml logs -f app-php
|
docker compose -f stacks/application/docker-compose.yml logs -f app
|
||||||
|
|
||||||
# Traefik logs
|
# Traefik logs
|
||||||
docker compose -f stacks/traefik/docker-compose.yml logs -f
|
docker compose -f stacks/traefik/docker-compose.yml logs -f
|
||||||
@@ -256,25 +254,22 @@ docker compose -f stacks/traefik/docker-compose.yml logs -f
|
|||||||
|
|
||||||
## 📚 Dokumentation Index
|
## 📚 Dokumentation Index
|
||||||
|
|
||||||
**Vollständige Dokumentations-Übersicht:** Siehe [DOCUMENTATION_INDEX.md](DOCUMENTATION_INDEX.md)
|
**Vollständige Dokumentations-Übersicht:** Siehe [docs/README.md](docs/README.md)
|
||||||
|
|
||||||
**Wichtigste Dokumente:**
|
**Wichtigste Dokumente:**
|
||||||
- **[QUICK_START.md](QUICK_START.md)** ⭐ - Schnellstart
|
- **[docs/guides/quick-start.md](docs/guides/quick-start.md)** ⭐ - Schnellstart
|
||||||
- **[CODE_CHANGE_WORKFLOW.md](CODE_CHANGE_WORKFLOW.md)** - Code deployen
|
- **[docs/guides/code-change-workflow.md](docs/guides/code-change-workflow.md)** - Code deployen
|
||||||
- **[APPLICATION_STACK_DEPLOYMENT.md](APPLICATION_STACK_DEPLOYMENT.md)** - Deployment-Details
|
- **[docs/reference/application-stack.md](docs/reference/application-stack.md)** - Deployment-Details
|
||||||
- **[CI_CD_STATUS.md](CI_CD_STATUS.md)** - CI/CD Status
|
- **[docs/status/ci-cd-status.md](docs/status/ci-cd-status.md)** - CI/CD Status
|
||||||
- **[DEPLOYMENT_SUMMARY.md](DEPLOYMENT_SUMMARY.md)** - Projekt-Übersicht
|
- **[docs/status/deployment-summary.md](docs/status/deployment-summary.md)** - Projekt-Übersicht
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
For issues and questions, see:
|
Für spezifische Fragen helfen die folgenden Dokumente weiter:
|
||||||
- [Troubleshooting Guide](docs/troubleshooting.md)
|
- [docs/reference/workflow-troubleshooting.md](docs/reference/workflow-troubleshooting.md) – Fehleranalyse für Laufzeiten & Pipelines
|
||||||
- [Workflow Troubleshooting](WORKFLOW-TROUBLESHOOTING.md)
|
- [docs/status/ci-cd-status.md](docs/status/ci-cd-status.md) – Pipeline-Status & Checklisten
|
||||||
- [CI/CD Status](CI_CD_STATUS.md) - Mit Troubleshooting-Section
|
- [docs/status/deployment-summary.md](docs/status/deployment-summary.md) – Aktueller Projektüberblick
|
||||||
|
- [docs/reference/application-stack.md](docs/reference/application-stack.md) – Detaillierte Deployment-Schritte
|
||||||
## Migration from Docker Swarm
|
|
||||||
|
|
||||||
See [Migration Guide](docs/migration-from-swarm.md) for detailed instructions on migrating from the old Docker Swarm setup.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -6,21 +6,35 @@ This directory contains Ansible playbooks and configuration for deploying the Cu
|
|||||||
|
|
||||||
```
|
```
|
||||||
deployment/ansible/
|
deployment/ansible/
|
||||||
├── ansible.cfg # Ansible configuration
|
├── ansible.cfg # Ansible configuration
|
||||||
├── inventory/
|
├── inventory/
|
||||||
│ └── production.yml # Production server inventory
|
│ ├── production.yml # Production server inventory
|
||||||
|
│ └── local.yml # Local testing inventory
|
||||||
├── playbooks/
|
├── playbooks/
|
||||||
│ ├── setup-production-secrets.yml # Deploy secrets
|
|
||||||
│ ├── deploy-update.yml # Deploy application updates
|
│ ├── deploy-update.yml # Deploy application updates
|
||||||
│ ├── rollback.yml # Rollback deployments
|
│ ├── rollback.yml # Rollback deployments
|
||||||
|
│ ├── setup-infrastructure.yml # Provision core stacks
|
||||||
|
│ ├── setup-production-secrets.yml # Deploy secrets
|
||||||
│ ├── setup-wireguard.yml # Setup WireGuard VPN server
|
│ ├── setup-wireguard.yml # Setup WireGuard VPN server
|
||||||
│ ├── add-wireguard-client.yml # Add WireGuard client
|
│ ├── add-wireguard-client.yml # Add WireGuard client
|
||||||
|
│ ├── sync-code.yml # Git-based code sync
|
||||||
│ └── README-WIREGUARD.md # WireGuard documentation
|
│ └── README-WIREGUARD.md # WireGuard documentation
|
||||||
|
├── scripts/ # Helper scripts for secrets & credentials
|
||||||
|
├── roles/ # Reusable roles (e.g. application stack)
|
||||||
├── secrets/
|
├── secrets/
|
||||||
│ ├── .gitignore # Prevent committing secrets
|
│ ├── .gitignore # Prevent committing secrets
|
||||||
│ └── production.vault.yml.example # Example vault file
|
│ └── production.vault.yml.example # Example vault file
|
||||||
└── templates/
|
└── templates/
|
||||||
└── .env.production.j2 # Environment file template
|
├── application.env.j2 # Application stack environment
|
||||||
|
├── gitea-app.ini.j2 # Gitea configuration
|
||||||
|
├── minio.env.j2 # MinIO environment
|
||||||
|
├── monitoring.env.j2 # Monitoring stack environment
|
||||||
|
├── wireguard-client.conf.j2 # WireGuard client config
|
||||||
|
└── wireguard-server.conf.j2 # WireGuard server config
|
||||||
|
|
||||||
|
## Roles
|
||||||
|
|
||||||
|
Stack-spezifische Aufgaben liegen in `roles/` (z. B. `application`, `traefik`, `registry`). Playbooks wie `setup-infrastructure.yml` importieren diese Rollen direkt. Die Application-Rolle kann mit Variablen wie `application_sync_files=false` oder `application_compose_recreate="always"` konfiguriert werden (siehe `playbooks/deploy-update.yml` als Beispiel).
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@@ -37,6 +51,7 @@ deployment/ansible/
|
|||||||
- Create `.vault_pass` file in `secrets/` directory
|
- Create `.vault_pass` file in `secrets/` directory
|
||||||
- Add vault password to this file (one line)
|
- Add vault password to this file (one line)
|
||||||
- File is gitignored for security
|
- File is gitignored for security
|
||||||
|
- 📖 **Detaillierte Dokumentation:** [docs/guides/vault-password.md](../docs/guides/vault-password.md)
|
||||||
|
|
||||||
## Setup Instructions
|
## Setup Instructions
|
||||||
|
|
||||||
@@ -66,6 +81,8 @@ echo "your-vault-password-here" > secrets/.vault_pass
|
|||||||
chmod 600 secrets/.vault_pass
|
chmod 600 secrets/.vault_pass
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**📖 Für detaillierte Informationen:** Siehe [docs/guides/vault-password.md](../docs/guides/vault-password.md)
|
||||||
|
|
||||||
### 3. Configure SSH Key
|
### 3. Configure SSH Key
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -265,11 +282,12 @@ docker login registry.michaelschiemer.de
|
|||||||
# SSH to production server
|
# SSH to production server
|
||||||
ssh -i ~/.ssh/production deploy@94.16.110.151
|
ssh -i ~/.ssh/production deploy@94.16.110.151
|
||||||
|
|
||||||
# Check Docker service logs
|
# Check Docker Compose service logs
|
||||||
docker service logs app_app
|
docker compose -f {{ app_stack_path }}/docker-compose.yml logs app
|
||||||
|
docker compose -f {{ app_stack_path }}/docker-compose.yml logs nginx
|
||||||
|
|
||||||
# Check stack status
|
# Check stack status
|
||||||
docker stack ps app
|
docker compose -f {{ app_stack_path }}/docker-compose.yml ps
|
||||||
```
|
```
|
||||||
|
|
||||||
## CI/CD Integration
|
## CI/CD Integration
|
||||||
@@ -283,19 +301,19 @@ Vault password is stored as Gitea Actions secret: `ANSIBLE_VAULT_PASSWORD`
|
|||||||
|
|
||||||
## Inventory Variables
|
## Inventory Variables
|
||||||
|
|
||||||
All deployment variables are defined in `inventory/production.yml`:
|
All zentralen Variablen werden in `group_vars/production.yml` gepflegt und können bei Bedarf im Inventory überschrieben werden. Häufig verwendete Werte:
|
||||||
|
|
||||||
| Variable | Description | Default |
|
| Variable | Beschreibung | Standardwert |
|
||||||
|----------|-------------|---------|
|
|----------|--------------|--------------|
|
||||||
| `docker_registry` | Docker registry URL | registry.michaelschiemer.de |
|
| `deploy_user_home` | Home-Verzeichnis des Deploy-Users | `/home/deploy` |
|
||||||
| `app_name` | Application name | framework |
|
| `stacks_base_path` | Basispfad für Docker Compose Stacks | `/home/deploy/deployment/stacks` |
|
||||||
| `app_domain` | Production domain | michaelschiemer.de |
|
| `app_stack_path` | Pfad zum Application Stack | `/home/deploy/deployment/stacks/application` |
|
||||||
| `stack_name` | Docker stack name | app |
|
| `backups_path` | Ablageort für Deployment-Backups | `/home/deploy/deployment/backups` |
|
||||||
| `compose_file` | Docker Compose file path | /home/deploy/docker-compose.prod.yml |
|
| `docker_registry` | Interner Registry-Endpunkt (lokal) | `localhost:5000` |
|
||||||
| `secrets_path` | Secrets directory | /home/deploy/secrets |
|
| `docker_registry_external` | Externer Registry-Endpunkt | `registry.michaelschiemer.de` |
|
||||||
| `backups_path` | Backups directory | /home/deploy/backups |
|
| `app_domain` | Produktions-Domain | `michaelschiemer.de` |
|
||||||
| `max_rollback_versions` | Backup retention | 5 |
|
| `health_check_url` | Health-Check Endpoint | `https://michaelschiemer.de/health` |
|
||||||
| `health_check_url` | Health check endpoint | https://michaelschiemer.de/health |
|
| `max_rollback_versions` | Anzahl vorgehaltener Backups | `5` |
|
||||||
|
|
||||||
## Backup Management
|
## Backup Management
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ gathering = smart
|
|||||||
fact_caching = jsonfile
|
fact_caching = jsonfile
|
||||||
fact_caching_connection = /tmp/ansible_facts
|
fact_caching_connection = /tmp/ansible_facts
|
||||||
fact_caching_timeout = 3600
|
fact_caching_timeout = 3600
|
||||||
|
roles_path = roles
|
||||||
|
|
||||||
[ssh_connection]
|
[ssh_connection]
|
||||||
pipelining = True
|
pipelining = True
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ docker_registry_external: "registry.michaelschiemer.de"
|
|||||||
docker_registry_username_default: "admin"
|
docker_registry_username_default: "admin"
|
||||||
# docker_registry_password_default should be set in vault as vault_docker_registry_password
|
# docker_registry_password_default should be set in vault as vault_docker_registry_password
|
||||||
# If not using vault, override via -e docker_registry_password_default="your-password"
|
# If not using vault, override via -e docker_registry_password_default="your-password"
|
||||||
|
docker_registry_password_default: ""
|
||||||
registry_auth_path: "{{ stacks_base_path }}/registry/auth"
|
registry_auth_path: "{{ stacks_base_path }}/registry/auth"
|
||||||
|
|
||||||
# Application Configuration
|
# Application Configuration
|
||||||
|
|||||||
66
deployment/ansible/playbooks/check-staging-logs.yml
Normal file
66
deployment/ansible/playbooks/check-staging-logs.yml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
- name: Check Staging Container Logs
|
||||||
|
hosts: production
|
||||||
|
gather_facts: yes
|
||||||
|
become: no
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Check staging container status
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose ps
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: container_status
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Get staging-app logs
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose logs --tail=100 staging-app
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: staging_app_logs
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Get staging-nginx logs
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose logs --tail=100 staging-nginx
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: staging_nginx_logs
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Get staging-queue-worker logs
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose logs --tail=100 staging-queue-worker
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: staging_queue_logs
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Get staging-scheduler logs
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose logs --tail=100 staging-scheduler
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: staging_scheduler_logs
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Display container status
|
||||||
|
debug:
|
||||||
|
msg: "{{ container_status.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display staging-app logs
|
||||||
|
debug:
|
||||||
|
msg: "{{ staging_app_logs.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display staging-nginx logs
|
||||||
|
debug:
|
||||||
|
msg: "{{ staging_nginx_logs.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display staging-queue-worker logs
|
||||||
|
debug:
|
||||||
|
msg: "{{ staging_queue_logs.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display staging-scheduler logs
|
||||||
|
debug:
|
||||||
|
msg: "{{ staging_scheduler_logs.stdout_lines }}"
|
||||||
@@ -133,31 +133,13 @@
|
|||||||
when: true
|
when: true
|
||||||
register: compose_updated
|
register: compose_updated
|
||||||
|
|
||||||
- name: Restart application stack with new image
|
- name: Redeploy application stack with new image
|
||||||
community.docker.docker_compose_v2:
|
import_role:
|
||||||
project_src: "{{ app_stack_path }}"
|
name: application
|
||||||
state: present
|
vars:
|
||||||
pull: always
|
application_sync_files: false
|
||||||
recreate: always
|
application_compose_recreate: "always"
|
||||||
remove_orphans: yes
|
application_remove_orphans: true
|
||||||
register: stack_deploy
|
|
||||||
# Always restart when deploying, even if image already exists
|
|
||||||
# This ensures code changes are applied even with same image tag
|
|
||||||
when: true
|
|
||||||
|
|
||||||
- name: Wait for services to be healthy
|
|
||||||
wait_for:
|
|
||||||
timeout: 60
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Check container health status
|
|
||||||
shell: |
|
|
||||||
docker compose -f {{ app_stack_path }}/docker-compose.yml ps --format json | jq -r '.[] | select(.Health != "healthy" and .Health != "") | "\(.Name): \(.Health)"' || echo "All healthy or no health checks"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
register: health_status
|
|
||||||
changed_when: false
|
|
||||||
ignore_errors: yes
|
|
||||||
|
|
||||||
- name: Get deployed image information
|
- name: Get deployed image information
|
||||||
shell: |
|
shell: |
|
||||||
@@ -175,8 +157,9 @@
|
|||||||
Image Tag: {{ image_tag }}
|
Image Tag: {{ image_tag }}
|
||||||
Deployed Image: {{ deployed_image.stdout }}
|
Deployed Image: {{ deployed_image.stdout }}
|
||||||
Image Pull: {{ 'SUCCESS' if image_pull.changed else 'SKIPPED (already exists)' }}
|
Image Pull: {{ 'SUCCESS' if image_pull.changed else 'SKIPPED (already exists)' }}
|
||||||
Stack Deploy: {{ 'UPDATED' if stack_deploy.changed else 'NO_CHANGE' }}
|
Stack Deploy: {{ 'UPDATED' if application_stack_changed else 'NO_CHANGE' }}
|
||||||
Health Status: {{ health_status.stdout if health_status.stdout != '' else 'All services healthy' }}
|
Health Status: {{ application_health_output if application_health_output != '' else 'All services healthy' }}
|
||||||
|
Health Check HTTP Status: {{ application_healthcheck_status }}
|
||||||
dest: "{{ backups_path }}/{{ deployment_timestamp | regex_replace(':', '-') }}/deployment_metadata.txt"
|
dest: "{{ backups_path }}/{{ deployment_timestamp | regex_replace(':', '-') }}/deployment_metadata.txt"
|
||||||
owner: "{{ ansible_user }}"
|
owner: "{{ ansible_user }}"
|
||||||
group: "{{ ansible_user }}"
|
group: "{{ ansible_user }}"
|
||||||
@@ -200,7 +183,9 @@
|
|||||||
- "Commit: {{ git_commit_sha }}"
|
- "Commit: {{ git_commit_sha }}"
|
||||||
- "Timestamp: {{ deployment_timestamp }}"
|
- "Timestamp: {{ deployment_timestamp }}"
|
||||||
- "Image Pull: {{ 'SUCCESS' if image_pull.changed else 'SKIPPED' }}"
|
- "Image Pull: {{ 'SUCCESS' if image_pull.changed else 'SKIPPED' }}"
|
||||||
- "Stack Deploy: {{ 'UPDATED' if stack_deploy.changed else 'NO_CHANGE' }}"
|
- "Stack Deploy: {{ 'UPDATED' if application_stack_changed else 'NO_CHANGE' }}"
|
||||||
|
- "Health Output: {{ application_health_output if application_health_output != '' else 'All services healthy' }}"
|
||||||
|
- "Health Check HTTP Status: {{ application_healthcheck_status }}"
|
||||||
- "Health Check URL: {{ health_check_url }}"
|
- "Health Check URL: {{ health_check_url }}"
|
||||||
- ""
|
- ""
|
||||||
- "Next: Verify application is healthy"
|
- "Next: Verify application is healthy"
|
||||||
|
|||||||
96
deployment/ansible/playbooks/diagnose-staging-502.yml
Normal file
96
deployment/ansible/playbooks/diagnose-staging-502.yml
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
---
|
||||||
|
- name: Diagnose Staging 502 Error
|
||||||
|
hosts: production
|
||||||
|
gather_facts: yes
|
||||||
|
become: no
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Check Nginx error logs
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose logs --tail=50 staging-nginx 2>&1 | grep -iE "(error|502|bad gateway|php|fpm)" || echo "No errors found in nginx logs"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: nginx_errors
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Check PHP-FPM status in staging-app
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-app php-fpm-healthcheck 2>&1 || echo "PHP-FPM healthcheck failed"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: php_fpm_status
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Test PHP-FPM connection from nginx container
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-nginx sh -c "nc -zv staging-app 9000 2>&1 || echo 'Connection test failed'" || echo "Connection test failed"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: connection_test
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Check if PHP-FPM is listening
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-app sh -c "netstat -tlnp 2>/dev/null | grep 9000 || ss -tlnp 2>/dev/null | grep 9000 || echo 'Port 9000 not found'" || echo "Could not check ports"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: php_fpm_port
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Check staging-app process list
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-app sh -c "ps aux | grep -E '(php-fpm|nginx)' | head -20" || echo "Could not get process list"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: processes
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Check network connectivity
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-nginx sh -c "ping -c 2 staging-app 2>&1 || echo 'Ping failed'" || echo "Network test failed"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: network_test
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Check if /var/www/html/public/index.php exists
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-nginx sh -c "test -f /var/www/html/public/index.php && echo 'index.php exists' || echo 'index.php NOT FOUND'" || echo "Could not check file"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: index_php_check
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Display Nginx error logs
|
||||||
|
debug:
|
||||||
|
msg: "{{ nginx_errors.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display PHP-FPM status
|
||||||
|
debug:
|
||||||
|
msg: "{{ php_fpm_status.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display connection test
|
||||||
|
debug:
|
||||||
|
msg: "{{ connection_test.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display PHP-FPM port check
|
||||||
|
debug:
|
||||||
|
msg: "{{ php_fpm_port.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display processes
|
||||||
|
debug:
|
||||||
|
msg: "{{ processes.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display network test
|
||||||
|
debug:
|
||||||
|
msg: "{{ network_test.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display index.php check
|
||||||
|
debug:
|
||||||
|
msg: "{{ index_php_check.stdout_lines }}"
|
||||||
71
deployment/ansible/playbooks/fix-staging-complete.yml
Normal file
71
deployment/ansible/playbooks/fix-staging-complete.yml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
---
|
||||||
|
- name: Complete Fix for Staging (502 + Git)
|
||||||
|
hosts: production
|
||||||
|
gather_facts: yes
|
||||||
|
become: no
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Check if index.php exists in staging-app
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-app sh -c "ls -la /var/www/html/public/index.php 2>&1" || echo "index.php NOT FOUND"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: index_php_app
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Check if index.php exists in staging-nginx
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-nginx sh -c "ls -la /var/www/html/public/index.php 2>&1" || echo "index.php NOT FOUND"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: index_php_nginx
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Check PHP-FPM listen configuration
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-app sh -c "cat /usr/local/etc/php-fpm.d/www.conf | grep -E '(^listen|^listen.allowed_clients|^listen.owner|^listen.group|^user|^group)' | head -20" || echo "Could not read config"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: php_fpm_full_config
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Test actual HTTP request to staging-app
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-nginx sh -c "curl -v http://staging-app:9000/index.php 2>&1 | head -30" || echo "HTTP test failed"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: http_test
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Fix Git ownership permanently in staging-app entrypoint
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-app sh -c "cd /var/www/html && git config --global --add safe.directory /var/www/html && git config --global --get-all safe.directory" || echo "Git config failed"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: git_config_check
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Display index.php check in app
|
||||||
|
debug:
|
||||||
|
msg: "{{ index_php_app.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display index.php check in nginx
|
||||||
|
debug:
|
||||||
|
msg: "{{ index_php_nginx.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display PHP-FPM config
|
||||||
|
debug:
|
||||||
|
msg: "{{ php_fpm_full_config.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display HTTP test
|
||||||
|
debug:
|
||||||
|
msg: "{{ http_test.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display git config
|
||||||
|
debug:
|
||||||
|
msg: "{{ git_config_check.stdout_lines }}"
|
||||||
83
deployment/ansible/playbooks/fix-staging-issues.yml
Normal file
83
deployment/ansible/playbooks/fix-staging-issues.yml
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
---
|
||||||
|
- name: Fix Staging Issues (502 Error + Git Ownership)
|
||||||
|
hosts: production
|
||||||
|
gather_facts: yes
|
||||||
|
become: no
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Get recent nginx error logs
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose logs --tail=100 staging-nginx 2>&1
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: nginx_all_logs
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Test PHP-FPM connection with curl
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-nginx sh -c "curl -v http://staging-app:9000 2>&1 | head -20" || echo "Connection test completed"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: curl_test
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Check PHP-FPM configuration
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-app sh -c "cat /usr/local/etc/php-fpm.d/www.conf | grep -E '(listen|listen.allowed_clients)' | head -10" || echo "Could not read PHP-FPM config"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: php_fpm_config
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Fix Git ownership issue in staging-app
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-app sh -c "cd /var/www/html && git config --global --add safe.directory /var/www/html && echo 'Git safe.directory configured'" || echo "Git config failed"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: git_fix
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Test if nginx can reach PHP-FPM
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-nginx sh -c "echo 'GET /index.php HTTP/1.0' | nc staging-app 9000 2>&1 | head -10" || docker compose exec -T staging-nginx sh -c "timeout 2 bash -c '</dev/tcp/staging-app/9000' && echo 'Port 9000 is reachable' || echo 'Port 9000 not reachable'" || echo "Could not test connection"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: port_test
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Check if nginx can read public directory
|
||||||
|
shell: |
|
||||||
|
cd ~/deployment/stacks/staging && docker compose exec -T staging-nginx sh -c "ls -la /var/www/html/public/ | head -10" || echo "Could not list public directory"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: public_dir_check
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Display all nginx logs
|
||||||
|
debug:
|
||||||
|
msg: "{{ nginx_all_logs.stdout_lines[-30:] }}"
|
||||||
|
|
||||||
|
- name: Display curl test
|
||||||
|
debug:
|
||||||
|
msg: "{{ curl_test.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display PHP-FPM config
|
||||||
|
debug:
|
||||||
|
msg: "{{ php_fpm_config.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display git fix result
|
||||||
|
debug:
|
||||||
|
msg: "{{ git_fix.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display port test
|
||||||
|
debug:
|
||||||
|
msg: "{{ port_test.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Display public directory check
|
||||||
|
debug:
|
||||||
|
msg: "{{ public_dir_check.stdout_lines }}"
|
||||||
@@ -41,284 +41,33 @@
|
|||||||
|
|
||||||
# 1. Deploy Traefik (Reverse Proxy & SSL)
|
# 1. Deploy Traefik (Reverse Proxy & SSL)
|
||||||
- name: Deploy Traefik stack
|
- name: Deploy Traefik stack
|
||||||
community.docker.docker_compose_v2:
|
import_role:
|
||||||
project_src: "{{ stacks_base_path }}/traefik"
|
name: traefik
|
||||||
state: present
|
|
||||||
pull: always
|
|
||||||
register: traefik_output
|
|
||||||
|
|
||||||
- name: Wait for Traefik to be ready
|
|
||||||
wait_for:
|
|
||||||
timeout: "{{ wait_timeout }}"
|
|
||||||
when: traefik_output.changed
|
|
||||||
|
|
||||||
- name: Check Traefik logs for readiness hint
|
|
||||||
shell: docker compose logs traefik 2>&1 | grep -Ei "(configuration loaded|traefik[[:space:]]v|Starting provider|Server configuration loaded)" || true
|
|
||||||
args:
|
|
||||||
chdir: "{{ stacks_base_path }}/traefik"
|
|
||||||
register: traefik_logs
|
|
||||||
until: traefik_logs.stdout != ""
|
|
||||||
retries: 6
|
|
||||||
delay: 10
|
|
||||||
changed_when: false
|
|
||||||
ignore_errors: yes
|
|
||||||
|
|
||||||
# 2. Deploy PostgreSQL (Database)
|
# 2. Deploy PostgreSQL (Database)
|
||||||
- name: Deploy PostgreSQL stack
|
- name: Deploy PostgreSQL stack
|
||||||
community.docker.docker_compose_v2:
|
import_role:
|
||||||
project_src: "{{ stacks_base_path }}/postgresql"
|
name: postgresql
|
||||||
state: present
|
|
||||||
pull: always
|
|
||||||
register: postgres_output
|
|
||||||
|
|
||||||
- name: Wait for PostgreSQL to be ready
|
|
||||||
wait_for:
|
|
||||||
timeout: "{{ wait_timeout }}"
|
|
||||||
when: postgres_output.changed
|
|
||||||
|
|
||||||
- name: Check PostgreSQL logs for readiness
|
|
||||||
shell: docker compose logs postgres 2>&1 | grep -Ei "(ready to accept connections|database system is ready)" || true
|
|
||||||
args:
|
|
||||||
chdir: "{{ stacks_base_path }}/postgresql"
|
|
||||||
register: postgres_logs
|
|
||||||
until: postgres_logs.stdout != ""
|
|
||||||
retries: 6
|
|
||||||
delay: 10
|
|
||||||
changed_when: false
|
|
||||||
ignore_errors: yes
|
|
||||||
|
|
||||||
# 3. Deploy Docker Registry (Private Registry)
|
# 3. Deploy Docker Registry (Private Registry)
|
||||||
- name: Ensure Registry auth directory exists
|
|
||||||
file:
|
|
||||||
path: "{{ registry_auth_path }}"
|
|
||||||
state: directory
|
|
||||||
mode: '0755'
|
|
||||||
become: yes
|
|
||||||
|
|
||||||
- name: Optionally load registry credentials from vault
|
|
||||||
include_vars:
|
|
||||||
file: "{{ playbook_dir }}/../secrets/production.vault.yml"
|
|
||||||
no_log: yes
|
|
||||||
ignore_errors: yes
|
|
||||||
delegate_to: localhost
|
|
||||||
become: no
|
|
||||||
|
|
||||||
- name: Set registry credentials from vault or defaults
|
|
||||||
set_fact:
|
|
||||||
registry_username: "{{ vault_docker_registry_username | default(docker_registry_username_default) }}"
|
|
||||||
registry_password: "{{ vault_docker_registry_password | default(docker_registry_password_default) }}"
|
|
||||||
no_log: true
|
|
||||||
|
|
||||||
- name: Fail if registry password is not set
|
|
||||||
fail:
|
|
||||||
msg: "Registry password must be set in vault or docker_registry_password_default"
|
|
||||||
when: registry_password is not defined or registry_password == ""
|
|
||||||
|
|
||||||
- name: Create Registry htpasswd file if missing
|
|
||||||
shell: |
|
|
||||||
if [ ! -f {{ registry_auth_path }}/htpasswd ]; then
|
|
||||||
docker run --rm --entrypoint htpasswd httpd:2 -Bbn {{ registry_username }} {{ registry_password }} > {{ registry_auth_path }}/htpasswd
|
|
||||||
chmod 644 {{ registry_auth_path }}/htpasswd
|
|
||||||
fi
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
become: yes
|
|
||||||
changed_when: true
|
|
||||||
register: registry_auth_created
|
|
||||||
no_log: true
|
|
||||||
|
|
||||||
- name: Deploy Docker Registry stack
|
- name: Deploy Docker Registry stack
|
||||||
community.docker.docker_compose_v2:
|
import_role:
|
||||||
project_src: "{{ stacks_base_path }}/registry"
|
name: registry
|
||||||
state: present
|
|
||||||
pull: always
|
|
||||||
register: registry_output
|
|
||||||
|
|
||||||
- name: Wait for Docker Registry to be ready
|
|
||||||
wait_for:
|
|
||||||
timeout: "{{ wait_timeout }}"
|
|
||||||
when: registry_output.changed
|
|
||||||
|
|
||||||
- name: Check Registry logs for readiness
|
|
||||||
shell: docker compose logs registry 2>&1 | grep -Ei "(listening on|listening at|http server)" || true
|
|
||||||
args:
|
|
||||||
chdir: "{{ stacks_base_path }}/registry"
|
|
||||||
register: registry_logs
|
|
||||||
until: registry_logs.stdout != ""
|
|
||||||
retries: 6
|
|
||||||
delay: 10
|
|
||||||
changed_when: false
|
|
||||||
ignore_errors: yes
|
|
||||||
|
|
||||||
- name: Verify Registry is accessible
|
|
||||||
uri:
|
|
||||||
url: "http://127.0.0.1:5000/v2/_catalog"
|
|
||||||
user: "{{ registry_username }}"
|
|
||||||
password: "{{ registry_password }}"
|
|
||||||
status_code: 200
|
|
||||||
timeout: 5
|
|
||||||
register: registry_check
|
|
||||||
ignore_errors: yes
|
|
||||||
changed_when: false
|
|
||||||
no_log: true
|
|
||||||
|
|
||||||
- name: Display Registry status
|
|
||||||
debug:
|
|
||||||
msg: "Registry accessibility: {{ 'SUCCESS' if registry_check.status == 200 else 'FAILED - may need manual check' }}"
|
|
||||||
|
|
||||||
# 4. Deploy MinIO (Object Storage)
|
# 4. Deploy MinIO (Object Storage)
|
||||||
- name: Optionally load MinIO secrets from vault
|
|
||||||
include_vars:
|
|
||||||
file: "{{ playbook_dir }}/../secrets/production.vault.yml"
|
|
||||||
no_log: yes
|
|
||||||
ignore_errors: yes
|
|
||||||
delegate_to: localhost
|
|
||||||
become: no
|
|
||||||
|
|
||||||
- name: Set MinIO root password from vault or generate
|
|
||||||
set_fact:
|
|
||||||
minio_password: "{{ vault_minio_root_password | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits,punctuation')) }}"
|
|
||||||
no_log: yes
|
|
||||||
|
|
||||||
- name: Set MinIO root user from vault or use default
|
|
||||||
set_fact:
|
|
||||||
minio_user: "{{ vault_minio_root_user | default('minioadmin') }}"
|
|
||||||
|
|
||||||
- name: Ensure MinIO stack directory exists
|
|
||||||
file:
|
|
||||||
path: "{{ stacks_base_path }}/minio"
|
|
||||||
state: directory
|
|
||||||
mode: '0755'
|
|
||||||
|
|
||||||
- name: Create MinIO stack .env file
|
|
||||||
template:
|
|
||||||
src: "{{ playbook_dir }}/../templates/minio.env.j2"
|
|
||||||
dest: "{{ stacks_base_path }}/minio/.env"
|
|
||||||
owner: "{{ ansible_user }}"
|
|
||||||
group: "{{ ansible_user }}"
|
|
||||||
mode: '0600'
|
|
||||||
vars:
|
|
||||||
minio_root_user: "{{ minio_user }}"
|
|
||||||
minio_root_password: "{{ minio_password }}"
|
|
||||||
minio_api_domain: "{{ minio_api_domain }}"
|
|
||||||
minio_console_domain: "{{ minio_console_domain }}"
|
|
||||||
no_log: yes
|
|
||||||
|
|
||||||
- name: Deploy MinIO stack
|
- name: Deploy MinIO stack
|
||||||
community.docker.docker_compose_v2:
|
import_role:
|
||||||
project_src: "{{ stacks_base_path }}/minio"
|
name: minio
|
||||||
state: present
|
|
||||||
pull: always
|
|
||||||
register: minio_output
|
|
||||||
|
|
||||||
- name: Wait for MinIO to be ready
|
|
||||||
wait_for:
|
|
||||||
timeout: "{{ wait_timeout }}"
|
|
||||||
when: minio_output.changed
|
|
||||||
|
|
||||||
- name: Check MinIO logs for readiness
|
|
||||||
shell: docker compose logs minio 2>&1 | grep -Ei "(API:|WebUI:|MinIO Object Storage Server)" || true
|
|
||||||
args:
|
|
||||||
chdir: "{{ stacks_base_path }}/minio"
|
|
||||||
register: minio_logs
|
|
||||||
until: minio_logs.stdout != ""
|
|
||||||
retries: 6
|
|
||||||
delay: 10
|
|
||||||
changed_when: false
|
|
||||||
ignore_errors: yes
|
|
||||||
|
|
||||||
- name: Verify MinIO health endpoint
|
|
||||||
uri:
|
|
||||||
url: "http://127.0.0.1:9000/minio/health/live"
|
|
||||||
method: GET
|
|
||||||
status_code: [200, 404, 502, 503]
|
|
||||||
timeout: 5
|
|
||||||
register: minio_health_check
|
|
||||||
ignore_errors: yes
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Display MinIO status
|
|
||||||
debug:
|
|
||||||
msg: "MinIO health check: {{ 'SUCCESS' if minio_health_check.status == 200 else 'FAILED - Status: ' + (minio_health_check.status|string) }}"
|
|
||||||
|
|
||||||
# 5. Deploy Gitea (CRITICAL - Git Server + MySQL + Redis)
|
# 5. Deploy Gitea (CRITICAL - Git Server + MySQL + Redis)
|
||||||
- name: Deploy Gitea stack
|
- name: Deploy Gitea stack
|
||||||
community.docker.docker_compose_v2:
|
import_role:
|
||||||
project_src: "{{ stacks_base_path }}/gitea"
|
name: gitea
|
||||||
state: present
|
|
||||||
pull: always
|
|
||||||
register: gitea_output
|
|
||||||
|
|
||||||
- name: Wait for Gitea to be ready
|
|
||||||
wait_for:
|
|
||||||
timeout: "{{ wait_timeout }}"
|
|
||||||
when: gitea_output.changed
|
|
||||||
|
|
||||||
- name: Check Gitea logs for readiness
|
|
||||||
shell: docker compose logs gitea 2>&1 | grep -Ei "(Listen:|Server is running|Starting server)" || true
|
|
||||||
args:
|
|
||||||
chdir: "{{ stacks_base_path }}/gitea"
|
|
||||||
register: gitea_logs
|
|
||||||
until: gitea_logs.stdout != ""
|
|
||||||
retries: 12
|
|
||||||
delay: 10
|
|
||||||
changed_when: false
|
|
||||||
ignore_errors: yes
|
|
||||||
|
|
||||||
# 6. Deploy Monitoring (Portainer + Grafana + Prometheus)
|
# 6. Deploy Monitoring (Portainer + Grafana + Prometheus)
|
||||||
- name: Optionally load monitoring secrets from vault
|
|
||||||
include_vars:
|
|
||||||
file: "{{ playbook_dir }}/../secrets/production.vault.yml"
|
|
||||||
no_log: yes
|
|
||||||
ignore_errors: yes
|
|
||||||
delegate_to: localhost
|
|
||||||
become: no
|
|
||||||
|
|
||||||
- name: Set Grafana admin password from vault or generate
|
|
||||||
set_fact:
|
|
||||||
grafana_admin_password: "{{ vault_grafana_admin_password | default(lookup('password', '/dev/null length=25 chars=ascii_letters,digits')) }}"
|
|
||||||
|
|
||||||
- name: Set Prometheus password from vault or generate
|
|
||||||
set_fact:
|
|
||||||
prometheus_password: "{{ vault_prometheus_password | default(lookup('password', '/dev/null length=25 chars=ascii_letters,digits')) }}"
|
|
||||||
|
|
||||||
- name: Generate Prometheus BasicAuth hash
|
|
||||||
shell: |
|
|
||||||
docker run --rm httpd:alpine htpasswd -nbB admin "{{ prometheus_password }}" 2>/dev/null | cut -d ":" -f 2
|
|
||||||
register: prometheus_auth_hash
|
|
||||||
changed_when: false
|
|
||||||
no_log: yes
|
|
||||||
|
|
||||||
- name: Set Prometheus BasicAuth string
|
|
||||||
set_fact:
|
|
||||||
prometheus_auth: "admin:{{ prometheus_auth_hash.stdout }}"
|
|
||||||
|
|
||||||
- name: Ensure monitoring stack directory exists
|
|
||||||
file:
|
|
||||||
path: "{{ stacks_base_path }}/monitoring"
|
|
||||||
state: directory
|
|
||||||
mode: '0755'
|
|
||||||
|
|
||||||
- name: Create monitoring stack .env file
|
|
||||||
template:
|
|
||||||
src: "{{ playbook_dir }}/../templates/monitoring.env.j2"
|
|
||||||
dest: "{{ stacks_base_path }}/monitoring/.env"
|
|
||||||
owner: "{{ ansible_user }}"
|
|
||||||
group: "{{ ansible_user }}"
|
|
||||||
mode: '0600'
|
|
||||||
no_log: yes
|
|
||||||
|
|
||||||
- name: Deploy Monitoring stack
|
- name: Deploy Monitoring stack
|
||||||
community.docker.docker_compose_v2:
|
import_role:
|
||||||
project_src: "{{ stacks_base_path }}/monitoring"
|
name: monitoring
|
||||||
state: present
|
|
||||||
pull: always
|
|
||||||
register: monitoring_output
|
|
||||||
|
|
||||||
- name: Wait for Monitoring to be ready
|
|
||||||
wait_for:
|
|
||||||
timeout: "{{ wait_timeout }}"
|
|
||||||
when: monitoring_output.changed
|
|
||||||
|
|
||||||
# Verification
|
# Verification
|
||||||
- name: List all running containers
|
- name: List all running containers
|
||||||
@@ -345,180 +94,42 @@
|
|||||||
msg: "Gitea HTTPS check: {{ 'SUCCESS' if gitea_http_check.status == 200 else 'FAILED - Status: ' + (gitea_http_check.status|string) }}"
|
msg: "Gitea HTTPS check: {{ 'SUCCESS' if gitea_http_check.status == 200 else 'FAILED - Status: ' + (gitea_http_check.status|string) }}"
|
||||||
|
|
||||||
# 7. Deploy Application Stack
|
# 7. Deploy Application Stack
|
||||||
- name: Optionally load application secrets from vault
|
- name: Deploy Application Stack
|
||||||
include_vars:
|
import_role:
|
||||||
file: "{{ playbook_dir }}/../secrets/production.vault.yml"
|
name: application
|
||||||
no_log: yes
|
|
||||||
ignore_errors: yes
|
|
||||||
delegate_to: localhost
|
|
||||||
become: no
|
|
||||||
|
|
||||||
- name: Check if PostgreSQL .env exists
|
|
||||||
stat:
|
|
||||||
path: "{{ stacks_base_path }}/postgresql/.env"
|
|
||||||
register: postgres_env_file
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Extract PostgreSQL password from .env file
|
|
||||||
shell: "grep '^POSTGRES_PASSWORD=' {{ stacks_base_path }}/postgresql/.env 2>/dev/null | cut -d'=' -f2- || echo ''"
|
|
||||||
register: postgres_password_from_file
|
|
||||||
changed_when: false
|
|
||||||
failed_when: false
|
|
||||||
when: postgres_env_file.stat.exists
|
|
||||||
no_log: yes
|
|
||||||
|
|
||||||
- name: Set application database password (from file, vault, or generate)
|
|
||||||
set_fact:
|
|
||||||
app_db_password: "{{ postgres_password_from_file.stdout if (postgres_env_file.stat.exists and postgres_password_from_file.stdout != '') else (vault_db_root_password | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits,punctuation'))) }}"
|
|
||||||
no_log: yes
|
|
||||||
|
|
||||||
- name: Set application redis password from vault or generate
|
|
||||||
set_fact:
|
|
||||||
app_redis_password: "{{ vault_redis_password | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits,punctuation')) }}"
|
|
||||||
|
|
||||||
- name: Ensure application stack directory exists
|
|
||||||
file:
|
|
||||||
path: "{{ stacks_base_path }}/application"
|
|
||||||
state: directory
|
|
||||||
mode: '0755'
|
|
||||||
|
|
||||||
- name: Check if application stack docker-compose.yml exists locally
|
|
||||||
stat:
|
|
||||||
path: "{{ playbook_dir }}/../../stacks/application/docker-compose.yml"
|
|
||||||
register: app_compose_local
|
|
||||||
delegate_to: localhost
|
|
||||||
become: no
|
|
||||||
|
|
||||||
- name: Copy application stack docker-compose.yml to server
|
|
||||||
copy:
|
|
||||||
src: "{{ playbook_dir }}/../../stacks/application/docker-compose.yml"
|
|
||||||
dest: "{{ stacks_base_path }}/application/docker-compose.yml"
|
|
||||||
owner: "{{ ansible_user }}"
|
|
||||||
group: "{{ ansible_user }}"
|
|
||||||
mode: '0644'
|
|
||||||
when: app_compose_local.stat.exists
|
|
||||||
|
|
||||||
- name: Check if application stack nginx directory exists locally
|
|
||||||
stat:
|
|
||||||
path: "{{ playbook_dir }}/../../stacks/application/nginx/"
|
|
||||||
register: app_nginx_local
|
|
||||||
delegate_to: localhost
|
|
||||||
become: no
|
|
||||||
|
|
||||||
- name: Copy application stack nginx configuration to server
|
|
||||||
copy:
|
|
||||||
src: "{{ playbook_dir }}/../../stacks/application/nginx/"
|
|
||||||
dest: "{{ stacks_base_path }}/application/nginx/"
|
|
||||||
owner: "{{ ansible_user }}"
|
|
||||||
group: "{{ ansible_user }}"
|
|
||||||
mode: '0644'
|
|
||||||
when: app_nginx_local.stat.exists
|
|
||||||
|
|
||||||
- name: Create application stack .env file
|
|
||||||
template:
|
|
||||||
src: "{{ playbook_dir }}/../templates/application.env.j2"
|
|
||||||
dest: "{{ stacks_base_path }}/application/.env"
|
|
||||||
owner: "{{ ansible_user }}"
|
|
||||||
group: "{{ ansible_user }}"
|
|
||||||
mode: '0600'
|
|
||||||
vars:
|
|
||||||
db_password: "{{ app_db_password }}"
|
|
||||||
db_user: "{{ db_user | default(db_user_default) }}"
|
|
||||||
db_name: "{{ db_name | default(db_name_default) }}"
|
|
||||||
redis_password: "{{ app_redis_password }}"
|
|
||||||
app_domain: "{{ app_domain }}"
|
|
||||||
no_log: yes
|
|
||||||
|
|
||||||
- name: Deploy Application stack
|
|
||||||
community.docker.docker_compose_v2:
|
|
||||||
project_src: "{{ stacks_base_path }}/application"
|
|
||||||
state: present
|
|
||||||
pull: always
|
|
||||||
register: application_output
|
|
||||||
|
|
||||||
- name: Wait for Application to be ready
|
|
||||||
wait_for:
|
|
||||||
timeout: "{{ wait_timeout }}"
|
|
||||||
when: application_output.changed
|
|
||||||
|
|
||||||
- name: Wait for application containers to be healthy
|
|
||||||
pause:
|
|
||||||
seconds: 30
|
|
||||||
when: application_output.changed
|
|
||||||
|
|
||||||
- name: Check application container health status
|
|
||||||
shell: |
|
|
||||||
docker compose -f {{ stacks_base_path }}/application/docker-compose.yml ps --format json | jq -r '.[] | select(.Health != "healthy" and .Health != "" and .Health != "starting") | "\(.Name): \(.Health)"' || echo "All healthy or no health checks"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
register: app_health_status
|
|
||||||
changed_when: false
|
|
||||||
ignore_errors: yes
|
|
||||||
|
|
||||||
- name: Display application health status
|
- name: Display application health status
|
||||||
debug:
|
debug:
|
||||||
msg: "Application health: {{ app_health_status.stdout if app_health_status.stdout != '' else 'All services healthy or starting' }}"
|
msg: "Application health: {{ application_health_output if application_health_output != '' else 'All services healthy or starting' }}"
|
||||||
|
|
||||||
- name: Wait for app container to be ready before migration
|
|
||||||
wait_for:
|
|
||||||
timeout: 60
|
|
||||||
when: application_output.changed
|
|
||||||
|
|
||||||
- name: Check if app container is running
|
|
||||||
shell: |
|
|
||||||
docker compose -f {{ stacks_base_path }}/application/docker-compose.yml ps app | grep -q "Up" || exit 1
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
register: app_container_running
|
|
||||||
changed_when: false
|
|
||||||
failed_when: false
|
|
||||||
when: application_output.changed
|
|
||||||
|
|
||||||
- name: Run database migrations
|
|
||||||
shell: |
|
|
||||||
docker compose -f {{ stacks_base_path }}/application/docker-compose.yml exec -T app php console.php db:migrate
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
register: migration_result
|
|
||||||
changed_when: true
|
|
||||||
failed_when: false
|
|
||||||
ignore_errors: yes
|
|
||||||
when: application_output.changed and app_container_running.rc == 0
|
|
||||||
|
|
||||||
- name: Display migration result
|
- name: Display migration result
|
||||||
debug:
|
debug:
|
||||||
msg: |
|
msg: |
|
||||||
Migration Result:
|
Migration Result:
|
||||||
{{ migration_result.stdout if migration_result.rc == 0 else 'Migration may have failed - check logs with: docker compose -f ' + stacks_base_path + '/application/docker-compose.yml logs app' }}
|
{{ application_migration_stdout if application_migration_stdout != '' else 'Migration may have failed - check logs with: docker compose -f ' + application_stack_dest + '/docker-compose.yml logs app' }}
|
||||||
when: application_output.changed
|
when: application_stack_changed and application_run_migrations
|
||||||
|
|
||||||
- name: Verify application accessibility via HTTPS
|
|
||||||
uri:
|
|
||||||
url: "{{ health_check_url }}"
|
|
||||||
method: GET
|
|
||||||
validate_certs: no
|
|
||||||
status_code: [200, 404, 502, 503]
|
|
||||||
timeout: 10
|
|
||||||
register: app_health_check
|
|
||||||
ignore_errors: yes
|
|
||||||
when: application_output.changed
|
|
||||||
|
|
||||||
- name: Display application accessibility status
|
- name: Display application accessibility status
|
||||||
debug:
|
debug:
|
||||||
msg: "Application health check: {{ 'SUCCESS (HTTP ' + (app_health_check.status|string) + ')' if app_health_check.status == 200 else 'FAILED or not ready yet (HTTP ' + (app_health_check.status|string) + ')' }}"
|
msg: >-
|
||||||
when: application_output.changed
|
Application health check: {{
|
||||||
|
'SUCCESS (HTTP ' + (application_healthcheck_status | string) + ')'
|
||||||
|
if application_healthcheck_status == 200 else
|
||||||
|
'FAILED or not ready yet (HTTP ' + (application_healthcheck_status | string) + ')'
|
||||||
|
}}
|
||||||
|
when: application_stack_changed and application_healthcheck_url | length > 0
|
||||||
|
|
||||||
- name: Summary
|
- name: Summary
|
||||||
debug:
|
debug:
|
||||||
msg:
|
msg:
|
||||||
- "=== Infrastructure Deployment Complete ==="
|
- "=== Infrastructure Deployment Complete ==="
|
||||||
- "Traefik: {{ 'Deployed' if traefik_output.changed else 'Already running' }}"
|
- "Traefik: {{ 'Deployed' if traefik_stack_changed else 'Already running' }}"
|
||||||
- "PostgreSQL: {{ 'Deployed' if postgres_output.changed else 'Already running' }}"
|
- "PostgreSQL: {{ 'Deployed' if postgresql_stack_changed else 'Already running' }}"
|
||||||
- "Docker Registry: {{ 'Deployed' if registry_output.changed else 'Already running' }}"
|
- "Docker Registry: {{ 'Deployed' if registry_stack_changed else 'Already running' }}"
|
||||||
- "MinIO: {{ 'Deployed' if minio_output.changed else 'Already running' }}"
|
- "MinIO: {{ 'Deployed' if minio_stack_changed else 'Already running' }}"
|
||||||
- "Gitea: {{ 'Deployed' if gitea_output.changed else 'Already running' }}"
|
- "Gitea: {{ 'Deployed' if gitea_stack_changed else 'Already running' }}"
|
||||||
- "Monitoring: {{ 'Deployed' if monitoring_output.changed else 'Already running' }}"
|
- "Monitoring: {{ 'Deployed' if monitoring_stack_changed else 'Already running' }}"
|
||||||
- "Application: {{ 'Deployed' if application_output.changed else 'Already running' }}"
|
- "Application: {{ 'Deployed' if application_stack_changed else 'Already running' }}"
|
||||||
- ""
|
- ""
|
||||||
- "Next Steps:"
|
- "Next Steps:"
|
||||||
- "1. Access Gitea at: https://{{ gitea_domain }}"
|
- "1. Access Gitea at: https://{{ gitea_domain }}"
|
||||||
|
|||||||
34
deployment/ansible/roles/application/defaults/main.yml
Normal file
34
deployment/ansible/roles/application/defaults/main.yml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
# Source path for application stack files on the control node
|
||||||
|
application_stack_src: "{{ role_path }}/../../stacks/application"
|
||||||
|
|
||||||
|
# Destination path on the target host (defaults to configured app_stack_path)
|
||||||
|
application_stack_dest: "{{ app_stack_path | default(stacks_base_path + '/application') }}"
|
||||||
|
|
||||||
|
# Template used to generate the application .env file
|
||||||
|
application_env_template: "{{ role_path }}/../../templates/application.env.j2"
|
||||||
|
|
||||||
|
# Optional vault file containing secrets (loaded if present)
|
||||||
|
application_vault_file: "{{ role_path }}/../../secrets/production.vault.yml"
|
||||||
|
|
||||||
|
# Whether to synchronize stack files from repository
|
||||||
|
application_sync_files: true
|
||||||
|
|
||||||
|
# Compose recreate strategy ("auto", "always", "never")
|
||||||
|
application_compose_recreate: "auto"
|
||||||
|
|
||||||
|
# Whether to remove orphaned containers during compose up
|
||||||
|
application_remove_orphans: false
|
||||||
|
|
||||||
|
# Whether to run database migrations after (re)deploying the stack
|
||||||
|
application_run_migrations: true
|
||||||
|
|
||||||
|
# Optional health check URL to verify after deployment
|
||||||
|
application_healthcheck_url: "{{ health_check_url | default('') }}"
|
||||||
|
|
||||||
|
# Timeout used for waits in this role
|
||||||
|
application_wait_timeout: "{{ wait_timeout | default(60) }}"
|
||||||
|
application_wait_interval: 5
|
||||||
|
|
||||||
|
# Command executed inside the app container to run migrations
|
||||||
|
application_migration_command: "php console.php db:migrate"
|
||||||
69
deployment/ansible/roles/application/tasks/deploy.yml
Normal file
69
deployment/ansible/roles/application/tasks/deploy.yml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy application stack
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ application_stack_dest }}"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
recreate: "{{ application_compose_recreate }}"
|
||||||
|
remove_orphans: "{{ application_remove_orphans | bool }}"
|
||||||
|
register: application_compose_result
|
||||||
|
|
||||||
|
- name: Wait for application container to report Up
|
||||||
|
shell: |
|
||||||
|
docker compose -f {{ application_stack_dest }}/docker-compose.yml ps app | grep -Eiq "Up|running"
|
||||||
|
register: application_app_running
|
||||||
|
changed_when: false
|
||||||
|
until: application_app_running.rc == 0
|
||||||
|
retries: "{{ ((application_wait_timeout | int) + (application_wait_interval | int) - 1) // (application_wait_interval | int) }}"
|
||||||
|
delay: "{{ application_wait_interval | int }}"
|
||||||
|
when: application_compose_result.changed
|
||||||
|
|
||||||
|
- name: Ensure app container is running before migrations
|
||||||
|
shell: |
|
||||||
|
docker compose -f {{ application_stack_dest }}/docker-compose.yml ps app | grep -Eiq "Up|running"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: application_app_container_running
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
when: application_compose_result.changed
|
||||||
|
|
||||||
|
- name: Run database migrations
|
||||||
|
shell: |
|
||||||
|
docker compose -f {{ application_stack_dest }}/docker-compose.yml exec -T app {{ application_migration_command }}
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: application_migration_result
|
||||||
|
changed_when: true
|
||||||
|
failed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
when:
|
||||||
|
- application_run_migrations
|
||||||
|
- application_compose_result.changed
|
||||||
|
- application_app_container_running.rc == 0
|
||||||
|
|
||||||
|
- name: Collect application container status
|
||||||
|
shell: docker compose -f {{ application_stack_dest }}/docker-compose.yml ps
|
||||||
|
register: application_ps
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Perform application health check
|
||||||
|
uri:
|
||||||
|
url: "{{ application_healthcheck_url }}"
|
||||||
|
method: GET
|
||||||
|
validate_certs: no
|
||||||
|
status_code: [200, 404, 502, 503]
|
||||||
|
timeout: 10
|
||||||
|
register: application_healthcheck_result
|
||||||
|
ignore_errors: yes
|
||||||
|
when:
|
||||||
|
- application_healthcheck_url | length > 0
|
||||||
|
- application_compose_result.changed
|
||||||
|
|
||||||
|
- name: Set application role summary facts
|
||||||
|
set_fact:
|
||||||
|
application_stack_changed: "{{ application_compose_result.changed | default(false) }}"
|
||||||
|
application_health_output: "{{ application_ps.stdout | default('') }}"
|
||||||
|
application_healthcheck_status: "{{ application_healthcheck_result.status | default('unknown') }}"
|
||||||
|
application_migration_stdout: "{{ application_migration_result.stdout | default('') }}"
|
||||||
7
deployment/ansible/roles/application/tasks/main.yml
Normal file
7
deployment/ansible/roles/application/tasks/main.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
- name: Synchronize application stack files
|
||||||
|
include_tasks: sync.yml
|
||||||
|
when: application_sync_files | bool
|
||||||
|
|
||||||
|
- name: Deploy application stack
|
||||||
|
include_tasks: deploy.yml
|
||||||
94
deployment/ansible/roles/application/tasks/sync.yml
Normal file
94
deployment/ansible/roles/application/tasks/sync.yml
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure application stack destination directory exists
|
||||||
|
file:
|
||||||
|
path: "{{ application_stack_dest }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Check if vault file exists locally
|
||||||
|
stat:
|
||||||
|
path: "{{ application_vault_file }}"
|
||||||
|
delegate_to: localhost
|
||||||
|
register: application_vault_stat
|
||||||
|
become: no
|
||||||
|
|
||||||
|
- name: Optionally load application secrets from vault
|
||||||
|
include_vars:
|
||||||
|
file: "{{ application_vault_file }}"
|
||||||
|
when: application_vault_stat.stat.exists
|
||||||
|
no_log: yes
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
|
||||||
|
- name: Check if PostgreSQL .env exists on target host
|
||||||
|
stat:
|
||||||
|
path: "{{ stacks_base_path }}/postgresql/.env"
|
||||||
|
register: application_postgres_env_file
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Extract PostgreSQL password from .env file
|
||||||
|
shell: "grep '^POSTGRES_PASSWORD=' {{ stacks_base_path }}/postgresql/.env 2>/dev/null | cut -d'=' -f2- || echo ''"
|
||||||
|
register: application_postgres_password
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
when: application_postgres_env_file.stat.exists
|
||||||
|
no_log: yes
|
||||||
|
|
||||||
|
- name: Determine application database password
|
||||||
|
set_fact:
|
||||||
|
application_db_password: >-
|
||||||
|
{{ (application_postgres_env_file.stat.exists and application_postgres_password.stdout != '') |
|
||||||
|
ternary(application_postgres_password.stdout,
|
||||||
|
vault_db_root_password | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits,punctuation'))) }}
|
||||||
|
no_log: yes
|
||||||
|
|
||||||
|
- name: Determine application redis password
|
||||||
|
set_fact:
|
||||||
|
application_redis_password: "{{ vault_redis_password | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits,punctuation')) }}"
|
||||||
|
no_log: yes
|
||||||
|
|
||||||
|
- name: Check if application docker-compose source exists locally
|
||||||
|
stat:
|
||||||
|
path: "{{ application_stack_src }}/docker-compose.yml"
|
||||||
|
delegate_to: localhost
|
||||||
|
register: application_compose_src
|
||||||
|
become: no
|
||||||
|
|
||||||
|
- name: Copy application docker-compose to target host
|
||||||
|
copy:
|
||||||
|
src: "{{ application_stack_src }}/docker-compose.yml"
|
||||||
|
dest: "{{ application_stack_dest }}/docker-compose.yml"
|
||||||
|
owner: "{{ ansible_user }}"
|
||||||
|
group: "{{ ansible_user }}"
|
||||||
|
mode: '0644'
|
||||||
|
when: application_compose_src.stat.exists
|
||||||
|
|
||||||
|
- name: Check if nginx configuration exists locally
|
||||||
|
stat:
|
||||||
|
path: "{{ application_stack_src }}/nginx"
|
||||||
|
delegate_to: localhost
|
||||||
|
register: application_nginx_src
|
||||||
|
become: no
|
||||||
|
|
||||||
|
- name: Synchronize nginx configuration
|
||||||
|
copy:
|
||||||
|
src: "{{ application_stack_src }}/nginx/"
|
||||||
|
dest: "{{ application_stack_dest }}/nginx/"
|
||||||
|
owner: "{{ ansible_user }}"
|
||||||
|
group: "{{ ansible_user }}"
|
||||||
|
mode: '0644'
|
||||||
|
when: application_nginx_src.stat.exists
|
||||||
|
|
||||||
|
- name: Render application environment file
|
||||||
|
template:
|
||||||
|
src: "{{ application_env_template }}"
|
||||||
|
dest: "{{ application_stack_dest }}/.env"
|
||||||
|
owner: "{{ ansible_user }}"
|
||||||
|
group: "{{ ansible_user }}"
|
||||||
|
mode: '0600'
|
||||||
|
vars:
|
||||||
|
db_password: "{{ application_db_password }}"
|
||||||
|
db_user: "{{ db_user | default(db_user_default) }}"
|
||||||
|
db_name: "{{ db_name | default(db_name_default) }}"
|
||||||
|
redis_password: "{{ application_redis_password }}"
|
||||||
|
app_domain: "{{ app_domain }}"
|
||||||
4
deployment/ansible/roles/gitea/defaults/main.yml
Normal file
4
deployment/ansible/roles/gitea/defaults/main.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
gitea_stack_path: "{{ stacks_base_path }}/gitea"
|
||||||
|
gitea_wait_timeout: "{{ wait_timeout | default(60) }}"
|
||||||
|
gitea_wait_interval: 5
|
||||||
35
deployment/ansible/roles/gitea/tasks/main.yml
Normal file
35
deployment/ansible/roles/gitea/tasks/main.yml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy Gitea stack
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ gitea_stack_path }}"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: gitea_compose_result
|
||||||
|
|
||||||
|
- name: Check Gitea container status
|
||||||
|
shell: |
|
||||||
|
docker compose -f {{ gitea_stack_path }}/docker-compose.yml ps gitea | grep -Eiq "Up|running"
|
||||||
|
register: gitea_state
|
||||||
|
changed_when: false
|
||||||
|
until: gitea_state.rc == 0
|
||||||
|
retries: "{{ ((gitea_wait_timeout | int) + (gitea_wait_interval | int) - 1) // (gitea_wait_interval | int) }}"
|
||||||
|
delay: "{{ gitea_wait_interval | int }}"
|
||||||
|
failed_when: gitea_state.rc != 0
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Check Gitea logs for readiness
|
||||||
|
shell: docker compose logs gitea 2>&1 | grep -Ei "(Listen:|Server is running|Starting server)" || true
|
||||||
|
args:
|
||||||
|
chdir: "{{ gitea_stack_path }}"
|
||||||
|
register: gitea_logs
|
||||||
|
until: gitea_logs.stdout != ""
|
||||||
|
retries: 12
|
||||||
|
delay: 10
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Record Gitea deployment facts
|
||||||
|
set_fact:
|
||||||
|
gitea_stack_changed: "{{ gitea_compose_result.changed | default(false) }}"
|
||||||
|
gitea_log_hint: "{{ gitea_logs.stdout | default('') }}"
|
||||||
6
deployment/ansible/roles/minio/defaults/main.yml
Normal file
6
deployment/ansible/roles/minio/defaults/main.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
minio_stack_path: "{{ stacks_base_path }}/minio"
|
||||||
|
minio_wait_timeout: "{{ wait_timeout | default(60) }}"
|
||||||
|
minio_wait_interval: 5
|
||||||
|
minio_env_template: "{{ role_path }}/../../templates/minio.env.j2"
|
||||||
|
minio_vault_file: "{{ role_path }}/../../secrets/production.vault.yml"
|
||||||
90
deployment/ansible/roles/minio/tasks/main.yml
Normal file
90
deployment/ansible/roles/minio/tasks/main.yml
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
---
|
||||||
|
- name: Check if MinIO vault file exists
|
||||||
|
stat:
|
||||||
|
path: "{{ minio_vault_file }}"
|
||||||
|
delegate_to: localhost
|
||||||
|
register: minio_vault_stat
|
||||||
|
become: no
|
||||||
|
|
||||||
|
- name: Optionally load MinIO secrets from vault
|
||||||
|
include_vars:
|
||||||
|
file: "{{ minio_vault_file }}"
|
||||||
|
when: minio_vault_stat.stat.exists
|
||||||
|
no_log: yes
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
|
||||||
|
- name: Set MinIO root password from vault or generate
|
||||||
|
set_fact:
|
||||||
|
minio_root_password: "{{ vault_minio_root_password | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits,punctuation')) }}"
|
||||||
|
no_log: yes
|
||||||
|
|
||||||
|
- name: Set MinIO root user from vault or use default
|
||||||
|
set_fact:
|
||||||
|
minio_root_user: "{{ vault_minio_root_user | default('minioadmin') }}"
|
||||||
|
no_log: yes
|
||||||
|
|
||||||
|
- name: Ensure MinIO stack directory exists
|
||||||
|
file:
|
||||||
|
path: "{{ minio_stack_path }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create MinIO stack .env file
|
||||||
|
template:
|
||||||
|
src: "{{ minio_env_template }}"
|
||||||
|
dest: "{{ minio_stack_path }}/.env"
|
||||||
|
owner: "{{ ansible_user }}"
|
||||||
|
group: "{{ ansible_user }}"
|
||||||
|
mode: '0600'
|
||||||
|
|
||||||
|
- name: Deploy MinIO stack
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ minio_stack_path }}"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: minio_compose_result
|
||||||
|
|
||||||
|
- name: Check MinIO container status
|
||||||
|
shell: |
|
||||||
|
docker compose -f {{ minio_stack_path }}/docker-compose.yml ps minio | grep -Eiq "Up|running"
|
||||||
|
register: minio_state
|
||||||
|
changed_when: false
|
||||||
|
until: minio_state.rc == 0
|
||||||
|
retries: "{{ ((minio_wait_timeout | int) + (minio_wait_interval | int) - 1) // (minio_wait_interval | int) }}"
|
||||||
|
delay: "{{ minio_wait_interval | int }}"
|
||||||
|
failed_when: minio_state.rc != 0
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Check MinIO logs for readiness
|
||||||
|
shell: docker compose logs minio 2>&1 | grep -Ei "(API:|WebUI:|MinIO Object Storage Server)" || true
|
||||||
|
args:
|
||||||
|
chdir: "{{ minio_stack_path }}"
|
||||||
|
register: minio_logs
|
||||||
|
until: minio_logs.stdout != ""
|
||||||
|
retries: 6
|
||||||
|
delay: 10
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Verify MinIO health endpoint
|
||||||
|
uri:
|
||||||
|
url: "http://127.0.0.1:9000/minio/health/live"
|
||||||
|
method: GET
|
||||||
|
status_code: [200, 404, 502, 503]
|
||||||
|
timeout: 5
|
||||||
|
register: minio_health_check
|
||||||
|
ignore_errors: yes
|
||||||
|
changed_when: false
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Display MinIO status
|
||||||
|
debug:
|
||||||
|
msg: "MinIO health check: {{ 'SUCCESS' if minio_health_check.status == 200 else 'FAILED - Status: ' + (minio_health_check.status|string) }}"
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Record MinIO deployment facts
|
||||||
|
set_fact:
|
||||||
|
minio_stack_changed: "{{ minio_compose_result.changed | default(false) }}"
|
||||||
|
minio_health_status: "{{ minio_health_check.status | default('unknown') }}"
|
||||||
5
deployment/ansible/roles/monitoring/defaults/main.yml
Normal file
5
deployment/ansible/roles/monitoring/defaults/main.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
monitoring_stack_path: "{{ stacks_base_path }}/monitoring"
|
||||||
|
monitoring_wait_timeout: "{{ wait_timeout | default(60) }}"
|
||||||
|
monitoring_env_template: "{{ role_path }}/../../templates/monitoring.env.j2"
|
||||||
|
monitoring_vault_file: "{{ role_path }}/../../secrets/production.vault.yml"
|
||||||
68
deployment/ansible/roles/monitoring/tasks/main.yml
Normal file
68
deployment/ansible/roles/monitoring/tasks/main.yml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
- name: Check if monitoring vault file exists
|
||||||
|
stat:
|
||||||
|
path: "{{ monitoring_vault_file }}"
|
||||||
|
delegate_to: localhost
|
||||||
|
register: monitoring_vault_stat
|
||||||
|
become: no
|
||||||
|
|
||||||
|
- name: Optionally load monitoring secrets from vault
|
||||||
|
include_vars:
|
||||||
|
file: "{{ monitoring_vault_file }}"
|
||||||
|
when: monitoring_vault_stat.stat.exists
|
||||||
|
no_log: yes
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
|
||||||
|
- name: Set Grafana admin password from vault or generate
|
||||||
|
set_fact:
|
||||||
|
grafana_admin_password: "{{ vault_grafana_admin_password | default(lookup('password', '/dev/null length=25 chars=ascii_letters,digits')) }}"
|
||||||
|
no_log: yes
|
||||||
|
|
||||||
|
- name: Set Prometheus password from vault or generate
|
||||||
|
set_fact:
|
||||||
|
prometheus_password: "{{ vault_prometheus_password | default(lookup('password', '/dev/null length=25 chars=ascii_letters,digits')) }}"
|
||||||
|
no_log: yes
|
||||||
|
|
||||||
|
- name: Generate Prometheus BasicAuth hash
|
||||||
|
shell: |
|
||||||
|
docker run --rm httpd:alpine htpasswd -nbB admin "{{ prometheus_password }}" 2>/dev/null | cut -d ":" -f 2
|
||||||
|
register: prometheus_auth_hash
|
||||||
|
changed_when: false
|
||||||
|
no_log: yes
|
||||||
|
|
||||||
|
- name: Set Prometheus BasicAuth string
|
||||||
|
set_fact:
|
||||||
|
prometheus_auth: "admin:{{ prometheus_auth_hash.stdout }}"
|
||||||
|
no_log: yes
|
||||||
|
|
||||||
|
- name: Ensure monitoring stack directory exists
|
||||||
|
file:
|
||||||
|
path: "{{ monitoring_stack_path }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create monitoring stack .env file
|
||||||
|
template:
|
||||||
|
src: "{{ monitoring_env_template }}"
|
||||||
|
dest: "{{ monitoring_stack_path }}/.env"
|
||||||
|
owner: "{{ ansible_user }}"
|
||||||
|
group: "{{ ansible_user }}"
|
||||||
|
mode: '0600'
|
||||||
|
no_log: yes
|
||||||
|
|
||||||
|
- name: Deploy Monitoring stack
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ monitoring_stack_path }}"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: monitoring_compose_result
|
||||||
|
|
||||||
|
- name: Wait for Monitoring to be ready
|
||||||
|
wait_for:
|
||||||
|
timeout: "{{ monitoring_wait_timeout }}"
|
||||||
|
when: monitoring_compose_result.changed
|
||||||
|
|
||||||
|
- name: Record monitoring deployment facts
|
||||||
|
set_fact:
|
||||||
|
monitoring_stack_changed: "{{ monitoring_compose_result.changed | default(false) }}"
|
||||||
4
deployment/ansible/roles/postgresql/defaults/main.yml
Normal file
4
deployment/ansible/roles/postgresql/defaults/main.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
postgresql_stack_path: "{{ stacks_base_path }}/postgresql"
|
||||||
|
postgresql_wait_timeout: "{{ wait_timeout | default(60) }}"
|
||||||
|
postgresql_wait_interval: 5
|
||||||
23
deployment/ansible/roles/postgresql/tasks/main.yml
Normal file
23
deployment/ansible/roles/postgresql/tasks/main.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy PostgreSQL stack
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ postgresql_stack_path }}"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: postgresql_compose_result
|
||||||
|
|
||||||
|
- name: Check PostgreSQL container status
|
||||||
|
shell: |
|
||||||
|
docker compose -f {{ postgresql_stack_path }}/docker-compose.yml ps postgres | grep -Eiq "Up|running"
|
||||||
|
register: postgresql_state
|
||||||
|
changed_when: false
|
||||||
|
until: postgresql_state.rc == 0
|
||||||
|
retries: "{{ ((postgresql_wait_timeout | int) + (postgresql_wait_interval | int) - 1) // (postgresql_wait_interval | int) }}"
|
||||||
|
delay: "{{ postgresql_wait_interval | int }}"
|
||||||
|
failed_when: postgresql_state.rc != 0
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Record PostgreSQL deployment facts
|
||||||
|
set_fact:
|
||||||
|
postgresql_stack_changed: "{{ postgresql_compose_result.changed | default(false) }}"
|
||||||
|
postgresql_log_hint: ""
|
||||||
5
deployment/ansible/roles/registry/defaults/main.yml
Normal file
5
deployment/ansible/roles/registry/defaults/main.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
registry_stack_path: "{{ stacks_base_path }}/registry"
|
||||||
|
registry_wait_timeout: "{{ wait_timeout | default(60) }}"
|
||||||
|
registry_wait_interval: 5
|
||||||
|
registry_vault_file: "{{ role_path }}/../../secrets/production.vault.yml"
|
||||||
115
deployment/ansible/roles/registry/tasks/main.yml
Normal file
115
deployment/ansible/roles/registry/tasks/main.yml
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure Registry auth directory exists
|
||||||
|
file:
|
||||||
|
path: "{{ registry_auth_path }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Check if registry vault file exists
|
||||||
|
stat:
|
||||||
|
path: "{{ registry_vault_file }}"
|
||||||
|
delegate_to: localhost
|
||||||
|
register: registry_vault_stat
|
||||||
|
become: no
|
||||||
|
|
||||||
|
- name: Optionally load registry credentials from vault
|
||||||
|
include_vars:
|
||||||
|
file: "{{ registry_vault_file }}"
|
||||||
|
when: registry_vault_stat.stat.exists
|
||||||
|
no_log: yes
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
register: registry_vault_vars
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Fail if registry vault decryption failed
|
||||||
|
fail:
|
||||||
|
msg: >
|
||||||
|
Failed to decrypt {{ registry_vault_file }}.
|
||||||
|
Provide a valid vault password (e.g. via --vault-password-file) or update docker_registry_password_default.
|
||||||
|
when:
|
||||||
|
- not ansible_check_mode
|
||||||
|
- registry_vault_stat.stat.exists
|
||||||
|
- registry_vault_vars is defined
|
||||||
|
- registry_vault_vars.failed | default(false)
|
||||||
|
|
||||||
|
- name: Set registry credentials from vault or defaults or generate
|
||||||
|
set_fact:
|
||||||
|
registry_username: "{{ vault_docker_registry_username | default(docker_registry_username_default) }}"
|
||||||
|
registry_password: >-
|
||||||
|
{{
|
||||||
|
vault_docker_registry_password
|
||||||
|
| default(docker_registry_password_default)
|
||||||
|
| default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits'))
|
||||||
|
}}
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Create Registry htpasswd file if missing
|
||||||
|
shell: |
|
||||||
|
docker run --rm --entrypoint htpasswd httpd:2 -Bbn {{ registry_username }} {{ registry_password }} > {{ registry_auth_path }}/htpasswd
|
||||||
|
chmod 644 {{ registry_auth_path }}/htpasswd
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
creates: "{{ registry_auth_path }}/htpasswd"
|
||||||
|
become: yes
|
||||||
|
no_log: true
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Deploy Docker Registry stack
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ registry_stack_path }}"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: registry_compose_result
|
||||||
|
|
||||||
|
- name: Wait for Docker Registry to be ready
|
||||||
|
wait_for:
|
||||||
|
timeout: "{{ registry_wait_timeout }}"
|
||||||
|
when: registry_compose_result.changed
|
||||||
|
|
||||||
|
- name: Check Registry container status
|
||||||
|
shell: |
|
||||||
|
docker compose -f {{ registry_stack_path }}/docker-compose.yml ps registry | grep -Eiq "Up|running"
|
||||||
|
register: registry_state
|
||||||
|
changed_when: false
|
||||||
|
until: registry_state.rc == 0
|
||||||
|
retries: "{{ ((registry_wait_timeout | int) + (registry_wait_interval | int) - 1) // (registry_wait_interval | int) }}"
|
||||||
|
delay: "{{ registry_wait_interval | int }}"
|
||||||
|
failed_when: registry_state.rc != 0
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Check Registry logs for readiness
|
||||||
|
shell: docker compose logs registry 2>&1 | grep -Ei "(listening on|listening at|http server)" || true
|
||||||
|
args:
|
||||||
|
chdir: "{{ registry_stack_path }}"
|
||||||
|
register: registry_logs
|
||||||
|
until: registry_logs.stdout != ""
|
||||||
|
retries: 6
|
||||||
|
delay: 10
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Verify Registry is accessible
|
||||||
|
uri:
|
||||||
|
url: "http://127.0.0.1:5000/v2/_catalog"
|
||||||
|
user: "{{ registry_username }}"
|
||||||
|
password: "{{ registry_password }}"
|
||||||
|
status_code: 200
|
||||||
|
timeout: 5
|
||||||
|
register: registry_check
|
||||||
|
ignore_errors: yes
|
||||||
|
changed_when: false
|
||||||
|
no_log: true
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Display Registry status
|
||||||
|
debug:
|
||||||
|
msg: "Registry accessibility: {{ 'SUCCESS' if registry_check.status == 200 else 'FAILED - may need manual check' }}"
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Record registry deployment facts
|
||||||
|
set_fact:
|
||||||
|
registry_stack_changed: "{{ registry_compose_result.changed | default(false) }}"
|
||||||
|
registry_access_status: "{{ registry_check.status | default('unknown') }}"
|
||||||
4
deployment/ansible/roles/traefik/defaults/main.yml
Normal file
4
deployment/ansible/roles/traefik/defaults/main.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
traefik_stack_path: "{{ stacks_base_path }}/traefik"
|
||||||
|
traefik_wait_timeout: "{{ wait_timeout | default(60) }}"
|
||||||
|
traefik_wait_interval: 5
|
||||||
23
deployment/ansible/roles/traefik/tasks/main.yml
Normal file
23
deployment/ansible/roles/traefik/tasks/main.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy Traefik stack
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ traefik_stack_path }}"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: traefik_compose_result
|
||||||
|
|
||||||
|
- name: Check Traefik container status
|
||||||
|
shell: |
|
||||||
|
docker compose -f {{ traefik_stack_path }}/docker-compose.yml ps traefik | grep -Eiq "Up|running"
|
||||||
|
register: traefik_state
|
||||||
|
changed_when: false
|
||||||
|
until: traefik_state.rc == 0
|
||||||
|
retries: "{{ ((traefik_wait_timeout | int) + (traefik_wait_interval | int) - 1) // (traefik_wait_interval | int) }}"
|
||||||
|
delay: "{{ traefik_wait_interval | int }}"
|
||||||
|
failed_when: traefik_state.rc != 0
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Record Traefik deployment facts
|
||||||
|
set_fact:
|
||||||
|
traefik_stack_changed: "{{ traefik_compose_result.changed | default(false) }}"
|
||||||
|
traefik_log_hint: ""
|
||||||
198
deployment/docs/README.md
Normal file
198
deployment/docs/README.md
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
# Deployment Dokumentation - Index
|
||||||
|
|
||||||
|
**Stand:** 2025-11-01
|
||||||
|
**Status:** ? Vollst?ndige Dokumentation vorhanden
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Schnellstart
|
||||||
|
|
||||||
|
### F?r schnellen Einstieg
|
||||||
|
|
||||||
|
1. **[quick-start.md](guides/quick-start.md)** ?
|
||||||
|
- Schnellstart-Guide
|
||||||
|
- Pipeline-Status pr?fen
|
||||||
|
- Troubleshooting Quick Reference
|
||||||
|
|
||||||
|
2. **[code-change-workflow.md](guides/code-change-workflow.md)**
|
||||||
|
- Wie Code?nderungen gepusht werden
|
||||||
|
- Automatisches vs. manuelles Deployment
|
||||||
|
- Branching-Strategien
|
||||||
|
- Beispiel-Workflows
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Detaillierte Guides
|
||||||
|
|
||||||
|
### Setup & Konfiguration
|
||||||
|
|
||||||
|
3. **[setup-guide.md](guides/setup-guide.md)**
|
||||||
|
- Kompletter Setup-Guide von Anfang bis Ende
|
||||||
|
- Infrastructure Deployment
|
||||||
|
- Gitea Runner Setup
|
||||||
|
- Secrets Konfiguration
|
||||||
|
- Schritt-f?r-Schritt Anleitung
|
||||||
|
|
||||||
|
4. **[deployment-commands.md](guides/deployment-commands.md)**
|
||||||
|
- Command-Referenz f?r Deployment
|
||||||
|
- Ansible Playbook Befehle
|
||||||
|
- Docker Compose Kommandos
|
||||||
|
- Troubleshooting Kommandos
|
||||||
|
|
||||||
|
5. **[vault-password.md](guides/vault-password.md)**
|
||||||
|
- Ansible Vault Password Dokumentation
|
||||||
|
- Setup und Verwaltung
|
||||||
|
- CI/CD Integration
|
||||||
|
- Best Practices
|
||||||
|
|
||||||
|
### Deployment-Prozess
|
||||||
|
|
||||||
|
6. **[application-stack.md](reference/application-stack.md)**
|
||||||
|
- Detaillierter Deployment-Ablauf Schritt f?r Schritt
|
||||||
|
- Was passiert bei jedem Deployment
|
||||||
|
- Container-Neustart Details
|
||||||
|
- Rollback-Prozess
|
||||||
|
- Troubleshooting
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Status & ?bersicht
|
||||||
|
|
||||||
|
### Projekt-Status
|
||||||
|
|
||||||
|
7. **[deployment-summary.md](status/deployment-summary.md)**
|
||||||
|
- Was ist fertig?
|
||||||
|
- Was fehlt noch?
|
||||||
|
- Completion Rate
|
||||||
|
- N?chste Schritte
|
||||||
|
|
||||||
|
8. **[deployment-todo.md](status/deployment-todo.md)**
|
||||||
|
- Aktuelle TODO-Liste
|
||||||
|
- Priorisierte Reihenfolge
|
||||||
|
- Quick Checklist
|
||||||
|
|
||||||
|
### CI/CD Pipeline
|
||||||
|
|
||||||
|
9. **[ci-cd-status.md](status/ci-cd-status.md)**
|
||||||
|
- Aktueller CI/CD Status
|
||||||
|
- Secrets-?bersicht
|
||||||
|
- Runner-Status
|
||||||
|
- Checkliste f?r Completion
|
||||||
|
- Troubleshooting
|
||||||
|
|
||||||
|
### Verbesserungen & Planung
|
||||||
|
|
||||||
|
10. **[improvements.md](status/improvements.md)**
|
||||||
|
- Verbesserungsvorschl?ge
|
||||||
|
- Refactoring-Ideen
|
||||||
|
- Architektur-?berlegungen
|
||||||
|
|
||||||
|
11. **[next-steps.md](status/next-steps.md)**
|
||||||
|
- Geplante n?chste Schritte
|
||||||
|
- Roadmap
|
||||||
|
- Priorit?ten
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Stack-spezifische Dokumentation
|
||||||
|
|
||||||
|
### Infrastructure Stacks
|
||||||
|
|
||||||
|
- **[stacks/traefik/README.md](../stacks/traefik/README.md)** - Reverse Proxy & SSL
|
||||||
|
- **[stacks/postgresql/README.md](../stacks/postgresql/README.md)** - Database mit Backups
|
||||||
|
- **[stacks/registry/README.md](../stacks/registry/README.md)** - Private Docker Registry
|
||||||
|
- **[stacks/gitea/README.md](../stacks/gitea/README.md)** - Git Server & CI/CD
|
||||||
|
- **[stacks/monitoring/README.md](../stacks/monitoring/README.md)** - Monitoring Tools
|
||||||
|
|
||||||
|
### Application Stack
|
||||||
|
|
||||||
|
- **[stacks/application/README.md](../stacks/application/README.md)** - Application Stack Details
|
||||||
|
- **[ansible/README.md](../ansible/README.md)** - Ansible Playbooks Dokumentation
|
||||||
|
|
||||||
|
### CI/CD
|
||||||
|
|
||||||
|
- **[gitea-runner/README.md](../gitea-runner/README.md)** - Gitea Runner Setup
|
||||||
|
- **[.gitea/workflows/production-deploy.yml](../../.gitea/workflows/production-deploy.yml)** - Haupt-Deployment-Pipeline
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Security & VPN
|
||||||
|
|
||||||
|
- **[vault-password.md](guides/vault-password.md)** - Ansible Vault Password Dokumentation
|
||||||
|
- **[docs/WIREGUARD-SETUP.md](../../docs/WIREGUARD-SETUP.md)** - WireGuard VPN Setup
|
||||||
|
- **[ansible/playbooks/README-WIREGUARD.md](../ansible/playbooks/README-WIREGUARD.md)** - WireGuard Ansible Playbooks
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Troubleshooting
|
||||||
|
|
||||||
|
### Workflow-Probleme
|
||||||
|
|
||||||
|
- **[workflow-troubleshooting.md](reference/workflow-troubleshooting.md)** - Workflow Troubleshooting
|
||||||
|
- **[quick-start.md](guides/quick-start.md)** - Troubleshooting Quick Reference
|
||||||
|
|
||||||
|
### Test-Dokumentation
|
||||||
|
|
||||||
|
- **[test-results.md](tests/test-results.md)** - Test Ergebnisse
|
||||||
|
- **[git-deployment-test.md](tests/git-deployment-test.md)** - Git Deployment Tests
|
||||||
|
- **[git-deployment-issue.md](tests/git-deployment-issue.md)** - Git Deployment Issues
|
||||||
|
- **[test-git-deployment.md](tests/test-git-deployment.md)** - Git Deployment Test Guide
|
||||||
|
- **[quick-test.md](tests/quick-test.md)** - Quick Tests
|
||||||
|
- **[recommended-test-flow.md](tests/recommended-test-flow.md)** - Empfohlene Test-Workflows
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Historie & Logs
|
||||||
|
|
||||||
|
- **[cleanup-log.md](history/cleanup-log.md)** - Cleanup Log
|
||||||
|
- **[cleanup-summary.md](history/cleanup-summary.md)** - Cleanup Zusammenfassung
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Haupt-Dokumentation
|
||||||
|
|
||||||
|
- **[README.md](../README.md)** - Haupt-Dokumentation & Architektur-?bersicht
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Empfohlene Lesereihenfolge
|
||||||
|
|
||||||
|
### F?r neue Nutzer
|
||||||
|
|
||||||
|
1. **[quick-start.md](guides/quick-start.md)** - Schneller ?berblick
|
||||||
|
2. **[code-change-workflow.md](guides/code-change-workflow.md)** - Code deployen lernen
|
||||||
|
3. **[deployment-summary.md](status/deployment-summary.md)** - Projekt-Status verstehen
|
||||||
|
|
||||||
|
### F?r Deployment-Verst?ndnis
|
||||||
|
|
||||||
|
1. **[application-stack.md](reference/application-stack.md)** - Wie Deployment funktioniert
|
||||||
|
2. **[ci-cd-status.md](status/ci-cd-status.md)** - CI/CD Pipeline verstehen
|
||||||
|
3. **[setup-guide.md](guides/setup-guide.md)** - Komplette Setup-Anleitung
|
||||||
|
|
||||||
|
### F?r Troubleshooting
|
||||||
|
|
||||||
|
1. **[quick-start.md](guides/quick-start.md)** - Quick Troubleshooting
|
||||||
|
2. **[workflow-troubleshooting.md](reference/workflow-troubleshooting.md)** - Workflow-Probleme
|
||||||
|
3. Stack-spezifische READMEs f?r Details
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Dokumentations-Standards
|
||||||
|
|
||||||
|
**Alle Dokumentationsdateien:**
|
||||||
|
- Verwenden Markdown-Format
|
||||||
|
- Haben klare ?berschriften-Struktur
|
||||||
|
- Enthalten Code-Beispiele
|
||||||
|
- Haben Troubleshooting-Abschnitte (wenn relevant)
|
||||||
|
- Verlinken zu verwandten Dokumenten
|
||||||
|
|
||||||
|
**Standards:**
|
||||||
|
- ? Beispiele sind ausf?hrbar
|
||||||
|
- ? Pfade sind absolut oder relativ klar
|
||||||
|
- ? Screenshots/Links sind aktuell
|
||||||
|
- ? Status ist klar markiert (?/??/?)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Letzte Aktualisierung:** 2025-11-01
|
||||||
|
**Status:** ? Dokumentation vollst?ndig
|
||||||
223
deployment/docs/RESTRUCTURE_PROPOSAL.md
Normal file
223
deployment/docs/RESTRUCTURE_PROPOSAL.md
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
# Dokumentations-Restrukturierung - Vorschlag
|
||||||
|
|
||||||
|
## Aktuelle Situation
|
||||||
|
|
||||||
|
### Statistiken
|
||||||
|
- **Gesamt:** 34 Markdown-Dateien im `deployment/` Ordner
|
||||||
|
- **Root-Level:** 21 Markdown-Dateien direkt in `deployment/`
|
||||||
|
- **Verlinkungen:** 35 Referenzen im `DOCUMENTATION_INDEX.md`
|
||||||
|
|
||||||
|
### Problem
|
||||||
|
- Viele Dokumentationsdateien direkt im Root (`deployment/*.md`)
|
||||||
|
- Mischung aus:
|
||||||
|
- Haupt-Dokumentation (README.md, SETUP-GUIDE.md)
|
||||||
|
- Status/Tracking (DEPLOYMENT_SUMMARY.md, DEPLOYMENT-TODO.md)
|
||||||
|
- Test/Entwicklung (TEST_*.md, GIT_*.md, QUICK_TEST.md)
|
||||||
|
- Troubleshooting (WORKFLOW-TROUBLESHOOTING.md, CI_CD_STATUS.md)
|
||||||
|
- Logs/Historie (CLEANUP_LOG.md, CLEANUP_SUMMARY.md)
|
||||||
|
- Schwer ?berschaubar
|
||||||
|
- Konfigurationsdateien (ansible/, stacks/, gitea-runner/) vermischt mit Docs
|
||||||
|
|
||||||
|
## Vorschlag: Strukturierte Dokumentation
|
||||||
|
|
||||||
|
### Neue Struktur
|
||||||
|
|
||||||
|
```
|
||||||
|
deployment/
|
||||||
|
??? README.md # ? Haupt-Dokumentation (bleibt)
|
||||||
|
??? docs/ # ?? Alle Dokumentation
|
||||||
|
? ??? README.md # Dokumentations-Index (ersetzt DOCUMENTATION_INDEX.md)
|
||||||
|
? ?
|
||||||
|
? ??? guides/ # ?? Anleitungen & Guides
|
||||||
|
? ? ??? setup-guide.md # (SETUP-GUIDE.md)
|
||||||
|
? ? ??? quick-start.md # (QUICK_START.md)
|
||||||
|
? ? ??? code-change-workflow.md # (CODE_CHANGE_WORKFLOW.md)
|
||||||
|
? ? ??? deployment-commands.md # (DEPLOYMENT_COMMANDS.md)
|
||||||
|
? ? ??? vault-password.md # (ansible/VAULT_PASSWORD.md)
|
||||||
|
? ?
|
||||||
|
? ??? reference/ # ?? Referenz-Dokumentation
|
||||||
|
? ? ??? application-stack.md # (APPLICATION_STACK_DEPLOYMENT.md)
|
||||||
|
? ? ??? ansible-playbooks.md # (ansible/README.md)
|
||||||
|
? ? ??? workflow-troubleshooting.md # (WORKFLOW-TROUBLESHOOTING.md)
|
||||||
|
? ?
|
||||||
|
? ??? status/ # ?? Status & Tracking
|
||||||
|
? ? ??? deployment-summary.md # (DEPLOYMENT_SUMMARY.md)
|
||||||
|
? ? ??? deployment-todo.md # (DEPLOYMENT-TODO.md)
|
||||||
|
? ? ??? ci-cd-status.md # (CI_CD_STATUS.md)
|
||||||
|
? ? ??? improvements.md # (IMPROVEMENTS.md)
|
||||||
|
? ? ??? next-steps.md # (NEXT_STEPS.md)
|
||||||
|
? ?
|
||||||
|
? ??? testing/ # ?? Test-Dokumentation
|
||||||
|
? ? ??? test-results.md # (TEST_RESULT.md)
|
||||||
|
? ? ??? git-deployment-test.md # (GIT_DEPLOYMENT_TEST.md)
|
||||||
|
? ? ??? git-deployment-issue.md # (GIT_DEPLOYMENT_ISSUE.md)
|
||||||
|
? ? ??? test-git-deployment.md # (TEST_GIT_DEPLOYMENT.md)
|
||||||
|
? ? ??? quick-test.md # (QUICK_TEST.md)
|
||||||
|
? ? ??? recommended-test-flow.md # (RECOMMENDED_TEST_FLOW.md)
|
||||||
|
? ?
|
||||||
|
? ??? history/ # ?? Logs & Historie
|
||||||
|
? ??? cleanup-log.md # (CLEANUP_LOG.md)
|
||||||
|
? ??? cleanup-summary.md # (CLEANUP_SUMMARY.md)
|
||||||
|
?
|
||||||
|
??? ansible/ # Ansible Konfiguration
|
||||||
|
? ??? README.md # ? Kurze ?bersicht, Link zu docs/reference/
|
||||||
|
? ??? ...
|
||||||
|
?
|
||||||
|
??? stacks/ # Docker Compose Stacks
|
||||||
|
? ??? */README.md # Stack-spezifische Docs (bleiben)
|
||||||
|
?
|
||||||
|
??? gitea-runner/ # Runner Konfiguration
|
||||||
|
??? README.md # Runner-spezifische Docs (bleibt)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Vorteile
|
||||||
|
|
||||||
|
### ? ?bersichtlichkeit
|
||||||
|
- Klare Trennung: Docs vs. Konfiguration
|
||||||
|
- Kategorisierung nach Zweck (Guides, Reference, Status, Tests, History)
|
||||||
|
- Einfacher zu navigieren
|
||||||
|
|
||||||
|
### ? Wartbarkeit
|
||||||
|
- Logische Gruppierung ?hnlicher Dokumente
|
||||||
|
- Einfaches Finden relevanter Dokumentation
|
||||||
|
- Einfachere Aktualisierung
|
||||||
|
|
||||||
|
### ? Klare Hierarchie
|
||||||
|
- `docs/README.md` als zentraler Einstiegspunkt
|
||||||
|
- `deployment/README.md` bleibt f?r Architektur-?bersicht
|
||||||
|
- Stack-spezifische READMEs bleiben nahe am Code
|
||||||
|
|
||||||
|
### ? Saubere Struktur
|
||||||
|
- Konfigurationsdateien nicht mit Docs vermischt
|
||||||
|
- Tests getrennt von Produktions-Docs
|
||||||
|
- Historie/Logs in separatem Bereich
|
||||||
|
|
||||||
|
## Nachteile
|
||||||
|
|
||||||
|
### ?? Breaking Changes
|
||||||
|
- Alle Verlinkungen m?ssen aktualisiert werden
|
||||||
|
- Externe Referenzen (z.B. in anderen Projekten) m?ssen angepasst werden
|
||||||
|
- Git-Historie wird aufgeteilt
|
||||||
|
|
||||||
|
### ?? Migration-Aufwand
|
||||||
|
- 21 Dateien m?ssen verschoben werden
|
||||||
|
- Verlinkungen in vielen Dateien aktualisieren
|
||||||
|
- CI/CD Skripte k?nnten Pfade referenzieren
|
||||||
|
|
||||||
|
### ?? Gew?hnung
|
||||||
|
- Team muss neue Struktur lernen
|
||||||
|
- Neue Pfade m?ssen bekannt gemacht werden
|
||||||
|
|
||||||
|
## Alternative: Minimale Restrukturierung
|
||||||
|
|
||||||
|
Falls die vollst?ndige Restrukturierung zu aufw?ndig ist:
|
||||||
|
|
||||||
|
### Option B: Nur Root-Level aufr?umen
|
||||||
|
|
||||||
|
```
|
||||||
|
deployment/
|
||||||
|
??? README.md # Haupt-Dokumentation
|
||||||
|
??? DOCUMENTATION_INDEX.md # Index (bleibt)
|
||||||
|
?
|
||||||
|
??? docs/ # Nur Root-Level Docs verschieben
|
||||||
|
? ??? guides/
|
||||||
|
? ? ??? setup-guide.md
|
||||||
|
? ? ??? quick-start.md
|
||||||
|
? ? ??? code-change-workflow.md
|
||||||
|
? ?
|
||||||
|
? ??? status/
|
||||||
|
? ? ??? deployment-summary.md
|
||||||
|
? ? ??? deployment-todo.md
|
||||||
|
? ? ??? ci-cd-status.md
|
||||||
|
? ?
|
||||||
|
? ??? tests/ # Test-Dokumentation
|
||||||
|
? ??? test-results.md
|
||||||
|
? ??? ...
|
||||||
|
?
|
||||||
|
??? ansible/ # Bleibt wie es ist
|
||||||
|
? ??? README.md
|
||||||
|
?
|
||||||
|
??? stacks/ # Bleibt wie es ist
|
||||||
|
```
|
||||||
|
|
||||||
|
**Vorteile:**
|
||||||
|
- Weniger Breaking Changes
|
||||||
|
- Schneller umzusetzen
|
||||||
|
- Hauptproblem (Root-Level Unordnung) gel?st
|
||||||
|
|
||||||
|
**Nachteile:**
|
||||||
|
- Keine vollst?ndige Strukturierung
|
||||||
|
- Stack-Docs bleiben verstreut
|
||||||
|
|
||||||
|
## Empfehlung
|
||||||
|
|
||||||
|
### F?r jetzt: **Option B (Minimal)**
|
||||||
|
1. ? Schnell umsetzbar
|
||||||
|
2. ? L?sen des Hauptproblems (21 Root-Level Dateien)
|
||||||
|
3. ? Minimal invasive ?nderungen
|
||||||
|
4. ? Stack-Docs bleiben nahe am Code (gut!)
|
||||||
|
|
||||||
|
### Sp?ter: **Option A (Vollst?ndig)** wenn:
|
||||||
|
- Mehr Zeit f?r Migration vorhanden
|
||||||
|
- Automatisierung f?r Link-Updates verf?gbar
|
||||||
|
- Team w?chst und bessere Struktur ben?tigt
|
||||||
|
|
||||||
|
## Migration-Plan (Option B)
|
||||||
|
|
||||||
|
### Phase 1: Docs-Ordner erstellen
|
||||||
|
```bash
|
||||||
|
mkdir -p deployment/docs/{guides,status,tests}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: Dateien verschieben
|
||||||
|
```bash
|
||||||
|
# Guides
|
||||||
|
mv SETUP-GUIDE.md docs/guides/setup-guide.md
|
||||||
|
mv QUICK_START.md docs/guides/quick-start.md
|
||||||
|
mv CODE_CHANGE_WORKFLOW.md docs/guides/code-change-workflow.md
|
||||||
|
mv DEPLOYMENT_COMMANDS.md docs/guides/deployment-commands.md
|
||||||
|
mv ansible/VAULT_PASSWORD.md docs/guides/vault-password.md
|
||||||
|
|
||||||
|
# Status
|
||||||
|
mv DEPLOYMENT_SUMMARY.md docs/status/deployment-summary.md
|
||||||
|
mv DEPLOYMENT-TODO.md docs/status/deployment-todo.md
|
||||||
|
mv CI_CD_STATUS.md docs/status/ci-cd-status.md
|
||||||
|
mv IMPROVEMENTS.md docs/status/improvements.md
|
||||||
|
mv NEXT_STEPS.md docs/status/next-steps.md
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
mv TEST_RESULT.md docs/tests/test-results.md
|
||||||
|
mv GIT_DEPLOYMENT_TEST.md docs/tests/git-deployment-test.md
|
||||||
|
mv GIT_DEPLOYMENT_ISSUE.md docs/tests/git-deployment-issue.md
|
||||||
|
mv TEST_GIT_DEPLOYMENT.md docs/tests/test-git-deployment.md
|
||||||
|
mv QUICK_TEST.md docs/tests/quick-test.md
|
||||||
|
mv RECOMMENDED_TEST_FLOW.md docs/tests/recommended-test-flow.md
|
||||||
|
|
||||||
|
# Reference (optional, kann auch bleiben)
|
||||||
|
mv APPLICATION_STACK_DEPLOYMENT.md docs/reference/application-stack.md
|
||||||
|
mv WORKFLOW-TROUBLESHOOTING.md docs/reference/workflow-troubleshooting.md
|
||||||
|
|
||||||
|
# History (optional)
|
||||||
|
mv CLEANUP_LOG.md docs/history/cleanup-log.md
|
||||||
|
mv CLEANUP_SUMMARY.md docs/history/cleanup-summary.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 3: Verlinkungen aktualisieren
|
||||||
|
- `DOCUMENTATION_INDEX.md` aktualisieren
|
||||||
|
- `README.md` Verlinkungen pr?fen
|
||||||
|
- Interne Links in Dokumenten pr?fen
|
||||||
|
- CI/CD Skripte pr?fen
|
||||||
|
|
||||||
|
### Phase 4: README.md erstellen
|
||||||
|
- `docs/README.md` als neuen Index erstellen
|
||||||
|
- `DOCUMENTATION_INDEX.md` ? `docs/README.md` migrieren
|
||||||
|
|
||||||
|
## Entscheidung ben?tigt
|
||||||
|
|
||||||
|
**Frage:** Soll die Dokumentation restrukturiert werden?
|
||||||
|
|
||||||
|
- ? **Ja, Option B (Minimal)** - Nur Root-Level aufr?umen
|
||||||
|
- ? **Ja, Option A (Vollst?ndig)** - Komplette Restrukturierung
|
||||||
|
- ? **Nein** - Behalten wie es ist
|
||||||
|
|
||||||
|
**Empfehlung:** Option B f?r jetzt, Option A sp?ter wenn n?tig.
|
||||||
@@ -13,8 +13,8 @@ git push origin main
|
|||||||
→ Automatisches Deployment startet (~8-15 Minuten)
|
→ Automatisches Deployment startet (~8-15 Minuten)
|
||||||
|
|
||||||
**📖 Verwandte Dokumentation:**
|
**📖 Verwandte Dokumentation:**
|
||||||
- **[Application Stack Deployment](APPLICATION_STACK_DEPLOYMENT.md)** - Wie das Deployment genau funktioniert
|
- **[Application Stack Deployment](../reference/application-stack.md)** - Wie das Deployment genau funktioniert
|
||||||
- **[CI/CD Status](CI_CD_STATUS.md)** - Aktueller Status der Pipeline
|
- **[CI/CD Status](../status/ci-cd-status.md)** - Aktueller Status der Pipeline
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -116,9 +116,9 @@ ansible-playbook -i inventory/production.yml \
|
|||||||
|
|
||||||
## 📖 Vollständige Dokumentation
|
## 📖 Vollständige Dokumentation
|
||||||
|
|
||||||
- **[README.md](README.md)** - Haupt-Dokumentation
|
- **[README.md](../../README.md)** - Haupt-Dokumentation
|
||||||
- **[QUICK_START.md](QUICK_START.md)** - Schnellstart-Guide
|
- **[quick-start.md](quick-start.md)** - Schnellstart-Guide
|
||||||
- **[CODE_CHANGE_WORKFLOW.md](CODE_CHANGE_WORKFLOW.md)** - Codeänderungen workflow
|
- **[code-change-workflow.md](code-change-workflow.md)** - Codeänderungen workflow
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ curl https://michaelschiemer.de/health
|
|||||||
|
|
||||||
### Setup-Dokumentation
|
### Setup-Dokumentation
|
||||||
|
|
||||||
- **`SETUP-GUIDE.md`** - Kompletter Setup-Guide
|
- **`docs/guides/setup-guide.md`** - Kompletter Setup-Guide
|
||||||
- **`ansible/README.md`** - Ansible Playbooks Dokumentation
|
- **`ansible/README.md`** - Ansible Playbooks Dokumentation
|
||||||
- **`stacks/application/README.md`** - Application Stack Details
|
- **`stacks/application/README.md`** - Application Stack Details
|
||||||
|
|
||||||
262
deployment/docs/guides/vault-password.md
Normal file
262
deployment/docs/guides/vault-password.md
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
# Ansible Vault Password Dokumentation
|
||||||
|
|
||||||
|
## ?bersicht
|
||||||
|
|
||||||
|
Das Ansible Vault-Passwort wird verwendet, um verschl?sselte Secrets-Dateien (`production.vault.yml`) zu sch?tzen. Diese Dokumentation beschreibt, wie das Vault-Passwort angelegt, gespeichert und verwendet wird.
|
||||||
|
|
||||||
|
## Historischer Kontext
|
||||||
|
|
||||||
|
### Erstellungsdatum
|
||||||
|
- **Erstellt am:** 30. Oktober 2025, 21:42:27
|
||||||
|
- **Datei:** `deployment/ansible/secrets/.vault_pass`
|
||||||
|
- **Erstes Setup-Script:** 31. Oktober 2025 (Commit `e26eb2a`)
|
||||||
|
- **Script-Datei:** `deployment/ansible/scripts/init-secrets.sh`
|
||||||
|
|
||||||
|
### Einf?hrung
|
||||||
|
Das Vault-Passwort-System wurde im Rahmen des CI/CD-Pipeline-Setups eingef?hrt, um die sichere Verwaltung von Production-Secrets zu erm?glichen. Das automatische Setup-Script wurde am 31. Oktober 2025 hinzugef?gt, um die manuelle Erstellung zu vereinfachen.
|
||||||
|
|
||||||
|
## Speicherort und Sicherheit
|
||||||
|
|
||||||
|
### Dateispeicherort
|
||||||
|
- **Pfad:** `deployment/ansible/secrets/.vault_pass`
|
||||||
|
- **Berechtigungen:** `600` (nur Owner lesbar/schreibbar)
|
||||||
|
- **Gitignored:** ? Ja (in `.gitignore` hinterlegt)
|
||||||
|
- **Inhalt:** Eine Zeile mit dem Vault-Passwort (plaintext)
|
||||||
|
|
||||||
|
### Sicherheitshinweise
|
||||||
|
?? **WICHTIG:**
|
||||||
|
- Das Passwort ist in Klartext in der Datei gespeichert
|
||||||
|
- Die Datei ist **gitignored** und wird **nie** ins Repository committet
|
||||||
|
- Berechtigungen sind auf `600` gesetzt (nur Owner-Zugriff)
|
||||||
|
- Das Passwort sollte zus?tzlich im **Passwort-Manager** gespeichert werden
|
||||||
|
- F?r verschiedene Umgebungen (dev/staging/prod) sollten unterschiedliche Passw?rter verwendet werden
|
||||||
|
|
||||||
|
## Erstellung des Vault-Passworts
|
||||||
|
|
||||||
|
### Methode 1: Automatisiertes Script (Empfohlen)
|
||||||
|
|
||||||
|
Das Script `init-secrets.sh` f?hrt Sie interaktiv durch den Setup-Prozess:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd deployment/ansible
|
||||||
|
./scripts/init-secrets.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Was das Script macht:**
|
||||||
|
1. Pr?ft, ob `.vault_pass` bereits existiert
|
||||||
|
2. Falls nicht vorhanden: Fragt interaktiv nach dem Passwort (mit Best?tigung)
|
||||||
|
3. Speichert das Passwort in `secrets/.vault_pass`
|
||||||
|
4. Setzt Berechtigungen auf `600`
|
||||||
|
5. Erstellt und verschl?sselt `production.vault.yml` (optional)
|
||||||
|
|
||||||
|
**Vorteile:**
|
||||||
|
- Automatische Berechtigungen
|
||||||
|
- Passwort-Best?tigung verhindert Tippfehler
|
||||||
|
- Vollst?ndiger Setup-Workflow inkl. Vault-Datei-Erstellung
|
||||||
|
|
||||||
|
### Methode 2: Manuelle Erstellung
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd deployment/ansible/secrets
|
||||||
|
|
||||||
|
# Passwort erstellen
|
||||||
|
echo "your-secure-vault-password-here" > .vault_pass
|
||||||
|
|
||||||
|
# Sicherheit: Berechtigungen setzen
|
||||||
|
chmod 600 .vault_pass
|
||||||
|
```
|
||||||
|
|
||||||
|
**Wichtig:** Verwenden Sie ein sicheres, zuf?lliges Passwort!
|
||||||
|
|
||||||
|
## Verwendung des Vault-Passworts
|
||||||
|
|
||||||
|
### In Ansible Playbooks
|
||||||
|
|
||||||
|
Das Vault-Passwort wird bei der Ausf?hrung von Playbooks ?bergeben:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Beispiel: Production Secrets deployen
|
||||||
|
ansible-playbook playbooks/setup-production-secrets.yml \
|
||||||
|
--vault-password-file secrets/.vault_pass
|
||||||
|
|
||||||
|
# Beispiel: Infrastructure deployen
|
||||||
|
ansible-playbook playbooks/setup-infrastructure.yml \
|
||||||
|
-i inventory/production.yml \
|
||||||
|
--vault-password-file secrets/.vault_pass
|
||||||
|
|
||||||
|
# Beispiel: Application Update deployen
|
||||||
|
ansible-playbook playbooks/deploy-update.yml \
|
||||||
|
-e "image_tag=sha-abc123" \
|
||||||
|
--vault-password-file secrets/.vault_pass
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vault-Dateien verwalten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Vault-Datei entschl?sseln und anzeigen
|
||||||
|
ansible-vault view secrets/production.vault.yml \
|
||||||
|
--vault-password-file secrets/.vault_pass
|
||||||
|
|
||||||
|
# Vault-Datei bearbeiten
|
||||||
|
ansible-vault edit secrets/production.vault.yml \
|
||||||
|
--vault-password-file secrets/.vault_pass
|
||||||
|
|
||||||
|
# Neue Vault-Datei erstellen und verschl?sseln
|
||||||
|
ansible-vault encrypt secrets/production.vault.yml \
|
||||||
|
--vault-password-file secrets/.vault_pass
|
||||||
|
|
||||||
|
# Vault-Datei entschl?sseln (dauerhaft)
|
||||||
|
ansible-vault decrypt secrets/production.vault.yml \
|
||||||
|
--vault-password-file secrets/.vault_pass
|
||||||
|
```
|
||||||
|
|
||||||
|
## CI/CD Integration
|
||||||
|
|
||||||
|
### Gitea Actions
|
||||||
|
|
||||||
|
In Gitea Actions wird das Vault-Passwort als Secret gespeichert:
|
||||||
|
|
||||||
|
- **Secret-Name:** `ANSIBLE_VAULT_PASSWORD`
|
||||||
|
- **Verwendung:** Wird automatisch in Workflows verwendet, die Ansible-Vault ben?tigen
|
||||||
|
|
||||||
|
**Hinzuf?gen des Secrets in Gitea:**
|
||||||
|
1. Gehe zu: Repository Settings ? Secrets
|
||||||
|
2. Erstelle neues Secret: `ANSIBLE_VAULT_PASSWORD`
|
||||||
|
3. Wert: Das Vault-Passwort aus `.vault_pass`
|
||||||
|
|
||||||
|
**Workflow-Beispiel:**
|
||||||
|
```yaml
|
||||||
|
- name: Deploy with Ansible
|
||||||
|
run: |
|
||||||
|
ansible-playbook playbooks/deploy-update.yml \
|
||||||
|
--vault-password-file <(echo "${{ secrets.ANSIBLE_VAULT_PASSWORD }}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Passwort zur?cksetzen/?ndern
|
||||||
|
|
||||||
|
### Passwort ?ndern
|
||||||
|
|
||||||
|
Wenn das Vault-Passwort ge?ndert werden muss:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd deployment/ansible
|
||||||
|
|
||||||
|
# 1. Alte Vault-Datei entschl?sseln (mit altem Passwort)
|
||||||
|
ansible-vault decrypt secrets/production.vault.yml \
|
||||||
|
--vault-password-file secrets/.vault_pass
|
||||||
|
|
||||||
|
# 2. Neues Passwort setzen
|
||||||
|
echo "new-secure-vault-password" > secrets/.vault_pass
|
||||||
|
chmod 600 secrets/.vault_pass
|
||||||
|
|
||||||
|
# 3. Vault-Datei mit neuem Passwort verschl?sseln
|
||||||
|
ansible-vault encrypt secrets/production.vault.yml \
|
||||||
|
--vault-password-file secrets/.vault_pass
|
||||||
|
|
||||||
|
# 4. Passwort im Passwort-Manager aktualisieren
|
||||||
|
# 5. CI/CD Secret in Gitea aktualisieren (ANSIBLE_VAULT_PASSWORD)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Passwort vergessen
|
||||||
|
|
||||||
|
?? **Wenn das Vault-Passwort verloren geht:**
|
||||||
|
- Die verschl?sselte `production.vault.yml` kann nicht mehr entschl?sselt werden
|
||||||
|
- Eine neue Vault-Datei muss erstellt werden
|
||||||
|
- Alle Secrets m?ssen neu konfiguriert werden
|
||||||
|
- **L?sung:** Passwort im Passwort-Manager speichern!
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Problem: "Decryption failed"
|
||||||
|
|
||||||
|
**Fehler:**
|
||||||
|
```
|
||||||
|
ERROR! Decryption failed (no vault secrets were found)
|
||||||
|
```
|
||||||
|
|
||||||
|
**L?sung:**
|
||||||
|
1. Passwort-Datei pr?fen:
|
||||||
|
```bash
|
||||||
|
cat deployment/ansible/secrets/.vault_pass
|
||||||
|
```
|
||||||
|
2. Korrekten Pfad verwenden:
|
||||||
|
```bash
|
||||||
|
--vault-password-file secrets/.vault_pass
|
||||||
|
```
|
||||||
|
3. Berechtigungen pr?fen:
|
||||||
|
```bash
|
||||||
|
ls -la deployment/ansible/secrets/.vault_pass
|
||||||
|
# Sollte: -rw------- (600)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem: "Vault password file not found"
|
||||||
|
|
||||||
|
**Fehler:**
|
||||||
|
```
|
||||||
|
ERROR! the vault password file secrets/.vault_pass was not found
|
||||||
|
```
|
||||||
|
|
||||||
|
**L?sung:**
|
||||||
|
```bash
|
||||||
|
# Pr?fen ob Datei existiert
|
||||||
|
ls -la deployment/ansible/secrets/.vault_pass
|
||||||
|
|
||||||
|
# Falls nicht vorhanden, neu erstellen (siehe "Erstellung des Vault-Passworts")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem: "Permission denied"
|
||||||
|
|
||||||
|
**Fehler:**
|
||||||
|
```
|
||||||
|
Permission denied: secrets/.vault_pass
|
||||||
|
```
|
||||||
|
|
||||||
|
**L?sung:**
|
||||||
|
```bash
|
||||||
|
chmod 600 deployment/ansible/secrets/.vault_pass
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### ? Empfohlene Vorgehensweise
|
||||||
|
|
||||||
|
1. **Passwort-Manager:** Vault-Passwort im Passwort-Manager speichern
|
||||||
|
2. **Sichere Passw?rter:** Verwendung von zuf?lligen, starken Passw?rtern
|
||||||
|
3. **Separate Passw?rter:** Verschiedene Passw?rter f?r dev/staging/prod
|
||||||
|
4. **Regelm??ige Rotation:** Passwort regelm??ig ?ndern (z.B. viertelj?hrlich)
|
||||||
|
5. **Backup:** Passwort an sicherem Ort (Passwort-Manager) sichern
|
||||||
|
6. **Zugriffskontrolle:** Nur autorisierte Personen sollten Zugriff haben
|
||||||
|
|
||||||
|
### ? Zu vermeiden
|
||||||
|
|
||||||
|
- Passwort ins Repository committen (gitignored!)
|
||||||
|
- Passwort in unverschl?sselten Dokumenten speichern
|
||||||
|
- Passwort per Email oder Chat teilen
|
||||||
|
- Einfache/erratbare Passw?rter verwenden
|
||||||
|
- Passwort mehreren Umgebungen teilen
|
||||||
|
|
||||||
|
## Verwandte Dateien
|
||||||
|
|
||||||
|
- **Setup-Script:** [`deployment/ansible/scripts/init-secrets.sh`](../../ansible/scripts/init-secrets.sh)
|
||||||
|
- **Vault-Datei:** `deployment/ansible/secrets/production.vault.yml`
|
||||||
|
- **Vault-Template:** `deployment/ansible/secrets/production.vault.yml.example`
|
||||||
|
- **Gitignore:** `deployment/ansible/secrets/.gitignore`
|
||||||
|
- **Haupt-Dokumentation:** [`deployment/ansible/README.md`](../../ansible/README.md)
|
||||||
|
- **Setup-Guide:** [`deployment/docs/guides/setup-guide.md`](setup-guide.md)
|
||||||
|
|
||||||
|
## Referenzen
|
||||||
|
|
||||||
|
- [Ansible Vault Dokumentation](https://docs.ansible.com/ansible/latest/user_guide/vault.html)
|
||||||
|
- [Ansible Vault Best Practices](https://docs.ansible.com/ansible/latest/user_guide/vault.html#best-practices)
|
||||||
|
|
||||||
|
## Zusammenfassung
|
||||||
|
|
||||||
|
| Aspekt | Details |
|
||||||
|
|--------|---------|
|
||||||
|
| **Erstellt am** | 30. Oktober 2025, 21:42:27 |
|
||||||
|
| **Speicherort** | `deployment/ansible/secrets/.vault_pass` |
|
||||||
|
| **Berechtigungen** | `600` (nur Owner) |
|
||||||
|
| **Gitignored** | ? Ja |
|
||||||
|
| **Setup-Script** | `scripts/init-secrets.sh` |
|
||||||
|
| **CI/CD Secret** | `ANSIBLE_VAULT_PASSWORD` |
|
||||||
|
| **Verwendung** | `--vault-password-file secrets/.vault_pass` |
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
Dieses Dokument erklärt, wie genau das Deployment in den Application Stack abläuft, wenn die CI/CD Pipeline ausgeführt wird.
|
Dieses Dokument erklärt, wie genau das Deployment in den Application Stack abläuft, wenn die CI/CD Pipeline ausgeführt wird.
|
||||||
|
|
||||||
**📖 Verwandte Dokumentation:**
|
**📖 Verwandte Dokumentation:**
|
||||||
- **[Code Changes Workflow](CODE_CHANGE_WORKFLOW.md)** - Wie Codeänderungen gepusht werden
|
- **[Code Changes Workflow](../guides/code-change-workflow.md)** - Wie Codeänderungen gepusht werden
|
||||||
- **[CI/CD Status](CI_CD_STATUS.md)** - Aktueller Status der Pipeline
|
- **[CI/CD Status](../status/ci-cd-status.md)** - Aktueller Status der Pipeline
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
## 📖 Dokumentation
|
## 📖 Dokumentation
|
||||||
|
|
||||||
- **[Code Changes Workflow](CODE_CHANGE_WORKFLOW.md)** - Anleitung: Wie Codeänderungen gepusht und deployed werden
|
- **[Code Changes Workflow](../guides/code-change-workflow.md)** - Anleitung: Wie Codeänderungen gepusht und deployed werden
|
||||||
- **[Application Stack Deployment](APPLICATION_STACK_DEPLOYMENT.md)** - Detaillierte Erklärung des Deployment-Prozesses
|
- **[Application Stack Deployment](../reference/application-stack.md)** - Detaillierte Erklärung des Deployment-Prozesses
|
||||||
|
|
||||||
## ✅ Was bereits vorhanden ist
|
## ✅ Was bereits vorhanden ist
|
||||||
|
|
||||||
@@ -176,6 +176,12 @@ services:
|
|||||||
find /var/www/html.orig -mindepth 1 -maxdepth 1 ! -name "storage" -exec cp -r {} "$$GIT_TARGET_DIR/" \; 2>/dev/null || true
|
find /var/www/html.orig -mindepth 1 -maxdepth 1 ! -name "storage" -exec cp -r {} "$$GIT_TARGET_DIR/" \; 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Fix nginx upstream configuration - sites-enabled/default overrides conf.d/default.conf
|
||||||
|
if [ -f "/etc/nginx/sites-available/default" ]; then
|
||||||
|
echo "🔧 [staging-nginx] Fixing PHP-FPM upstream configuration..."
|
||||||
|
sed -i "s|server 127.0.0.1:9000;|server staging-app:9000;|g" /etc/nginx/sites-available/default || true
|
||||||
|
fi
|
||||||
|
|
||||||
# Start nginx only (no PHP-FPM, no Git clone - staging-app container handles that)
|
# Start nginx only (no PHP-FPM, no Git clone - staging-app container handles that)
|
||||||
echo "🚀 [staging-nginx] Starting nginx..."
|
echo "🚀 [staging-nginx] Starting nginx..."
|
||||||
exec nginx -g "daemon off;"
|
exec nginx -g "daemon off;"
|
||||||
|
|||||||
66
docs/Makefile.md
Normal file
66
docs/Makefile.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# Makefile Quick Reference
|
||||||
|
|
||||||
|
Dieses Dokument fasst die wichtigsten Ziele aus dem Projekt-Makefile zusammen und erklärt, wie du sie anpasst.
|
||||||
|
|
||||||
|
## Grundlagen
|
||||||
|
|
||||||
|
- `make help` listet alle verfügbaren Targets mit Kurzbeschreibung.
|
||||||
|
- Alle Docker-Befehle nutzen standardmäßig `docker compose`; überschreibe das Kommando bei Bedarf mit `DOCKER=...`.
|
||||||
|
- Variablen wie `PHP_SERVICE`, `COMPOSER_BIN`, `NODE_BIN` oder `ARGS` lassen sich beim Aufruf anpassen, z. B. `make phpstan PHP_SERVICE=php-alt`.
|
||||||
|
|
||||||
|
## Container-Steuerung
|
||||||
|
|
||||||
|
| Befehl | Beschreibung |
|
||||||
|
| ------ | ------------ |
|
||||||
|
| `make up` | startet die lokale Docker-Umgebung im Hintergrund |
|
||||||
|
| `make down` | stoppt und entfernt Container, Netzwerke und Volumes |
|
||||||
|
| `make build` | baut die Images neu |
|
||||||
|
| `make restart` | startet den PHP-Container neu (`PHP_SERVICE`) |
|
||||||
|
| `make logs SERVICE=name` | streamt Logs (Standard: alle Container) |
|
||||||
|
| `make ps` | zeigt laufende Container |
|
||||||
|
|
||||||
|
## Composer & Anwendung
|
||||||
|
|
||||||
|
| Befehl | Beschreibung |
|
||||||
|
| ------ | ------------ |
|
||||||
|
| `make composer-install` | führt `composer install` im PHP-Container aus |
|
||||||
|
| `make composer-update` | führt `composer update` aus |
|
||||||
|
| `make autoload` | aktualisiert den Autoloader (`composer dump-autoload -o`) |
|
||||||
|
| `make console CMD="cache:clear"` | ruft `php console.php` mit übergebenem Befehl auf |
|
||||||
|
| `make cache-clear` | ruft intern `console` mit `cache:clear` auf |
|
||||||
|
|
||||||
|
## Tests & Qualitätssicherung
|
||||||
|
|
||||||
|
| Befehl | Beschreibung |
|
||||||
|
| ------ | ------------ |
|
||||||
|
| `make test` | führt alle Pest-Tests im Profil `test` aus; weitere Parameter via `ARGS` |
|
||||||
|
| `make test-unit` / `test-domain` / `test-framework` | scoped Pest-Läufe für einzelne Ordner |
|
||||||
|
| `make test-watch` | Pest im Watch-Modus |
|
||||||
|
| `make test-coverage` / `test-coverage-html` | Coverage-Reports (Text bzw. HTML) |
|
||||||
|
| `make test-filter FILTER=Klasse` | filtert Tests nach Name |
|
||||||
|
| `make phpstan` | PHPStan-Analyse im Container |
|
||||||
|
| `make phpstan-baseline` | erzeugt eine neue Baseline |
|
||||||
|
| `make cs` | php-cs-fixer Dry-Run |
|
||||||
|
| `make cs-fix` | php-cs-fixer mit automatischer Korrektur |
|
||||||
|
| `make security-check` | führt `composer audit` aus |
|
||||||
|
|
||||||
|
## Frontend-Helper
|
||||||
|
|
||||||
|
| Befehl | Beschreibung |
|
||||||
|
| ------ | ------------ |
|
||||||
|
| `make npm-install` | installiert Node-Abhängigkeiten |
|
||||||
|
| `make npm-build` | baut Produktions-Assets via Vite |
|
||||||
|
| `make npm-dev` | startet den Vite-Dev-Server |
|
||||||
|
| `make npm-test` | führt JavaScript-Tests aus |
|
||||||
|
|
||||||
|
## Git & Deployment
|
||||||
|
|
||||||
|
| Befehl | Beschreibung |
|
||||||
|
| ------ | ------------ |
|
||||||
|
| `make push-staging` | pusht den aktuellen HEAD nach `origin/staging` |
|
||||||
|
|
||||||
|
## Tipps
|
||||||
|
|
||||||
|
- `console` und andere Container-Kommandos verwenden `docker exec -it`; wenn die Umgebung keine TTY mag (z. B. CI), `TTY=0 make console CMD="list"` ausführen und das Makefile bei Bedarf erweitern.
|
||||||
|
- Tests laufen im Container `php-test` mit dem Compose-Profil `test`. Vor der Nutzung sicherstellen, dass das Profil gebaut wurde (`make build`).
|
||||||
|
- Zusätzliche Shortcuts lassen sich leicht durch neue Targets ergänzen – einfach mit Beschreibung versehen und in `.PHONY` aufnehmen, damit GNU Make nicht versucht, gleichnamige Dateien zu bauen.
|
||||||
169
scripts/delete-all-workflow-runs.sh
Executable file
169
scripts/delete-all-workflow-runs.sh
Executable file
@@ -0,0 +1,169 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Script to delete all workflow runs from Gitea repository
|
||||||
|
# Usage: ./scripts/delete-all-workflow-runs.sh [GITEA_TOKEN]
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
GITEA_URL="${GITEA_URL:-https://git.michaelschiemer.de}"
|
||||||
|
REPO_OWNER="${REPO_OWNER:-michael}"
|
||||||
|
REPO_NAME="${REPO_NAME:-michaelschiemer}"
|
||||||
|
|
||||||
|
# Try to get token from parameter, env var, CI_TOKEN, or Ansible vault
|
||||||
|
if [ -n "${1:-}" ]; then
|
||||||
|
GITEA_TOKEN="$1"
|
||||||
|
elif [ -n "${GITEA_TOKEN:-}" ]; then
|
||||||
|
# Token already set
|
||||||
|
:
|
||||||
|
elif [ -n "${CI_TOKEN:-}" ]; then
|
||||||
|
GITEA_TOKEN="$CI_TOKEN"
|
||||||
|
else
|
||||||
|
# Try to extract from Ansible vault
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
VAULT_FILE="$PROJECT_ROOT/deployment/ansible/secrets/production.vault.yml"
|
||||||
|
VAULT_PASS="$PROJECT_ROOT/deployment/ansible/.vault_pass"
|
||||||
|
|
||||||
|
if [ -f "$VAULT_FILE" ] && command -v ansible-playbook >/dev/null 2>&1; then
|
||||||
|
echo -e "${BLUE}Trying to extract CI_TOKEN from Ansible vault...${NC}"
|
||||||
|
if [ -f "$VAULT_PASS" ]; then
|
||||||
|
TOKEN=$(cd "$PROJECT_ROOT" && ansible localhost -m debug -a "var=vault_git_token" -e "@deployment/ansible/secrets/production.vault.yml" --vault-password-file "$VAULT_PASS" 2>/dev/null | grep -oP "vault_git_token.*\"\K[^\"]+" | head -1 || echo "")
|
||||||
|
else
|
||||||
|
TOKEN=$(cd "$PROJECT_ROOT" && ansible localhost -m debug -a "var=vault_git_token" -e "@deployment/ansible/secrets/production.vault.yml" --ask-vault-pass <<< "" 2>/dev/null | grep -oP "vault_git_token.*\"\K[^\"]+" | head -1 || echo "")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$TOKEN" ] && [ "$TOKEN" != "null" ] && [ "$TOKEN" != "undefined" ]; then
|
||||||
|
GITEA_TOKEN="$TOKEN"
|
||||||
|
echo -e "${GREEN}? Token extracted from Ansible vault${NC}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${BLUE}=== Gitea Workflow Runs Deletion ===${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if token is provided
|
||||||
|
if [ -z "$GITEA_TOKEN" ]; then
|
||||||
|
echo -e "${YELLOW}?? GITEA_TOKEN nicht gesetzt${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Bitte generiere einen Gitea Access Token:"
|
||||||
|
echo "1. Gehe zu: ${GITEA_URL}/user/settings/applications"
|
||||||
|
echo "2. Klicke 'Generate New Token'"
|
||||||
|
echo "3. Name: z.B. 'delete-workflow-runs'"
|
||||||
|
echo "4. Scopes: 'write:repository' (mindestens)"
|
||||||
|
echo "5. Kopiere den Token"
|
||||||
|
echo ""
|
||||||
|
echo "Dann f?hre aus:"
|
||||||
|
echo " export GITEA_TOKEN='dein-token'"
|
||||||
|
echo " ./scripts/delete-all-workflow-runs.sh"
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Function to get all workflow runs
|
||||||
|
get_workflow_runs() {
|
||||||
|
local page="${1:-1}"
|
||||||
|
local per_page="${2:-100}"
|
||||||
|
|
||||||
|
curl -s \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-H "Accept: application/json" \
|
||||||
|
"${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/actions/runs?page=${page}&limit=${per_page}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to delete a workflow run
|
||||||
|
delete_workflow_run() {
|
||||||
|
local run_id=$1
|
||||||
|
|
||||||
|
local response=$(curl -s -w "\n%{http_code}" \
|
||||||
|
-X DELETE \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
"${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/actions/runs/${run_id}")
|
||||||
|
|
||||||
|
local http_code=$(echo "$response" | tail -n1)
|
||||||
|
local body=$(echo "$response" | sed '$d')
|
||||||
|
|
||||||
|
if [ "$http_code" = "204" ] || [ "$http_code" = "200" ]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}? FAILED (HTTP $http_code)${NC}"
|
||||||
|
echo "Response: $body"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Repository: ${REPO_OWNER}/${REPO_NAME}"
|
||||||
|
echo "Gitea URL: ${GITEA_URL}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Fetch all workflow runs
|
||||||
|
echo -e "${BLUE}Fetching workflow runs...${NC}"
|
||||||
|
all_runs=""
|
||||||
|
page=1
|
||||||
|
total_deleted=0
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
echo -n "Loading page ${page}... "
|
||||||
|
runs_data=$(get_workflow_runs "$page" 100)
|
||||||
|
|
||||||
|
# Check if we got any runs
|
||||||
|
if ! echo "$runs_data" | grep -q "\"workflow_runs\""; then
|
||||||
|
echo "no more runs"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract run IDs using jq if available, otherwise use grep/sed
|
||||||
|
if command -v jq >/dev/null 2>&1; then
|
||||||
|
run_ids=$(echo "$runs_data" | jq -r '.workflow_runs[]?.id // empty' 2>/dev/null || echo "")
|
||||||
|
total_count=$(echo "$runs_data" | jq -r '.total_count // 0' 2>/dev/null || echo "0")
|
||||||
|
else
|
||||||
|
# Fallback: extract IDs with grep/sed
|
||||||
|
run_ids=$(echo "$runs_data" | grep -o '"id":[0-9]*' | grep -o '[0-9]*' || echo "")
|
||||||
|
total_count=$(echo "$runs_data" | grep -o '"total_count":[0-9]*' | grep -o '[0-9]*' | head -1 || echo "0")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$run_ids" ]; then
|
||||||
|
echo "no runs found"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
run_count=$(echo "$run_ids" | wc -l)
|
||||||
|
echo "${run_count} runs found"
|
||||||
|
|
||||||
|
# Delete each run
|
||||||
|
for run_id in $run_ids; do
|
||||||
|
if [ -n "$run_id" ] && [ "$run_id" != "null" ]; then
|
||||||
|
echo -n " Deleting run ${run_id}... "
|
||||||
|
if delete_workflow_run "$run_id"; then
|
||||||
|
echo -e "${GREEN}?${NC}"
|
||||||
|
total_deleted=$((total_deleted + 1))
|
||||||
|
else
|
||||||
|
echo -e "${RED}?${NC}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if there are more pages
|
||||||
|
if command -v jq >/dev/null 2>&1; then
|
||||||
|
has_more=$(echo "$runs_data" | jq -r 'if .workflow_runs | length > 0 then true else false end' 2>/dev/null || echo "false")
|
||||||
|
else
|
||||||
|
has_more=$(echo "$runs_data" | grep -q '"workflow_runs"' && echo "true" || echo "false")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$has_more" != "true" ] || [ "$run_count" -eq 0 ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
page=$((page + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}=== Deletion Complete ===${NC}"
|
||||||
|
echo -e "Total runs deleted: ${total_deleted}"
|
||||||
|
echo ""
|
||||||
11
scripts/extract-ci-token.yml
Normal file
11
scripts/extract-ci-token.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
- hosts: localhost
|
||||||
|
connection: local
|
||||||
|
gather_facts: no
|
||||||
|
vars_files:
|
||||||
|
- deployment/ansible/secrets/production.vault.yml
|
||||||
|
tasks:
|
||||||
|
- name: Extract CI_TOKEN
|
||||||
|
debug:
|
||||||
|
msg: "{{ vault_git_token }}"
|
||||||
|
no_log: false
|
||||||
44
scripts/get-ci-token-from-vault.sh
Executable file
44
scripts/get-ci-token-from-vault.sh
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Script to extract CI_TOKEN (vault_git_token) from Ansible Vault
|
||||||
|
# Usage: ./scripts/get-ci-token-from-vault.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
VAULT_FILE="deployment/ansible/secrets/production.vault.yml"
|
||||||
|
VAULT_PASS_FILE="deployment/ansible/.vault_pass"
|
||||||
|
|
||||||
|
# Check if vault file exists
|
||||||
|
if [ ! -f "$VAULT_FILE" ]; then
|
||||||
|
echo "Error: Vault file not found at $VAULT_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Try to extract token
|
||||||
|
if [ -f "$VAULT_PASS_FILE" ]; then
|
||||||
|
# Use vault password file
|
||||||
|
TOKEN=$(ansible-vault view "$VAULT_FILE" --vault-password-file "$VAULT_PASS_FILE" 2>/dev/null | grep "vault_git_token:" | cut -d'"' -f2 || echo "")
|
||||||
|
elif command -v ansible-playbook >/dev/null 2>&1; then
|
||||||
|
# Try with ansible-playbook
|
||||||
|
TOKEN=$(cd deployment/ansible && ansible-playbook -i localhost, -c local /dev/stdin --vault-password-file .vault_pass 2>/dev/null <<EOF || echo ""
|
||||||
|
---
|
||||||
|
- hosts: localhost
|
||||||
|
gather_facts: no
|
||||||
|
vars_files:
|
||||||
|
- secrets/production.vault.yml
|
||||||
|
tasks:
|
||||||
|
- debug:
|
||||||
|
var: vault_git_token
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
TOKEN=$(echo "$TOKEN" | grep -oP "vault_git_token.*:\s*\K[^\s]+" || echo "")
|
||||||
|
else
|
||||||
|
echo "Error: Cannot extract token. Please provide vault password manually or set GITEA_TOKEN directly."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$TOKEN" ] && [ "$TOKEN" != "null" ] && [ "$TOKEN" != "undefined" ]; then
|
||||||
|
echo "$TOKEN"
|
||||||
|
else
|
||||||
|
echo "Error: Could not extract token from vault"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -27,8 +27,7 @@ final readonly class ConfigValidator
|
|||||||
$issues = [];
|
$issues = [];
|
||||||
|
|
||||||
// APP_ENV validation
|
// APP_ENV validation
|
||||||
/** @var array<int, string> */
|
/*$allowedEnvs = ['development', 'testing', 'production'];
|
||||||
$allowedEnvs = ['development', 'testing', 'production'];
|
|
||||||
$appEnv = $this->env->getString(EnvKey::APP_ENV, 'production');
|
$appEnv = $this->env->getString(EnvKey::APP_ENV, 'production');
|
||||||
if (! in_array($appEnv, $allowedEnvs, true)) {
|
if (! in_array($appEnv, $allowedEnvs, true)) {
|
||||||
$issues[] = [
|
$issues[] = [
|
||||||
@@ -37,7 +36,7 @@ final readonly class ConfigValidator
|
|||||||
'severity' => 'medium',
|
'severity' => 'medium',
|
||||||
'recommendation' => 'Setze APP_ENV auf einen der Werte: development | testing | production',
|
'recommendation' => 'Setze APP_ENV auf einen der Werte: development | testing | production',
|
||||||
];
|
];
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// APP_DEBUG should be boolean-like if present
|
// APP_DEBUG should be boolean-like if present
|
||||||
if ($this->env->has(EnvKey::APP_DEBUG)) {
|
if ($this->env->has(EnvKey::APP_DEBUG)) {
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ use App\Framework\DI\Container;
|
|||||||
use App\Framework\Http\Exceptions\MiddlewareTimeoutException;
|
use App\Framework\Http\Exceptions\MiddlewareTimeoutException;
|
||||||
use App\Framework\Http\Metrics\MiddlewareMetricsCollector;
|
use App\Framework\Http\Metrics\MiddlewareMetricsCollector;
|
||||||
use App\Framework\Logging\DefaultLogger;
|
use App\Framework\Logging\DefaultLogger;
|
||||||
|
use App\Framework\Logging\Logger;
|
||||||
use App\Framework\Logging\ValueObjects\LogContext;
|
use App\Framework\Logging\ValueObjects\LogContext;
|
||||||
|
|
||||||
final readonly class MiddlewareInvoker
|
final readonly class MiddlewareInvoker
|
||||||
{
|
{
|
||||||
private DefaultLogger $logger;
|
private Logger $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default timeout for middleware execution in seconds
|
* Default timeout for middleware execution in seconds
|
||||||
@@ -46,7 +47,7 @@ final readonly class MiddlewareInvoker
|
|||||||
?MiddlewareCircuitBreaker $circuitBreaker = null,
|
?MiddlewareCircuitBreaker $circuitBreaker = null,
|
||||||
?MiddlewareMetricsCollector $metricsCollector = null
|
?MiddlewareMetricsCollector $metricsCollector = null
|
||||||
) {
|
) {
|
||||||
$this->logger = $this->container->get(DefaultLogger::class);
|
$this->logger = $this->container->get(Logger::class);
|
||||||
|
|
||||||
if ($defaultTimeout === null) {
|
if ($defaultTimeout === null) {
|
||||||
try {
|
try {
|
||||||
@@ -80,13 +81,13 @@ final readonly class MiddlewareInvoker
|
|||||||
|
|
||||||
// Middleware-Instanz holen, falls ein Klassenname übergeben wurde
|
// Middleware-Instanz holen, falls ein Klassenname übergeben wurde
|
||||||
if (is_string($middleware)) {
|
if (is_string($middleware)) {
|
||||||
error_log("MiddlewareInvoker: Getting instance for {$middleware}");
|
#error_log("MiddlewareInvoker: Getting instance for {$middleware}");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$middleware = $this->container->get($middleware);
|
$middleware = $this->container->get($middleware);
|
||||||
error_log("MiddlewareInvoker: Successfully got instance for " . get_class($middleware));
|
#error_log("MiddlewareInvoker: Successfully got instance for " . get_class($middleware));
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
error_log("MiddlewareInvoker: FAILED to get instance for {$middleware}: " . $e->getMessage());
|
#error_log("MiddlewareInvoker: FAILED to get instance for {$middleware}: " . $e->getMessage());
|
||||||
|
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
@@ -108,8 +109,8 @@ final readonly class MiddlewareInvoker
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
// Debug-Ausgabe vor der Ausführung
|
// Debug-Ausgabe vor der Ausführung
|
||||||
$this->logger->debug('VOR: Middleware ' . $middlewareName .
|
#$this->logger->debug('VOR: Middleware ' . $middlewareName .
|
||||||
' - hasResponse: ' . ($context->hasResponse() ? 'ja' : 'nein'));
|
# ' - hasResponse: ' . ($context->hasResponse() ? 'ja' : 'nein'));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Start timing the middleware execution
|
// Start timing the middleware execution
|
||||||
@@ -133,7 +134,7 @@ final readonly class MiddlewareInvoker
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log execution time for monitoring
|
// Log execution time for monitoring
|
||||||
$this->logger->debug("Middleware {$middlewareName} executed in {$executionTime} seconds");
|
#$this->logger->debug("Middleware {$middlewareName} executed in {$executionTime} seconds");
|
||||||
|
|
||||||
$response = $resultContext->response;
|
$response = $resultContext->response;
|
||||||
|
|
||||||
@@ -161,8 +162,8 @@ final readonly class MiddlewareInvoker
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Debug-Ausgabe nach der Ausführung
|
// Debug-Ausgabe nach der Ausführung
|
||||||
$this->logger->debug('NACH: Middleware ' . $middlewareName .
|
#$this->logger->debug('NACH: Middleware ' . $middlewareName .
|
||||||
' - hasResponse: ' . ($resultContext->hasResponse() ? 'ja' : 'nein'));
|
# ' - hasResponse: ' . ($resultContext->hasResponse() ? 'ja' : 'nein'));
|
||||||
|
|
||||||
return $resultContext;
|
return $resultContext;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace App\Framework\Logging;
|
namespace App\Framework\Logging;
|
||||||
|
|
||||||
use App\Framework\Config\Environment;
|
use App\Framework\Config\Environment;
|
||||||
|
use App\Framework\Config\EnvKey;
|
||||||
use App\Framework\Config\TypedConfiguration;
|
use App\Framework\Config\TypedConfiguration;
|
||||||
use App\Framework\Core\PathProvider;
|
use App\Framework\Core\PathProvider;
|
||||||
use App\Framework\DI\Container;
|
use App\Framework\DI\Container;
|
||||||
@@ -69,7 +70,7 @@ final readonly class LoggerInitializer
|
|||||||
// Stelle sicher, dass alle Logverzeichnisse existieren
|
// Stelle sicher, dass alle Logverzeichnisse existieren
|
||||||
$logConfig->ensureLogDirectoriesExist();
|
$logConfig->ensureLogDirectoriesExist();
|
||||||
|
|
||||||
$redisConfig = new RedisConfig(host: 'redis', database: 2);
|
$redisConfig = new RedisConfig(host: $env->getString(EnvKey::REDIS_HOST, 'redis'), database: 2);
|
||||||
$redisConnection = new RedisConnection($redisConfig, 'queue');
|
$redisConnection = new RedisConnection($redisConfig, 'queue');
|
||||||
$queue = new RedisQueue($redisConnection, 'commands');
|
$queue = new RedisQueue($redisConnection, 'commands');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user