edu@dorner-it
WerkzeugeEinsteiger20 min

GitHub Actions Basics: CI/CD verstehen

Wie GitHub Actions wirklich funktioniert — Workflows, Jobs, Steps und Trigger. Mit einem ersten lauffähigen Workflow und den Konzepten dahinter.

Zuletzt aktualisiert: 11. Mai 2026

GitHub Actions ist die Automatisierungs­schicht direkt im Repo: Jedes Mal, wenn jemand pushed, einen PR öffnet, ein Tag setzt oder ein Cron-Timer feuert, kann Code laufen — gebaut, getestet, deployed, gelabelt. In diesem Kurs lernst du das mentale Modell und schreibst deinen ersten eigenen Workflow.

Lernziele

  • Du verstehst die Hierarchie Workflow → Job → Step
  • Du kennst die wichtigsten Trigger (on:)
  • Du schreibst einen funktionierenden Workflow von Hand
  • Du nutzt Secrets, Caches und Matrix-Builds bewusst

Das mentale Modell

flowchart TD
    E[Event: push, PR, schedule, ...] --> WF[Workflow<br/><small>.github/workflows/ci.yml</small>]
    WF --> J1[Job: build]
    WF --> J2[Job: test]
    WF --> J3[Job: deploy]
    J1 --> S1[Step: checkout]
    J1 --> S2[Step: setup-node]
    J1 --> S3[Step: npm run build]
Ebene Was es ist
Workflow YAML-Datei in .github/workflows/
Job Eine Gruppe von Steps, läuft auf einem Runner
Step Ein einzelner Befehl oder eine Action
Action Wiederverwendbarer Baustein (z. B. actions/checkout@v4)
Runner Die Maschine, auf der der Job ausgeführt wird

Wichtig: Jeder Job startet in einer frischen VM. Dateien zwischen Jobs zu teilen geht nur über Artifacts oder Caches — nicht über das Dateisystem.

Dein erster Workflow

Lege eine Datei .github/workflows/ci.yml an:

name: CI
 
on:
  push:
    branches: [main]
  pull_request:
 
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npm test

Was hier passiert, Zeile für Zeile:

  • name: — wie der Workflow in der UI heißt
  • on:wann er läuft (siehe nächster Abschnitt)
  • jobs.test — ein Job namens test
  • runs-on: — der Runner-Typ (Ubuntu, Windows, macOS oder self-hosted)
  • steps: — die Befehlsfolge, von oben nach unten

Die wichtigsten Trigger

on:
  push:
    branches: [main, release/*]
    paths:
      - "src/**"
      - "package.json"
  pull_request:
    types: [opened, synchronize, reopened]
  schedule:
    - cron: "0 6 * * *"      # täglich 06:00 UTC
  workflow_dispatch:          # manuell aus der UI
  release:
    types: [published]

workflow_dispatch ist Gold wert beim Testen — du kannst den Workflow manuell aus der UI starten, ohne ein Commit erzwingen zu müssen.

Steps: uses vs run

Es gibt genau zwei Arten von Steps:

Typ Beispiel Wann
uses: actions/checkout@v4 Wiederverwendbare Action aus Marketplace/Repo
run: npm test Direkter Shell-Befehl auf dem Runner
- name: Tests laufen lassen
  run: |
    npm ci
    npm test -- --reporter=verbose
  env:
    NODE_ENV: test

Action immer mit Version pinnen (@v4 oder besser ein SHA-Hash) — sonst kann sich Verhalten unter dir ändern.

Secrets & Variables

Niemals Tokens ins YAML schreiben. Stattdessen in den Repository- Settings unter Secrets and variables → Actions hinterlegen:

- name: Deploy
  env:
    API_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
    REGION: ${{ vars.AWS_REGION }}
  run: ./scripts/deploy.sh
Wert Sichtbar im Log? Wofür
secrets.X nein (maskiert) Tokens, Passwörter, Keys
vars.X ja Konfiguration, Regionen, Flags

Jobs parallel & abhängig

Standardmäßig laufen Jobs parallel. Mit needs: machst du sie abhängig:

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
 
  deploy:
    needs: [lint, test]
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - run: ./deploy.sh
flowchart LR
    L[lint] --> D[deploy]
    T[test] --> D

Das if: ist eine Bedingung — deploy läuft nur auf main, nicht bei jedem PR.

Matrix-Builds

Wenn du die gleichen Schritte auf mehreren Konfigurationen laufen lassen willst:

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        node: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci && npm test

Das erzeugt 3 × 3 = 9 parallele Jobs. fail-fast: false heißt: selbst wenn einer scheitert, laufen die anderen weiter — du siehst alle Probleme auf einmal.

Caching — Builds beschleunigen

- uses: actions/setup-node@v4
  with:
    node-version: 20
    cache: "npm"            # eingebauter Cache von setup-node

Oder explizit mit actions/cache:

- uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
    restore-keys: |
      ${{ runner.os }}-pip-

Der Key entscheidet über Hit/Miss. hashFiles(...) ändert sich, wenn sich die Lockfile ändert — genau das, was du willst.

Artifacts — Dateien zwischen Jobs teilen

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/
 
  e2e:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: dist
          path: dist/
      - run: npm run test:e2e

Häufige Stolperfallen

„Mein Workflow läuft gar nicht"

  • Liegt die Datei in .github/workflows/ (zwei Punkte beachten)?
  • Endung .yml oder .yaml?
  • Auf welcher Branch? Trigger feuert nur, wenn die YAML auf der Branch liegt, die das Event auslöst.

„Secrets sind leer in Forks"

Aus Sicherheitsgründen: bei PRs aus Forks werden Secrets nicht mitgegeben. Workaround: pull_request_target — aber vorsichtig, das führt zu eigenen Sicherheitsrisiken.

„Workflow gewinnt nie an Geschwindigkeit"

Checke in dieser Reihenfolge:

  1. Wird wirklich gecached? (UI zeigt Cache-Hit/Miss)
  2. Lassen sich Jobs parallel statt sequenziell führen?
  3. Kann der Job auf einem kleineren Runner laufen?

Praxis-Übung

In einem beliebigen kleinen Repo:

  1. Lege .github/workflows/hello.yml an:
name: Hello
on: [workflow_dispatch, push]
jobs:
  greet:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Hallo von $GITHUB_ACTOR auf $GITHUB_REF"
      - run: |
          echo "Event: $GITHUB_EVENT_NAME"
          echo "SHA:   $GITHUB_SHA"
  1. Push die Datei.
  2. Geh auf den Actions-Tab im Repo — du solltest deinen Workflow laufen sehen.
  3. Klick auf „Run workflow" (workflow_dispatch), um ihn manuell zu starten.

Wenn das klappt: erweitere ihn um einen zweiten Job mit needs: und schau dir die Visualisierung in der UI an.

Weiterführendes


CI/CD ist kein Tool, das man installiert — es ist eine Gewohnheit, die man schreibt. ⚙️