CI/CD ist das Automatisierungsrückgrat der modernen Softwarelieferung: die Praktiken und Werkzeuge, die eine Codeänderung schnell, wiederholbar und mit einem Nachweis der Unbedenklichkeit an jedem Schritt vom Branch eines Entwicklers in die Produktion bringen. Dieser Leitfaden erklärt, was die Begriffe tatsächlich bedeuten, wie eine Pipeline in der Praxis aussieht und wie man sie auf GitHub Actions aufbaut — einschließlich eines vollständigen, funktionierenden Deployments nach AWS Lambda, das gänzlich ohne langlebige Cloud-Credentials auskommt.

Was CI/CD tatsächlich bedeutet

Continuous Integration (CI) ist die Praxis, Codeänderungen häufig — idealerweise täglich — in eine gemeinsame Mainline zu mergen und jeden Merge mit einem automatisierten Build und einer Testsuite zu validieren. Ziel ist es, Integrationsprobleme innerhalb von Minuten nach der verursachenden Änderung sichtbar zu machen, solange der Diff klein ist und der Autor noch den Kontext hat.

Das "CD" lässt sich auf zwei Arten auflösen, und der Unterschied ist wichtig. Continuous Delivery bedeutet: Jede Änderung, die die Pipeline besteht, erzeugt ein deploybares Artefakt, und die Freigabe in die Produktion ist eine bewusste Entscheidung — typischerweise eine manuelle Freigabe oder ein geplanter Release. Continuous Deployment geht einen Schritt weiter: Jede bestandene Änderung geht automatisch in Produktion, ohne menschliches Gate. Die meisten Teams praktizieren Continuous Delivery; Continuous Deployment ist der richtige Zielzustand für Services mit starker Testabdeckung und reifem Betrieb. Beachten Sie: Jede Änderung zu deployen macht Releases für sich genommen nicht sicherer — was den Blast Radius begrenzt, ist die Maschinerie um das Deployment herum: gestufte Rollouts, Canary Releases, Health Checks und automatisches Rollback, wenn Metriken einbrechen.

Anatomie einer Pipeline

Welches Werkzeug Sie auch verwenden, eine Pipeline ist eine Abfolge von Stufen, von denen jede eine Änderung am Weiterkommen hindern kann:

  • Source — ein Trigger feuert bei einem Pull Request oder einem Merge auf den Main-Branch.
  • Build — kompilieren, Abhängigkeiten auflösen und ein versioniertes Artefakt erzeugen: ein Container-Image, ein Zip-Bundle, ein Package.
  • Test — schnelle Unit-Tests bei jedem Commit; Integrations- und End-to-End-Tests dort, wo ihr Aufwand gerechtfertigt ist.
  • Security-Checks — Dependency-Audit, statische Analyse, Secret Scanning.
  • Deploy nach Staging — das Artefakt geht, unverändert, in eine produktionsnahe Umgebung.
  • Promotion in die Produktion — wieder dasselbe Artefakt, hinter einem Freigabe-Gate oder automatisch.

Die wichtigste Eigenschaft ist: einmal bauen, dasselbe Artefakt überall deployen. Wenn Staging und Produktion unterschiedliche Builds fahren, validiert Staging gar nichts.

GitHub Actions als Referenzimplementierung

GitHub Actions ist das Standard-CI/CD-System für Teams, die bereits auf GitHub sind, und sein Modell bildet die Pipeline-Anatomie direkt ab. Ein Workflow ist eine YAML-Datei in .github/workflows/, die als Reaktion auf Events läuft. Ein Workflow enthält einen oder mehrere Jobs; jeder Job läuft auf einem Runner — einer von GitHub gehosteten virtuellen Maschine oder einer selbst betriebenen Maschine bzw. einem Container — und besteht aus sequenziellen Steps. Jobs laufen standardmäßig parallel und lassen sich mit needs ordnen.

Hier ein minimaler, aber produktionstauglicher CI-Workflow für ein Node.js-Projekt:

name: ci

on:
  pull_request:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm

      - run: npm ci
      - run: npm test

Die Details unterscheiden dies von Tutorial-Code: Actions auf aktuelle Major-Versionen gepinnt (checkout@v4, setup-node@v4 — GitHub lässt Workflows fehlschlagen, die noch stillgelegte Majors wie v2 verwenden, die auf End-of-Life-Node-Runtimes liefen), Node 22 als aktive LTS-Linie, Dependency-Caching und npm ci statt npm install für reproduzierbare Installationen.

AWS Lambda mit GitHub Actions und OIDC deployen

Beim Deployment gehen die meisten veröffentlichten Tutorials in die Irre, üblicherweise indem sie AWS_ACCESS_KEY_ID und AWS_SECRET_ACCESS_KEY als Repository-Secrets speichern. Langlebige Cloud-Credentials in der CI sind eine Hypothek: Sie laufen nie ab, sie können über Logs und Forks leaken, und ihre Rotation ist Handarbeit, die selten passiert. Das korrekte Muster — von AWS und GitHub seit 2021 unterstützt und 2026 die unstrittige Best Practice — ist OIDC-Föderation: Der Workflow fordert bei GitHub ein kurzlebiges Identitätstoken an, legt es AWS STS vor und übernimmt eine IAM-Rolle, die exakt auf dieses Repository und diesen Branch begrenzt ist. Es existieren nirgendwo statische Schlüssel.

