# Semaphore CI Stack - Lokale Entwicklung ## Übersicht Selbst-gehostete Semaphore CI/CD-Plattform für lokale Entwicklung, die es ermöglicht, CI/CD-Pipelines und Ansible-Playbooks lokal zu testen und auszuführen, ohne Abhängigkeit von externen CI-Services. **Features**: - **Selbst-gehostet**: Läuft vollständig lokal auf dem Entwicklungsrechner - **Lokal isoliert**: NUR über localhost (127.0.0.1) erreichbar - KEIN externer Zugriff aus Sicherheitsgründen! - **MySQL-Backend**: Persistente Datenbank für Projekte, Tasks und Templates - **Web-UI**: Intuitive Benutzeroberfläche für Pipeline-Management (nur lokal) - **Ansible-Integration**: Native Unterstützung für Ansible-Playbooks - **Docker-basiert**: Einfaches Setup und Wartung **Einsatzzweck**: - Lokales Testen von CI/CD-Pipelines - Entwicklung und Test von Ansible-Playbooks - Experimentieren mit Deployment-Workflows - Keine Abhängigkeit von externen CI-Services ## Services - **mysql** - MySQL 8.0 Datenbank für Semaphore-Daten - **semaphore** - Semaphore CI/CD Web-UI und API ## Voraussetzungen - Docker und Docker Compose installiert - Port 9300 auf localhost frei verfügbar (3000 wird von Gitea verwendet) - Ausreichend Speicherplatz für Docker Volumes (~500MB initial) ## Verzeichnisstruktur ``` semaphore/ ├── docker-compose.yml # Service-Definitionen ├── env.example # Environment-Variablen Template ├── .env # Environment-Konfiguration (aus env.example erstellen) └── README.md # Diese Datei ``` ## Quick Start ### 1. Environment-Datei erstellen ```bash cd deployment/stacks/semaphore cp env.example .env ``` ### 2. Konfiguration anpassen (Optional) Bearbeite `.env` und passe die Werte an: ```bash nano .env ``` **Wichtig**: Generiere einen sicheren Encryption Key: ```bash # Linux/WSL head -c32 /dev/urandom | base64 # Windows PowerShell -join ((48..57) + (65..90) + (97..122) | Get-Random -Count 32 | % {[char]$_}) | ConvertTo-Base64 ``` Aktualisiere `SEMAPHORE_ACCESS_KEY_ENCRYPTION` in der `.env`-Datei. ### 3. Stack starten ```bash docker compose up -d ``` ### 4. Semaphore Web-UI öffnen Öffne im Browser: **http://localhost:9300** ⚠️ **WICHTIG**: Semaphore ist NUR lokal zugänglich (127.0.0.1). Es gibt KEINEN externen Zugriff aus Sicherheitsgründen. **Standard-Login**: - **Username**: `admin` (oder Wert aus `SEMAPHORE_ADMIN`) - **Password**: `admin` (oder Wert aus `SEMAPHORE_ADMIN_PASSWORD`) ### 5. Erste Schritte in Semaphore 1. **Projekt erstellen**: Klicke auf "New Project" und erstelle ein neues Projekt 2. **Inventory anlegen**: Erstelle ein Inventory mit lokalen Hosts oder Docker-Containern 3. **Template erstellen**: Erstelle ein Template mit einem Ansible-Playbook 4. **Task ausführen**: Starte einen Task und beobachte die Ausführung ## Konfiguration ### Environment-Variablen (.env) #### MySQL-Datenbank ```env MYSQL_ROOT_PASSWORD=semaphore_root MYSQL_DATABASE=semaphore MYSQL_USER=semaphore MYSQL_PASSWORD=semaphore ``` #### Semaphore-Konfiguration ```env # Port-Binding (Standard: 9300) SEMAPHORE_PORT=9300 # Admin-Benutzer SEMAPHORE_ADMIN=admin SEMAPHORE_ADMIN_NAME=Administrator SEMAPHORE_ADMIN_EMAIL=admin@localhost SEMAPHORE_ADMIN_PASSWORD=admin # Playbook-Pfad (im Container) SEMAPHORE_PLAYBOOK_PATH=/tmp/semaphore # Encryption Key (WICHTIG: Für Produktion ändern!) SEMAPHORE_ACCESS_KEY_ENCRYPTION=change-me-in-production ``` #### Optionale Konfiguration **LDAP-Integration** (Standard: deaktiviert): ```env SEMAPHORE_LDAP_ENABLED=true SEMAPHORE_LDAP_HOST=ldap.example.com SEMAPHORE_LDAP_PORT=389 SEMAPHORE_LDAP_DN=cn=admin,dc=example,dc=com SEMAPHORE_LDAP_PASSWORD=ldap_password SEMAPHORE_LDAP_BASE_DN=dc=example,dc=com SEMAPHORE_LDAP_USER_FILTER=(uid=%s) ``` **Webhook-Integration**: ```env SEMAPHORE_WEBHOOK_URL=http://localhost:8080/webhook ``` ## Verwendung ### Stack starten ```bash # Services im Hintergrund starten docker compose up -d # Logs anzeigen docker compose logs -f # Nur Semaphore-Logs docker compose logs -f semaphore # Nur MySQL-Logs docker compose logs -f mysql ``` ### Stack stoppen ```bash docker compose down ``` ### Stack neu starten ```bash docker compose restart ``` ### Status prüfen ```bash # Container-Status anzeigen docker compose ps # Health-Check-Status docker compose ps --format "table {{.Name}}\t{{.Status}}" # Semaphore-Health-Check manuell docker compose exec semaphore wget --no-verbose --spider http://localhost:3000/api/health ``` ### Datenbank-Backup ```bash # MySQL-Dump erstellen docker compose exec mysql mysqldump -u semaphore -psemaphore semaphore > semaphore-backup-$(date +%Y%m%d).sql # Backup wiederherstellen docker compose exec -T mysql mysql -u semaphore -psemaphore semaphore < semaphore-backup-YYYYMMDD.sql ``` ### Daten löschen und neu starten ```bash # ⚠️ WARNUNG: Löscht alle Daten! docker compose down -v docker compose up -d ``` ## Erste Schritte mit Semaphore ### 1. Projekt erstellen 1. Öffne http://localhost:9300 im Browser 2. Melde dich mit Admin-Credentials an 3. Klicke auf "New Project" 4. Gib einen Projektnamen ein (z.B. "My Project") 5. Klicke auf "Create" ### 2. Inventory anlegen Ein Inventory definiert die Hosts, auf denen Playbooks ausgeführt werden sollen. **Option A: Lokaler Host** 1. Gehe zu Projekt → Inventories → New Inventory 2. Name: "Local Hosts" 3. Hinzufügen von Host: - Name: `localhost` - Address: `127.0.0.1` - SSH Username: `your-username` - SSH Key: Füge deinen privaten SSH-Key hinzu **Option B: Docker-Container** 1. Erstelle ein Inventory mit Docker-Hosts 2. Für Docker-in-Docker Support benötigst du zusätzliche Konfiguration ### 3. Template erstellen Templates definieren welche Playbooks ausgeführt werden sollen. 1. Gehe zu Projekt → Templates → New Template 2. Template-Name: "Hello World" 3. Inventory: Wähle dein Inventory 4. Playbook: Erstelle ein einfaches Playbook: ```yaml --- - hosts: all gather_facts: no tasks: - name: Print hello world debug: msg: "Hello from Semaphore CI!" ``` 5. Speichere das Template ### 4. Task ausführen 1. Gehe zu Templates 2. Klicke auf dein Template 3. Klicke auf "Run" 4. Beobachte die Ausführung in Echtzeit ## Integration mit bestehenden Stacks ### Verwendung mit lokaler Docker-Registry Semaphore kann Docker-Images aus der lokalen Registry verwenden: **In Ansible-Playbooks**: ```yaml - name: Pull image from local registry docker_image: name: registry.michaelschiemer.de/framework:latest source: pull register: image_result ``` **Voraussetzung**: Der Semaphore-Container muss Zugriff auf den Docker-Socket oder die Registry haben. ### Verwendung mit bestehenden Ansible-Playbooks 1. Mounte deine Playbooks als Volume: ```yaml volumes: - /path/to/your/playbooks:/tmp/semaphore/playbooks:ro ``` 2. Oder kopiere Playbooks in den Container: ```bash docker compose exec semaphore mkdir -p /tmp/semaphore/my-playbook docker cp my-playbook.yml semaphore:/tmp/semaphore/my-playbook/playbook.yml ``` 3. Verweise im Template auf den Playbook-Pfad ## Troubleshooting ### Port-Konflikt (Port 3000 vs 9300) **Problem**: Port 3000 ist standardmäßig von Gitea belegt, daher verwendet Semaphore Port 9300. **Lösung**: Wenn du einen anderen Port verwenden möchtest, setze `SEMAPHORE_PORT` in der `.env` Datei: ```env SEMAPHORE_PORT=8080 # Oder ein anderer freier Port ``` **Wichtig**: Der interne Container-Port bleibt immer 3000 - nur der externe Host-Port ändert sich. ### Semaphore startet nicht **Prüfe Logs**: ```bash docker compose logs semaphore ``` **Häufige Ursachen**: - MySQL ist noch nicht bereit (warte auf Health-Check) - Port 9300 ist bereits belegt: `netstat -tuln | grep 9300` (oder auf Windows: `netstat -ano | findstr :9300`) - Falsche Datenbank-Credentials **Lösung**: ```bash # Prüfe MySQL-Status docker compose ps mysql # Prüfe Semaphore-Logs für DB-Verbindungsfehler docker compose logs semaphore | grep -i database # Restart wenn nötig docker compose restart semaphore ``` ### MySQL startet nicht **Prüfe MySQL-Logs**: ```bash docker compose logs mysql ``` **Häufige Ursachen**: - Volume-Permissions-Probleme - Port-Konflikte (unwahrscheinlich, da kein Port-Mapping) **Lösung**: ```bash # Prüfe Volume docker volume inspect semaphore-mysql-data # Cleanup und Neu-Start (⚠️ Datenverlust!) docker compose down -v docker compose up -d ``` ### Login funktioniert nicht **Standard-Credentials**: - Username: `admin` (oder `SEMAPHORE_ADMIN` Wert) - Password: `admin` (oder `SEMAPHORE_ADMIN_PASSWORD` Wert) **Admin-Passwort zurücksetzen**: 1. Stoppe Semaphore: `docker compose stop semaphore` 2. Setze `SEMAPHORE_ADMIN_PASSWORD` in `.env` auf neues Passwort 3. Starte Semaphore: `docker compose up -d` ### Playbooks werden nicht gefunden **Prüfe Playbook-Pfad**: ```bash docker compose exec semaphore ls -la /tmp/semaphore ``` **Lösung**: - Stelle sicher, dass `SEMAPHORE_PLAYBOOK_PATH` korrekt gesetzt ist - Prüfe, ob Playbooks im richtigen Pfad liegen - Stelle sicher, dass Datei-Berechtigungen korrekt sind ### Health-Check schlägt fehl **Prüfe Health-Check**: ```bash docker compose exec semaphore wget --no-verbose --spider http://localhost:3000/api/health ``` **Lösung**: - Warte auf vollständigen Start (kann 1-2 Minuten dauern) - Prüfe Logs: `docker compose logs semaphore` - Restart wenn nötig: `docker compose restart semaphore` ## Sicherheit ### 🔒 Lokaler Zugriff (Nur localhost) Semaphore ist absichtlich NUR lokal zugänglich aus Sicherheitsgründen: - ✅ **Nur localhost-Zugriff**: Port 9300 gebunden an 127.0.0.1 (nicht 0.0.0.0) - ✅ **Keine externen Netzwerke**: Kein externer Zugriff möglich - ✅ **Keine Traefik-Integration**: Keine öffentliche Route konfiguriert - ✅ **Isoliertes Netzwerk**: Nur internes Docker-Netzwerk - ⚠️ **Standard-Passwörter**: Nur für lokale Entwicklung - ändern bei Bedarf ### ⚠️ KEINE Produktions-Nutzung über Internet! **Semaphore sollte NICHT öffentlich zugänglich gemacht werden!** Gründe: 1. **Sicherheitsrisiko**: Semaphore hat Zugriff auf SSH-Keys und Deployment-Credentials 2. **Privilegierter Zugriff**: Kann auf Produktions-Server zugreifen 3. **Keine Multi-Factor-Authentication**: Standardmäßig keine 2FA 4. **Exploits**: Selbst-gehostete Software kann Sicherheitslücken haben ### Für lokale Entwicklung (Empfohlen) Wenn du Semaphore lokal nutzen willst: 1. **Starke Passwörter**: Ändere alle Passwörter in `.env`: ```env SEMAPHORE_ADMIN_PASSWORD= MYSQL_PASSWORD= MYSQL_ROOT_PASSWORD= ``` 2. **Encryption Key**: Generiere einen sicheren Key: ```bash head -c32 /dev/urandom | base64 ``` Setze in `.env`: `SEMAPHORE_ACCESS_KEY_ENCRYPTION=` 3. **SSH-Keys**: Stelle sicher, dass SSH-Keys sicher gespeichert sind 4. **Backup-Strategie**: Regelmäßige MySQL-Backups einrichten 5. **Resource Limits**: Füge Memory/CPU-Limits hinzu (optional) ## Wartung ### Regelmäßige Aufgaben **Wöchentlich**: - Logs auf Fehler prüfen: `docker compose logs --tail=100` - Disk-Space prüfen: `docker system df` - Backup erstellen (wenn wichtige Daten vorhanden) **Monatlich**: - Images aktualisieren: `docker compose pull && docker compose up -d` - Alte Tasks in Semaphore aufräumen (über Web-UI) ### Updates ```bash # Aktuelle Images herunterladen docker compose pull # Mit neuen Images neu starten docker compose up -d # Logs prüfen docker compose logs -f ``` ### Daten bereinigen ```bash # Alte Docker-Images löschen docker image prune -a # Alte Volumes prüfen docker volume ls # ⚠️ Vorsicht: Löscht alle Semaphore-Daten! docker compose down -v ``` ## Backup und Wiederherstellung ### Backup erstellen ```bash # MySQL-Dump docker compose exec mysql mysqldump \ -u semaphore -psemaphore semaphore \ > semaphore-backup-$(date +%Y%m%d-%H%M%S).sql # Volume-Backup (komplett) docker run --rm \ -v semaphore-mysql-data:/data \ -v $(pwd):/backup \ alpine tar czf /backup/semaphore-mysql-backup-$(date +%Y%m%d).tar.gz /data ``` ### Wiederherstellung ```bash # MySQL-Dump wiederherstellen docker compose exec -T mysql mysql \ -u semaphore -psemaphore semaphore \ < semaphore-backup-YYYYMMDD.sql # Volume wiederherstellen (⚠️ stoppt Container) docker compose down docker run --rm \ -v semaphore-mysql-data:/data \ -v $(pwd):/backup \ alpine sh -c "cd /data && tar xzf /backup/semaphore-mysql-backup-YYYYMMDD.tar.gz" docker compose up -d ``` ## Performance-Optimierung ### MySQL-Optimierung Für bessere Performance kannst du MySQL-Konfiguration anpassen: 1. Erstelle `mysql/conf.d/my.cnf`: ```ini [mysqld] innodb_buffer_pool_size = 256M max_connections = 100 ``` 2. Mounte in `docker-compose.yml`: ```yaml volumes: - ./mysql/conf.d:/etc/mysql/conf.d:ro ``` ### Resource Limits Füge Limits in `docker-compose.yml` hinzu: ```yaml deploy: resources: limits: memory: 1G cpus: '0.5' ``` ## Unterstützung ### Dokumentation - **Semaphore CI Docs**: https://docs.semaphoreui.com/ - **Semaphore GitHub**: https://github.com/semaphoreui/semaphore ### Logs ```bash # Alle Logs docker compose logs -f # Semaphore-Logs docker compose logs -f semaphore # MySQL-Logs docker compose logs -f mysql # Letzte 100 Zeilen docker compose logs --tail=100 ``` ### Health-Checks ```bash # Container-Status docker compose ps # Semaphore-Health curl http://localhost:9300/api/health # MySQL-Health docker compose exec mysql mysqladmin ping -h localhost -u root -psemaphore_root ``` --- **Setup-Status**: ✅ Bereit für lokale Entwicklung **Nächste Schritte**: 1. `cp env.example .env` ausführen 2. `docker compose up -d` starten 3. http://localhost:9300 öffnen 4. Mit Admin-Credentials anmelden 5. Erstes Projekt und Template erstellen