GitHub Actions CI/CD: Build-, Test- und Deploy-Workflows von Grund auf
Lerne, wie du GitHub Actions für Continuous Integration und Deployment einrichtest. Behandelt Trigger, Jobs, Matrizen, Secrets, Caching, Docker und praxisnahe Workflow-Beispiele.
GitHub Actions verwandelt jeden Push, Pull Request und Merge in eine automatisierte Pipeline – Tests werden ausgeführt, Artefakte gebaut, Sicherheitslücken gescannt und Deployments in die Produktion durchgeführt. Es ist die CI/CD-Plattform, die direkt in deinem Repository lebt, ohne jegliche Infrastruktur, die du verwalten müsstest.
Wie GitHub Actions funktioniert
Jeder Workflow ist eine YAML-Datei in .github/workflows/. Wenn ein Trigger-Ereignis ausgelöst wird, startet GitHub eine neue virtuelle Maschine, führt deine Jobs aus und meldet die Ergebnisse – alles innerhalb von Sekunden.
Push to main
↓
Workflow triggered
↓
Job: Build & Test (ubuntu-latest)
├── Step 1: Checkout code
├── Step 2: Install Node.js
├── Step 3: npm ci
├── Step 4: npm test
└── Step 5: npm run build
↓
✅ All checks passed
Dein erster Workflow
Erstelle .github/workflows/ci.yml:
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm test
- run: npm run build
Das war's. Jeder Push auf main und jeder PR führt nun automatisch deine Test-Suite aus.
Trigger: Wann Workflows ausgeführt werden
Code-Ereignisse
on:
push:
branches: [main, develop]
paths: ['src/**', 'package.json'] # Only run when these change
pull_request:
types: [opened, synchronize]
Geplant (cron)
on:
schedule:
- cron: '0 6 * * 1' # Every Monday at 6:00 UTC
Manueller Dispatch
on:
workflow_dispatch:
inputs:
environment:
description: 'Deploy target'
required: true
type: choice
options: [staging, production]
Dies fügt in der GitHub-Oberfläche eine Schaltfläche „Run workflow" hinzu, über die du Parameter auswählen kannst.
Wiederverwendbare Workflows
on:
workflow_call:
inputs:
node-version:
type: string
default: '20'
Rufe ihn aus einem anderen Workflow mit uses: ./.github/workflows/reusable.yml auf.
Jobs und Steps
Parallele Jobs
Jobs werden standardmäßig parallel ausgeführt:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
build:
runs-on: ubuntu-latest
needs: [lint, test] # Waits for both to pass
steps:
- uses: actions/checkout@v4
- run: npm run build
Matrix-Strategie – testen über mehrere Versionen
Denselben Job über mehrere Konfigurationen hinweg ausführen:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
Dies erzeugt 6 parallele Jobs (3 Versionen × 2 Betriebssysteme).
Secrets und Umgebungsvariablen
Secrets verwenden
Sensible Werte unter Settings → Secrets and variables → Actions speichern:
steps:
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: ./deploy.sh
Secrets werden in Logs maskiert und niemals an Forks weitergegeben.
Umgebungsvariablen
# Workflow-level
env:
NODE_ENV: production
jobs:
build:
# Job-level
env:
CI: true
steps:
- name: Build
# Step-level
env:
VITE_API_URL: https://api.example.com
run: npm run build
Caching für schnellere Builds
Ohne Caching lädt jeder Durchlauf alle Abhängigkeiten neu herunter. Caching reduziert die Build-Zeiten um 50–80 %:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm # Built-in npm caching
# Or manual caching for other tools
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
Artefakte: Daten zwischen Jobs teilen
Build-Ausgaben aus einem Job hochladen und in einem anderen herunterladen:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: dist
- run: ./deploy.sh
Praxisnahe Workflow-Beispiele
Docker Build und Push
name: Docker
on:
push:
tags: ['v*']
permissions:
packages: write
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
cache-from: type=gha
cache-to: type=gha,mode=max
Deployment auf Cloudflare Pages
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci && npm run build
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: pages deploy dist --project-name=my-site
Release mit Changelog
name: Release
on:
push:
tags: ['v*.*.*']
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate changelog
run: |
git log $(git describe --tags --abbrev=0 HEAD^)..HEAD \
--pretty=format:"- %s" > CHANGELOG.md
- uses: softprops/action-gh-release@v2
with:
body_path: CHANGELOG.md
generate_release_notes: true
Bedingte Ausführung
Steuern, wann Steps und Jobs ausgeführt werden:
steps:
- name: Deploy to production
if: github.ref == 'refs/heads/main'
run: ./deploy-prod.sh
- name: Deploy to staging
if: github.event_name == 'pull_request'
run: ./deploy-staging.sh
- name: Notify on failure
if: failure()
run: curl -X POST ${{ secrets.SLACK_WEBHOOK }} -d '{"text":"Build failed!"}'
Sicherheits-Best-Practices
1. Action-Versionen auf SHA pinnen
# ❌ Mutable tag — could be compromised
- uses: actions/checkout@v4
# ✅ Pinned to exact commit SHA
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
2. Minimale Berechtigungen verwenden
permissions:
contents: read # Only what's needed
packages: write
3. Secrets niemals ausgeben
# ❌ NEVER do this
- run: echo ${{ secrets.API_KEY }}
# ✅ Use environment variables
- env:
API_KEY: ${{ secrets.API_KEY }}
run: ./script-that-uses-api-key.sh
4. Berechtigungen für PRs aus Forks einschränken
on:
pull_request_target: # Runs in context of base branch
types: [opened, synchronize]
Fehlgeschlagene Workflows debuggen
- Logs prüfen – Klicke auf einen fehlgeschlagenen Step, um die vollständige Ausgabe zu sehen
- Debug-Logging aktivieren – Setze das Secret
ACTIONS_STEP_DEBUGauftrue actlokal nutzen – Workflows auf deiner Maschine ausführen mit nektos/act- Per SSH in den Runner einloggen –
mxschmitt/action-tmatefür interaktives Debugging verwenden
Workflows visuell erstellen
Du möchtest kein YAML von Hand schreiben? Nutze unseren GitHub Actions Generator, um Workflows visuell mit Templates für Node.js, Python, Docker, Deployments und mehr zu erstellen – und lade dann produktionsfertige YAML-Dateien herunter.
Fazit
GitHub Actions bietet dir CI/CD, das direkt in deinem Repository lebt:
- Einfach starten – Eine Workflow-Datei mit Build + Test
- Caching hinzufügen – Build-Zeiten mit
actions/cacheoder integriertem Sprach-Caching reduzieren - Matrix nutzen – Über Versionen und Betriebssysteme hinweg testen
- Secrets schützen – Nie hardcoden, immer verschlüsselte Secrets verwenden
- Alles automatisieren – Releases, Deployments, Sicherheitsscans, geplante Aufgaben
Die beste CI/CD-Pipeline ist die, die bei jedem Commit läuft, ohne dass du daran denken musst. Richte sie einmal ein und überlass den Rest GitHub.