Zum Inhalt springen

CI/CD Pipeline aufsetzen

Felix Lenhard 14 min
Zurück zum Blog

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 Server
  • SERVER_HOST: Die IP-Adresse oder Domain deines Servers
  • SERVER_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_URL zeigt auf Staging-Datenbank
  • Production: DATABASE_URL zeigt 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 paths Filter, 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

ToolVorteileKosten
GitLab CIIntegriert in GitLab, gute Docker-UnterstützungFree Tier: 400 Min/Monat
CircleCISchnell, gutes CachingFree Tier: 6000 Min/Monat
BuildkiteSelf-hosted Runners möglichFree für kleine Teams
Woodpecker CIOpen Source, selbst gehostetKostenlos

Für die meisten Startups ist GitHub Actions die beste Wahl -- weil du wahrscheinlich schon auf GitHub bist.


Best Practices

  1. Pipeline als Code: Deine CI/CD-Konfiguration gehört ins Repository, nicht in eine Web-Oberfläche
  2. Schnelle Feedback-Loops: Die Pipeline sollte in unter 10 Minuten durchlaufen
  3. Fail Fast: Setze die schnellsten Checks (Lint, Format) an den Anfang
  4. Trunk-Based Development: Halte Feature-Branches kurz (maximal 1-2 Tage)
  5. Keine Ausnahmen: Jeder Code durchläuft die Pipeline -- keine Abkürzungen
  6. Rollback-Fähigkeit: Behalte alte Versionen (Docker Tags, Build Artifacts) für Rollbacks
  7. 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.

Jetzt Beratung anfragen

Weiterführende Artikel


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.

Erstgespräch vereinbaren

Du überlegst zu gründen oder bist schon mittendrin? Schreib uns ein formloses E-Mail -- wir melden uns innerhalb weniger Tage.

E-Mail schreiben