Die Theorie hinter GitHub-gehosteten Runnern haben wir im vorherigen Kapitel behandelt. Jetzt geht es darum, diese Runner konkret in Workflows einzusetzen. Die gute Nachricht: Der Einstieg ist denkbar einfach. Die Herausforderung liegt eher darin, die Runner optimal zu nutzen und ihre Eigenheiten zu verstehen.
Das zentrale Element zur Runner-Auswahl ist das
runs-on-Attribut im Job. Hier definieren Sie, auf welchem
Betriebssystem und welcher Architektur Ihr Job ausgeführt werden soll.
Die Syntax ist bewusst schlicht gehalten:
jobs:
build:
runs-on: ubuntu-latestDas Schlüsselwort ubuntu-latest ist ein sogenanntes
Runner-Label. GitHub pflegt eine Reihe vordefinierter
Labels, die jeweils auf spezifische VM-Images verweisen. Die gängigsten
Labels sind:
| Label | Betriebssystem | Typische Verwendung |
|---|---|---|
ubuntu-latest |
Ubuntu Linux (aktuellste LTS) | Web-Apps, Container, Backend |
ubuntu-22.04 |
Ubuntu 22.04 LTS | Spezifische Ubuntu-Version |
windows-latest |
Windows Server (neueste Version) | .NET, Windows-Software |
windows-2022 |
Windows Server 2022 | Spezifische Windows-Version |
macos-latest |
macOS (neueste Version) | iOS/macOS-Entwicklung |
macos-13 |
macOS 13 Ventura | Spezifische macOS-Version |
macos-latest-xlarge |
macOS mit M1-Chip | ARM64-basierte Builds |
Das -latest-Suffix folgt einer einfachen Logik: GitHub
aktualisiert diese Label automatisch, wenn neue Versionen verfügbar
werden. Wenn Sie ubuntu-latest verwenden, erhalten Sie
stets die aktuelle Ubuntu LTS-Version – aktuell Ubuntu 22.04, in Zukunft
automatisch Ubuntu 24.04. Das ist praktisch, birgt aber ein Risiko: Ihr
Workflow könnte bei einem Major-Update des OS unerwartet
fehlschlagen.
Für produktive Workflows empfiehlt sich daher eine explizite
Versionierung: ubuntu-22.04 statt
ubuntu-latest. Sie kontrollieren dann selbst, wann Sie auf
eine neue OS-Version wechseln, und können Tests vorab durchführen.
Ein häufiges Szenario: Sie entwickeln eine Anwendung, die auf mehreren Betriebssystemen laufen soll. Der klassische Fall ist ein Node.js-CLI-Tool oder eine Electron-App. Sie möchten sicherstellen, dass Ihre Tests auf Linux, macOS und Windows durchlaufen. GitHub Actions macht das elegant durch parallele Jobs:
name: Cross-Platform Tests
on: [push, pull_request]
jobs:
test-ubuntu:
name: Tests auf Ubuntu
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test
test-windows:
name: Tests auf Windows
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test
test-macos:
name: Tests auf macOS
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm testDieser Workflow startet drei Jobs parallel – vorausgesetzt, Sie haben genügend Runner-Kapazität. Jeder Job läuft in einer isolierten VM, klont das Repository neu und führt die Tests aus. Wenn einer der Jobs fehlschlägt, sehen Sie sofort, auf welcher Plattform das Problem auftritt.
Die Redundanz in diesem Beispiel ist offensichtlich. Später werden wir sehen, wie Job-Matrizen diesen Code deutlich kompakter machen können. Für den Moment fokussieren wir uns auf das Grundprinzip: Ein Job, ein Runner, ein Betriebssystem.
Manchmal ist es hilfreich zu wissen, welche Runner für ein Repository
überhaupt verfügbar sind. GitHub bietet dafür eine UI-Ansicht im
Repository-Settings-Bereich. Der Zugriff erfordert
repo: write-Rechte:
Navigieren Sie zu Settings → Actions → Runners im Repository. Dort finden Sie eine Übersicht aller verfügbaren Runner – sowohl GitHub-gehostete als auch selbst gehostete (falls konfiguriert). Für GitHub-gehostete Runner sehen Sie einen Sammel-Eintrag, der auf die Standard-Runner verweist.
Ein praktischer Button ermöglicht es, das Runner-Label direkt zu
kopieren. Das ist hilfreich, wenn Sie nicht sicher sind, wie ein
spezifischer Runner-Typ exakt heißt. Klicken Sie auf das Kopiersymbol
neben dem Runner, und Sie erhalten das Label für runs-on in
die Zwischenablage.
GitHub Actions ist kein unbegrenzter Ressourcenpool. Abhängig von Ihrem GitHub-Plan gibt es eine Obergrenze für gleichzeitig laufende Jobs. Für Free-Accounts sind das beispielsweise 20 Jobs gleichzeitig auf Linux, 5 auf macOS und 5 auf Windows. Wenn Sie diese Grenze erreichen, werden neue Jobs in eine Warteschlange (Queue) eingereiht.
Um zu sehen, was gerade läuft und was wartet, navigieren Sie erneut zu Settings → Actions → Runners und klicken auf den Eintrag für GitHub-gehostete Runner. Dort finden Sie zwei relevante Bereiche:
Aktive Jobs zeigt alle derzeit laufenden Workflows. Sie sehen den Job-Namen, das Repository und die Laufzeit. Das ist wertvoll für Debugging: Wenn ein Workflow unerwartet lange läuft, können Sie hier nachsehen, ob er tatsächlich noch aktiv ist oder vielleicht hängt.
Alle Jobs: Verwendung zeigt die aktuelle Auslastung. Eine Anzeige wie “12 / 20” bedeutet: 12 Jobs laufen gerade, 20 sind maximal möglich. Erreichen Sie die 20, werden weitere Jobs in die Queue eingereiht und warten, bis Kapazität frei wird.
# Beispiel: Viele parallele Jobs
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
shard: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
steps:
- run: echo "Test Shard ${{ matrix.shard }}"Dieser Workflow würde 15 Jobs gleichzeitig starten wollen. Auf einem Free-Account mit 20er-Limit kein Problem. Aber stellen Sie sich vor, gleichzeitig läuft noch ein anderer Workflow mit 10 Jobs – plötzlich müssen 5 Jobs warten.
Die Queue ist fair: Jobs werden in der Reihenfolge ihres Eintreffens abgearbeitet. Es gibt keine Priorisierung nach Repository oder User. Das kann frustrierend sein, wenn Sie einen kritischen Hotfix deployen möchten, aber alle Runner mit Test-Jobs belegt sind.
Praktischer Tipp: Wenn Sie regelmäßig an Queue-Limits stoßen, überdenken Sie Ihre Workflow-Strategie. Müssen wirklich alle Tests parallel laufen? Oder können Sie Tests serialisieren und dafür mehr Test-Shards einsetzen? Manchmal ist es effizienter, Tests auf weniger Runnern nacheinander laufen zu lassen, statt die Queue zu verstopfen.
Die vorinstallierten Tools auf GitHub-Runnern decken viele Szenarien ab, aber nicht alle. Vielleicht benötigen Sie ein spezifisches CLI-Tool, eine Bibliothek oder eine bestimmte Compiler-Version. Kein Problem: Sie haben vollen Root-Zugriff auf die VM und können beliebige Software installieren.
Auf Ubuntu-Runnern steht Ihnen der komplette Ubuntu-Paket-Kosmos zur
Verfügung. Die Installation erfolgt über apt-get:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Installiere jq für JSON-Verarbeitung
run: |
sudo apt-get update
sudo apt-get install -y jq
- name: Verwende jq
run: |
echo '{"name": "GitHub Actions", "awesome": true}' | jq '.name'Beachten Sie das sudo apt-get update vor der
Installation. Der apt-Index auf dem Runner kann veraltet sein – ein
Update stellt sicher, dass Sie die neuesten Paketversionen erhalten und
vermeidet kryptische Fehler wie “Paket konnte nicht gefunden
werden”.
Das -y-Flag bestätigt automatisch alle Prompts. Ohne
dieses Flag würde der Installationsbefehl in einem nicht-interaktiven
Workflow hängen bleiben.
Für Software, die nicht in den offiziellen Ubuntu-Repositories ist, können Sie auch snap verwenden:
- name: Installiere kubectl via snap
run: sudo snap install kubectl --classicOder Sie laden Binaries direkt herunter:
- name: Installiere Terraform
run: |
wget https://releases.hashicorp.com/terraform/1.6.0/terraform_1.6.0_linux_amd64.zip
unzip terraform_1.6.0_linux_amd64.zip
sudo mv terraform /usr/local/bin/
terraform --versionmacOS-Runner kommen mit Homebrew vorinstalliert, dem de-facto Package Manager für macOS. Die Installation ist elegant:
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Installiere GitHub CLI
run: |
brew update
brew install gh
- name: Verwende GitHub CLI
run: gh --versionHomebrew unterscheidet zwischen Formulae (Kommandozeilen-Tools) und Casks (GUI-Anwendungen). Für Browser-Tests benötigen Sie möglicherweise einen Cask:
- name: Installiere Microsoft Edge
run: |
brew update
brew install --cask microsoft-edgeDas brew update ist hier ebenfalls wichtig – ohne Update
kennt Homebrew möglicherweise neue Pakete oder Versionen nicht.
Ein Hinweis zu macOS-Runnern: Sie sind deutlich teurer als Linux-Runner (Faktor 10 in der Abrechnung). Installieren Sie daher nur, was Sie wirklich brauchen, und cachen Sie Dependencies wo möglich.
Windows-Runner nutzen Chocolatey als Package Manager. Chocolatey ist vorinstalliert und kann über PowerShell angesprochen werden:
jobs:
build:
runs-on: windows-latest
steps:
- name: Installiere GitHub CLI
run: choco install gh -y
- name: Verwende GitHub CLI
run: gh versionDas -y-Flag bestätigt auch hier automatisch alle
Prompts. Chocolatey bietet eine riesige Auswahl an Paketen – von
Entwicklungstools über Editoren bis zu kompletten Frameworks.
Wenn ein Paket nicht über Chocolatey verfügbar ist, können Sie auf PowerShell zurückgreifen und Installer direkt herunterladen:
- name: Installiere Custom Tool
shell: pwsh
run: |
Invoke-WebRequest -Uri "https://example.com/tool.msi" -OutFile "tool.msi"
Start-Process msiexec.exe -Wait -ArgumentList '/I tool.msi /quiet'Jede Installation kostet Zeit. Wenn Sie in jedem Workflow-Lauf
dieselben Pakete installieren, addiert sich das. Ein
apt-get install für ein großes Paket kann 30 Sekunden oder
mehr dauern. Bei 100 Workflow-Läufen pro Tag sind das 50 Minuten – Zeit,
die Sie mit Caching oder Custom Images sparen könnten.
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Zeitaufwändig: In jedem Lauf neu installieren
- name: Installiere Dependencies (langsam)
run: |
sudo apt-get update
sudo apt-get install -y build-essential libssl-dev pkg-config
# Dauert ~1-2 Minuten
- name: Build
run: makeBessere Ansätze:
Actions verwenden: Viele Tools haben dedizierte Actions, die optimiert und gecacht sind:
- uses: actions/setup-python@v4
with:
python-version: '3.11'Diese Action ist schneller als manuelles Installieren und garantiert Reproduzierbarkeit.
Dependencies cachen: Wenn Sie regelmäßig dieselben Pakete installieren, nutzen Sie den Cache:
- name: Cache APT packages
uses: actions/cache@v3
with:
path: /var/cache/apt/archives
key: apt-${{ runner.os }}-${{ hashFiles('**/packages.txt') }}
- name: Installiere Packages
run: |
sudo apt-get update
sudo apt-get install -y $(cat packages.txt)Custom Images: Für Larger Runner können Sie ein Custom Image mit vorinstallierten Tools erstellen. Das ist der ultimative Performance-Boost, erfordert aber mehr Setup-Aufwand.
Ein subtiles Detail: Die Default-Shell variiert je nach
Betriebssystem. Ubuntu-Runner nutzen bash, Windows-Runner
nutzen PowerShell. Das kann zu überraschenden Unterschieden führen:
# Funktioniert auf Linux, nicht auf Windows
- run: export FOO=bar && echo $FOO
# Funktioniert auf Windows, nicht auf Linux
- run: $env:FOO="bar"; echo $env:FOOFür plattformübergreifende Kompatibilität können Sie die Shell explizit setzen:
- name: Plattform-unabhängiges Script
shell: bash
run: |
export FOO=bar
echo "FOO ist: $FOO"Das funktioniert, weil Windows-Runner Git Bash vorinstalliert haben. Alternativ können Sie PowerShell Core verwenden, das auf allen Plattformen läuft:
- name: PowerShell überall
shell: pwsh
run: |
$env:FOO = "bar"
Write-Host "FOO ist: $env:FOO"Ein häufiger Anfängerfehler: Sie definieren einen Workflow, er startet, aber Sie wissen nicht, auf welchem Runner er läuft. Die Workflow-Logs geben Ihnen diese Information:
Expandieren Sie in der Workflow-Ansicht den Abschnitt “Set up job”. Dort finden Sie unter “Runner Image” exakte Informationen:
ubuntu-22.04)Der “Included Software”-Link ist Gold wert beim Debugging. Wenn ein Tool, das gestern funktionierte, heute plötzlich fehlt, können Sie über diesen Link nachsehen, ob sich die Runner-Konfiguration geändert hat.
Trotz aller Flexibilität gibt es Grenzen bei GitHub-gehosteten Runnern:
Maximale Job-Laufzeit: Ein einzelner Job darf maximal 6 Stunden laufen. Danach wird er abgebrochen. Für die meisten Builds mehr als ausreichend, aber Machine-Learning-Training oder umfangreiche Integrationstests können das sprengen.
Festplattenspeicher: Runner haben begrenzten Disk Space. Wenn Sie große Datasets oder viele Container-Images bauen, kann der Speicher knapp werden. Überwachen Sie die Disk-Usage in Ihren Workflows:
- name: Check Disk Space
run: df -hNetzwerk-Bandbreite: Obwohl die Runner in Azure laufen und exzellente Anbindung haben, können sehr große Downloads oder Uploads Zeit kosten. Optimieren Sie, wo möglich.
Keine persistenten Daten: Jeder Job startet mit einer frischen VM. Alles, was Sie nicht explizit speichern (via Artifacts, Cache oder externe Speicher), ist nach Job-Ende weg.
Die von GitHub gehosteten Runner bieten eine leistungsfähige, wartungsfreie Basis für CI/CD-Workflows. Mit den richtigen Techniken zur Software-Installation, einem Verständnis für die Platform-Eigenheiten und Monitoring der Runner-Kapazität lassen sich professionelle Workflows realisieren. Die Herausforderung liegt meist nicht in technischen Limitierungen, sondern darin, die Runner effizient zu nutzen und Wartezeiten zu minimieren.