Das einmalige AWS-Setup:

  • Erstellen Sie einen IAM-OIDC-Identity-Provider für token.actions.githubusercontent.com.
  • Erstellen Sie eine Deployment-Rolle, deren Trust Policy sts:AssumeRoleWithWebIdentity nur erlaubt, wenn der sub-Claim des Tokens zu Ihrem Repository und Branch passt (zum Beispiel repo:your-org/your-repo:ref:refs/heads/main), mit einer Permissions Policy, die lambda:UpdateFunctionCode auf der Zielfunktion erlaubt.

Halten Sie diese Deployment-Rolle getrennt von der Execution Role der Funktion: Die Execution Role ist das, was Ihrem laufenden Lambda-Code Zugriff auf andere AWS-Services gewährt, und die Pipeline braucht diese Berechtigungen nie. Wenn der Service selbst neu für Sie ist, beginnen Sie mit unserem Grundlagenartikel Was ist AWS Lambda und wann setzt man es ein.

Der vollständige Deployment-Workflow:

name: deploy-lambda

on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

concurrency:
  group: lambda-deploy
  cancel-in-progress: false

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm

      - name: Install production dependencies
        run: npm ci --omit=dev

      - name: Package function
        run: zip -r bundle.zip . -x ".git/*" -x ".github/*"

      - name: Configure AWS credentials via OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-lambda-deploy
          aws-region: eu-central-1

      - name: Deploy
        run: |
          aws lambda update-function-code \
            --function-name my-lambda-function \
            --zip-file fileb://bundle.zip
          aws lambda wait function-updated \
            --function-name my-lambda-function

Vier Zeilen tragen das Gewicht von Sicherheit und Korrektheit. permissions: id-token: write erlaubt dem Job, das OIDC-Token anzufordern. Der Trigger ist auf Pushes auf main beschränkt — ein nacktes on: push feuert auf jedem Branch, was bei einem Deploy-Workflow bedeutet, dass jeder Feature-Branch in Produktion geht. Die concurrency-Gruppe verhindert, dass zwei Deployments gegeneinander laufen, wenn Merges kurz hintereinander landen. Und aws lambda wait function-updated lässt den Job laut fehlschlagen, wenn das Update nicht abgeschlossen wird, statt bei einem halbfertigen Deployment Grün zu melden.

Test-Gates

Eine Pipeline ist nur so vertrauenswürdig wie die Gates in ihr. Lassen Sie Unit-Tests und Linting bei jedem Pull Request laufen und markieren Sie sie in der Branch Protection als Required Status Checks, damit ein roter Build nicht bloß peinlich, sondern unmöglich zu mergen ist. Reservieren Sie langsamere Integrations- und End-to-End-Suiten für Merges auf main oder eine Pre-Deploy-Stufe. Behandeln Sie einen flaky Test als Incident, nicht als Ärgernis: Sobald Engineers einen roten Build zum ersten Mal neu starten, "weil es wahrscheinlich eh in Ordnung ist", hat das Gate aufgehört, etwas zu bedeuten. Wie man diese Suiten schichtet, behandeln wir in unserem Leitfaden zu automatisierten Teststrategien.

Environments und Freigaben

GitHub-Environments sind die Release-Steuerungsebene. Definieren Sie staging und production in den Repository-Einstellungen, hängen Sie environment-spezifische Secrets und Variablen an und ergänzen Sie Schutzregeln: Pflicht-Reviewer für die Produktion, optionale Wartezeiten und Deployment-Branch-Beschränkungen, sodass nur main sie ansteuern kann. Die Zeile environment: production im obigen Workflow aktiviert diese Regeln — der Job pausiert, bis ein autorisierter Reviewer freigibt, und jede Freigabe wird auditiert. Das ist Continuous Delivery mit explizitem Release-Gate; entfernen Sie die Pflicht-Reviewer-Regel, und aus derselben Pipeline wird Continuous Deployment.

Häufige Fallstricke

  • Statische Cloud-Schlüssel in der CI. Ersetzen Sie sie durch OIDC-Rollenübernahme — auf AWS, Azure und Google Cloud gleichermaßen.
  • Veraltete Action-Majors. checkout@v2 und Konsorten laufen auf stillgelegten Runtimes und schlagen inzwischen schlicht fehl. Pinnen Sie aktuelle Majors und lassen Sie Dependabot Updates vorschlagen.
  • Zu breite Trigger. Ein ungefiltertes on: push läuft — und deployt — von jedem Branch. Filtern Sie Deploy-Workflows immer auf den Release-Branch.
  • Neu bauen pro Environment. Promoten Sie das Artefakt, das Sie getestet haben; ein Rebuild für die Produktion ist ein ungetesteter Build.
  • Kein Rollback-Pfad. Nutzen Sie Lambda-Versionen und -Aliases (oder Blue-Green für Server), damit ein Rollback ein umgelegter Zeiger ist und kein Re-Deploy unter Druck.

Nichts davon ist exotisch — die obigen Workflows sind Vorlagen, die Sie an einem Nachmittag anpassen können. Die härtere Arbeit ist organisatorisch: die Testabdeckung dorthin zu bringen, wo Grün wirklich "auslieferbar" bedeutet, und die Deploy-Frequenz dorthin, wo Releases langweilig sind. Das ist die Arbeit, die unsere DevOps-Consulting-Practice mit Engineering-Teams leistet — von der ersten Pipeline bis zur vollautomatisierten Lieferung.

Betreiben Sie so etwas in Produktion? Unser AWS-Managed-Services-Team betreibt solche Umgebungen rund um die Uhr — Monitoring, Incident Response, Patching und Kostenkontrolle durch namentlich benannte Senior Engineers, ab 3.000 €/Monat.