- Add QUICKSTART.md and SETUP_REPOSITORY.md for Semaphore stack - Add playbooks directory for Semaphore deployment - Update Semaphore docker-compose.yml, env.example, and README - Add Traefik local configuration files - Disable semaphore.yml in Traefik dynamic config - Update docker-compose.local.yml and build-image workflow
577 lines
14 KiB
Markdown
577 lines
14 KiB
Markdown
# 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=<starkes-passwort>
|
|
MYSQL_PASSWORD=<starkes-passwort>
|
|
MYSQL_ROOT_PASSWORD=<starkes-passwort>
|
|
```
|
|
2. **Encryption Key**: Generiere einen sicheren Key:
|
|
```bash
|
|
head -c32 /dev/urandom | base64
|
|
```
|
|
Setze in `.env`: `SEMAPHORE_ACCESS_KEY_ENCRYPTION=<generierter-key>`
|
|
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
|
|
|