CI/CD Pipeline aufsetzen
Du hast gerade ein Feature fertig programmiert. Jetzt musst du es deployen. Also verbindest du dich per SSH mit dem Server, ziehst den neuesten Code, installierst Dependencies, baust die Anwendung, startest den Server neu -- und hoffst, dass alles funktioniert. Das dauert 30 Minuten, und du machst es dreimal die Woche.
Oder: Du pushst deinen Code auf GitHub, und drei Minuten später ist alles automatisch getestet und deployed. Willkommen in der Welt von CI/CD.
Was ist CI/CD?
Continuous Integration (CI)
Continuous Integration bedeutet, dass Code regelmässig in ein gemeinsames Repository zusammengeführt wird -- und dabei automatisch Tests laufen. Das Ziel: Fehler früh erkennen, bevor sie in Produktion landen.
Continuous Delivery (CD)
Continuous Delivery geht einen Schritt weiter: Nach erfolgreichen Tests wird der Code automatisch für das Deployment vorbereitet. Der letzte Schritt -- das tatsächliche Deployment in Produktion -- kann automatisch oder manuell erfolgen.
Continuous Deployment
Continuous Deployment ist die Königsdisziplin: Jeder Commit, der die Tests besteht, wird automatisch in Produktion deployed. Kein manueller Eingriff nötig.
Continuous Integration: Code -> Tests -> Feedback
Continuous Delivery: Code -> Tests -> Build -> Ready to Deploy
Continuous Deployment: Code -> Tests -> Build -> Automatisch in Produktion
Warum du eine CI/CD Pipeline brauchst
Zeit sparen
Ein manuelles Deployment dauert 15-30 Minuten. Eine automatisierte Pipeline: 3-5 Minuten. Bei drei Deployments pro Woche sparst du über eine Stunde -- jede Woche.
Fehler vermeiden
Menschen machen Fehler. Besonders um 22 Uhr, wenn der Kunde auf ein Feature wartet. Eine Pipeline macht immer dasselbe, immer in der gleichen Reihenfolge, immer zuverlässig.
Qualität sichern
Automatisierte Tests stellen sicher, dass neuer Code keine bestehenden Features kaputt macht. Kein "Ich teste das schnell auf meinem Laptop" mehr.
Vertrauen aufbauen
Wenn du weisst, dass jeder Commit automatisch getestet wird, traust du dich, öfter zu deployen. Und öftere Deployments bedeuten schnelleres Feedback und schnellere Iteration.
GitHub Actions -- Deine erste Pipeline
GitHub Actions ist die einfachste Möglichkeit, eine CI/CD Pipeline aufzusetzen. Es ist direkt in GitHub integriert, kostenlos für Open-Source-Projekte und bietet 2000 Minuten pro Monat für private Repositories.
Schritt 1: Workflow-Datei erstellen
Erstelle die Datei .github/workflows/ci.yml in deinem Repository:
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
NODE_VERSION: '20'
jobs:
# Job 1: Lint und Formatierung pruefen
lint:
name: Lint & Format Check
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install Dependencies
run: npm ci
- name: Run Linter
run: npm run lint
- name: Check Formatting
run: npm run format:check
# Job 2: Tests ausfuehren
test:
name: Run Tests
runs-on: ubuntu-latest
needs: lint
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install Dependencies
run: npm ci
- name: Run Unit Tests
run: npm test -- --coverage
- name: Upload Coverage Report
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/
# Job 3: Build erstellen
build:
name: Build Application
runs-on: ubuntu-latest
needs: test
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install Dependencies
run: npm ci
- name: Build
run: npm run build
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: build
path: dist/
# Job 4: Deployment (nur auf main)
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- name: Download Build Artifacts
uses: actions/download-artifact@v4
with:
name: build
path: dist/
- name: Deploy to Server
env:
SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
SERVER_HOST: ${{ secrets.SERVER_HOST }}
SERVER_USER: ${{ secrets.SERVER_USER }}
run: |
mkdir -p ~/.ssh
echo "$SSH_KEY" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
rsync -avz -e "ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no" \
dist/ $SERVER_USER@$SERVER_HOST:/var/www/app/
Schritt 2: Secrets konfigurieren
Gehe in deinem GitHub-Repository zu Settings > Secrets and variables > Actions und füge hinzu:
DEPLOY_SSH_KEY: Dein SSH Private Key für den ServerSERVER_HOST: Die IP-Adresse oder Domain deines ServersSERVER_USER: Der SSH-Benutzername
Wichtig: Speichere niemals Secrets im Code! GitHub Secrets werden verschlüsselt gespeichert und sind in Logs nicht sichtbar.
Schritt 3: Pipeline testen
Committe die Workflow-Datei und pushe sie:
git add .github/workflows/ci.yml
git commit -m "CI/CD Pipeline hinzufuegen"
git push origin main
Gehe auf GitHub zu Actions -- du solltest sehen, wie deine Pipeline läuft.
Pipeline für verschiedene Technologien
Python (Django/Flask)
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: testpassword
POSTGRES_DB: testdb
ports:
- 5432:5432
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install Dependencies
run: |
pip install -r requirements.txt
pip install pytest pytest-cov
- name: Run Tests
env:
DATABASE_URL: postgresql://postgres:testpassword@localhost:5432/testdb
run: pytest --cov=app tests/
Docker-basiertes Deployment
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and Push Docker Image
uses: docker/build-push-action@v5
with:
push: true
tags: |
ghcr.io/${{ github.repository }}:latest
ghcr.io/${{ github.repository }}:${{ github.sha }}
deploy:
needs: build-and-push
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to Server
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
docker pull ghcr.io/${{ github.repository }}:latest
docker compose up -d --force-recreate
Erweiterte Pipeline-Features
Matrix Builds
Teste auf mehreren Node.js-Versionen gleichzeitig:
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
Caching für schnellere Builds
- name: Cache node_modules
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
Staging und Production Environments
deploy-staging:
if: github.ref == 'refs/heads/develop'
environment: staging
# ... Deploy zu Staging
deploy-production:
if: github.ref == 'refs/heads/main'
environment: production
# ... Deploy zu Produktion
Manuelle Approvals
Für Production-Deployments kannst du in GitHub ein Environment mit Required Reviewers konfigurieren. So muss jemand das Deployment manuell bestätigen, bevor es losgeht.
Typische Pipeline-Stages für ein Startup
Hier ist eine vollständige Pipeline, wie sie für ein typisches österreichisches Startup aussehen könnte:
1. Lint & Format Check (30 Sekunden)
2. Unit Tests (1-2 Minuten)
3. Integration Tests (2-3 Minuten)
4. Build (1-2 Minuten)
5. Security Scan (1 Minute)
6. Deploy to Staging (1-2 Minuten)
7. Smoke Tests on Staging (30 Sekunden)
8. Deploy to Production (1-2 Minuten)
---
Gesamtdauer: 8-13 Minuten
Am Anfang brauchst du nicht alle Stages. Starte mit Lint, Tests und Build. Den Rest kannst du später hinzufügen.
Secrets und Umgebungsvariablen richtig verwalten
GitHub Secrets
Für einfache Projekte reichen GitHub Secrets:
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
API_KEY: ${{ secrets.API_KEY }}
Environment-spezifische Secrets
GitHub Environments erlauben unterschiedliche Secrets für Staging und Production:
- Staging:
DATABASE_URLzeigt auf Staging-Datenbank - Production:
DATABASE_URLzeigt auf Production-Datenbank
Für komplexere Setups
Wenn du viele Secrets hast, schau dir Doppler oder HashiCorp Vault an. Beide haben kostenlose Tiers für kleine Teams.
Häufige Probleme und Lösungen
Problem: Tests schlagen nur in der Pipeline fehl
Ursache: Unterschiede zwischen deiner lokalen Umgebung und der CI-Umgebung (Betriebssystem, Versionen, Umgebungsvariablen).
Lösung: Nutze Docker für deine lokale Entwicklung. So ist die Umgebung identisch.
Problem: Pipeline ist zu langsam
Ursache: Keine Caches, zu viele sequenzielle Steps, grosse Docker Images.
Lösung:
- Nutze Caching (npm, Docker Layer Cache)
- Führe unabhängige Jobs parallel aus
- Nutze kleinere Base Images (Alpine statt Ubuntu)
Problem: Deployment schlägt fehl
Ursache: Oft SSH-Verbindungsprobleme oder falsche Secrets.
Lösung:
- Teste die SSH-Verbindung manuell
- Überprüfe die Secrets in GitHub (sie werden nach dem Speichern nicht mehr angezeigt)
- Füge Debug-Output hinzu:
run: ssh -v ...
Problem: Kosten übersteigen das Free Tier
Ursache: Zu viele Builds, zu lange Build-Zeiten.
Lösung:
- Nutze
pathsFilter, um nur bei relevanten Änderungen zu bauen - Cancle vorherige Runs bei neuen Pushes:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
Alternativen zu GitHub Actions
| Tool | Vorteile | Kosten |
|---|---|---|
| GitLab CI | Integriert in GitLab, gute Docker-Unterstützung | Free Tier: 400 Min/Monat |
| CircleCI | Schnell, gutes Caching | Free Tier: 6000 Min/Monat |
| Buildkite | Self-hosted Runners möglich | Free für kleine Teams |
| Woodpecker CI | Open Source, selbst gehostet | Kostenlos |
Für die meisten Startups ist GitHub Actions die beste Wahl -- weil du wahrscheinlich schon auf GitHub bist.
Best Practices
- Pipeline als Code: Deine CI/CD-Konfiguration gehört ins Repository, nicht in eine Web-Oberfläche
- Schnelle Feedback-Loops: Die Pipeline sollte in unter 10 Minuten durchlaufen
- Fail Fast: Setze die schnellsten Checks (Lint, Format) an den Anfang
- Trunk-Based Development: Halte Feature-Branches kurz (maximal 1-2 Tage)
- Keine Ausnahmen: Jeder Code durchläuft die Pipeline -- keine Abkürzungen
- Rollback-Fähigkeit: Behalte alte Versionen (Docker Tags, Build Artifacts) für Rollbacks
- Notifications: Richte Benachrichtigungen ein (Slack, E-Mail), wenn die Pipeline fehlschlägt
Fazit
Eine CI/CD Pipeline ist eine der besten Investitionen, die du als Startup-Gründer machen kannst. Sie spart dir Zeit, reduziert Fehler und gibt dir das Vertrauen, jederzeit deployen zu können.
Du brauchst dafür kein grosses Budget und kein DevOps-Team. Mit GitHub Actions und den Beispielen aus diesem Beitrag kannst du heute noch deine erste Pipeline aufsetzen. Starte einfach: Lint, Tests, Build. Den Rest baust du Stück für Stück aus.
Denk dran: Eine Pipeline, die 80 Prozent automatisiert, ist unendlich besser als keine Pipeline.
Startup Burgenland unterstützt dich
Du brauchst Hilfe beim Aufsetzen deiner CI/CD Pipeline? Bei Startup Burgenland stehen dir technische Mentoren zur Seite, die dir helfen, die richtige Pipeline für dein Projekt aufzubauen -- von der ersten Konfiguration bis zum automatisierten Production Deployment.
Weiterführende Artikel
- DevOps Grundlagen für Gründer
- Docker und Container für Einsteiger
- Cloud-Hosting für Startups -- AWS Azure oder Hetzner
- API-Design und Dokumentation
- Serverless Architecture für Startups
Dieser Beitrag ist Teil der Serie "Cloud und Infrastruktur" im Startup Burgenland Blog. In dieser Serie behandeln wir alle technischen Themen rund um Hosting, Deployment und Skalierung -- speziell für österreichische Startups und Gründer.
Über den Autor: Felix Lenhard ist Program Director und Startup Coach bei Startup Burgenland. Zuvor Managing Director beim 360 Innovation Lab, Innovation Manager bei RHI Magnesita und Serial Entrepreneur mit internationalen Exits. Über 15 Jahre Erfahrung in Innovation und Unternehmensaufbau.