--- type: types/entity.md entity_type: tool tags: [ci-cd, gitea, docker, runner] created: 2026-07-25 modified: 2026-09-01 related: - uses: Gitea - hosts: Gitea Actions sources: [Source - Conversation - Versioning CI-CD and Content Migration Session 2026-08-30] confidence: 0.95 confidence_base: 0.95 provenance: sourced summary: Offizieller Gitea-Actions-Runner, der CI/CD-Workflows in Docker-Containern auf einer dedizierten Runner-VM ausführt; JavaScript-Actions brauchen node im Job-Container --- # Act Runner **Typ:** Tool (Gitea Actions Runner) ## Beschreibung `act_runner` ist die offizielle Runner-Implementierung für Gitea Actions. Sie führt CI/CD-Workflows auf der VM `ci-runner.example.net` aus und läuft als Docker-Container im Host-Network-Modus, damit die Verbindung zu den Job-Containern und zum Actions Cache Server funktioniert. ## Kerndaten - **Zweck:** Ausführen von Gitea-Actions-Workflows - **Status:** Aktiv (Stand 2026-07-12) - **Container-Image:** `gitea/act_runner:latest` - **Containername:** `act_runner` - **Restart Policy:** `unless-stopped` - **Network Mode:** `host` (entscheidend für die Cache-Anbindung) ## Architektur ### Container-Konfiguration ```yaml services: act_runner: image: gitea/act_runner:latest container_name: act_runner restart: unless-stopped network_mode: host environment: - CONFIG_FILE=/config.yaml - GITEA_INSTANCE_URL=http://192.0.2.10:3000 - GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_REGISTRATION_TOKEN} - GITEA_RUNNER_NAME=ci-vm-runner volumes: - ./data:/data - ./config.yaml:/config.yaml:ro - /var/run/docker.sock:/var/run/docker.sock ``` ### Wesentliche Konfigurationseinstellungen **config.yaml:** ```yaml cache: enabled: true host: "192.0.2.10" # static IP of ci-runner.example.net port: 8088 container: network: "" # empty = each job gets isolated bridge network ``` ### Routing-Labels Eigene semantische Labels anstelle der Standard-Ubuntu-Labels: - `linux-docker` - `container-builder` - `k3s-deploy` Damit lassen sich Workflows gezielt an Runner mit bestimmten Capabilities leiten. ## Beziehungen - **Teil von:** Ökosystem [[Gitea Actions]] - **Verbindet sich mit:** [[Gitea]]-Instanz unter `docker-host.example.net` für die Container-Ausführung - **Verwaltet:** Job-Container mit isolierten Bridge-Netzen ## Netzwerk ### Host-Network-Modus Die entscheidende Einstellung, die das Problem mit dem Actions Cache Server gelöst hat: - Der Runner-Container nutzt `network_mode: host` - Dadurch erreichen Job-Container den Cache-Server unter der konfigurierten statischen IP - Die Cache-URL wird automatisch als Umgebungsvariable `ACTIONS_CACHE_URL` gesetzt - **Wichtig:** `network_mode: host` und ein `networks:`-Block schließen sich in Docker Compose gegenseitig aus ### Isolation der Job-Container Obwohl der Runner im Host-Netz läuft: - Jeder CI-Job läuft in einem eigenen, temporären Bridge-Netz - `container.network: ""` in der `config.yaml` stellt das sicher - Die Job-Isolation bleibt erhalten - Nur der Runner-Prozess selbst hat Zugriff auf das Host-Netz ## Verwaltung von Secrets ### 1Password-Anbindung - Das Service-Account-Token wird über eine systemd-`EnvironmentFile` eingespielt (`/etc/act_runner/secrets.env`) - Es ist das einzige Secret, das als Umgebungsvariable vorliegt - In Gitea heißt das ein "Actions Secret" - Workflows holen weitere Secrets zur Laufzeit über `1password/load-secrets-action@v2` ### Gitea-Token - Workflows können `${{ gitea.token }}` zur Authentifizierung verwenden - Genutzt für Image-Pushes in die Gitea Container Registry - Erfordert `permissions: packages: write` im Workflow - Reicht auch für **Releases, Tags und Asset-Uploads**; ein Actions-Secret mit `write:repository` ist dafür nicht nötig. Belegt dadurch, dass ein Release-Workflow beim Versionssprung von selbst feuerte und Tarball samt `.sha256` ablegte[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30] ## Betrieb ### Neustartverhalten - Nach Netzwerkänderungen ist ein vollständiges `docker compose down && docker compose up -d` nötig - Ein einfaches `docker restart` übernimmt Änderungen an `network_mode` **nicht** zuverlässig ### Persistenz - Workflow-Daten liegen im Volume `./data` - Konfiguration in `./config.yaml` (nur lesend eingebunden) - Docker-Socket eingebunden für den Zugriff auf BuildKit ## JavaScript-Actions brauchen `node` im Job-Container Nennt ein Job sein eigenes `container:`-Image, führt act_runner JavaScript-Actions - darunter `actions/checkout` - mit `node` **innerhalb dieses Job-Containers** aus. Ein schlankes Image bringt keins mit, und der Lauf endet vor dem ersten eigenen Schritt[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]: ``` OCI runtime exec failed: exec: "node": executable file not found in $PATH ❌ Failure - Main actions/checkout@v4 exitcode '127': command not found ``` Der erste Schritt eines solchen Jobs muss deshalb `nodejs` nachinstallieren, **vor** dem Checkout[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]: ```yaml - name: Install CI Dependencies run: apt-get install -y --no-install-recommends git nodejs curl unzip ca-certificates build-essential - name: Checkout Code uses: actions/checkout@v7 ``` Bekannt funktionierende Kombination auf dieser Installation, nicht neu herzuleiten[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]: - `actions/checkout@v7` und `actions/upload-artifact@v3` (v4 ist auf dieser Instanz eingeschränkt) - `debian:trixie-slim` als Job-Image; es trägt python3 3.13 - Die Labels `linux-docker` und `container-builder` nehmen beide einen Job an, der sein eigenes Image benennt Ein gepinntes Image war ursprünglich als Vorsichtsmaßnahme gegen die undokumentierte Zuordnung von `linux-docker` zu einem Image gewählt worden. Die Vorsichtsmaßnahme verursachte den Fehlschlag: Das Label routete von Anfang an korrekt und startete den Container, nur fehlte im gewählten Image `node`[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]. ## Läufe sind von außen nicht beobachtbar Bei einem privaten Repository antwortet [[Gitea]] einem anonymen Aufrufer mit einem identischen `404` für ein unsichtbares und für ein nicht existierendes Repository[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]. Aus einem `curl` gegen die API lässt sich damit kein Rückschluss auf den Lauf-Zustand ziehen. Läufe und ihre Logs werden über den [[Gitea MCP Server]] gelesen. ## Erprobte CI/CD-Szenarien Der Runner deckt drei Szenarien nachweislich ab: 1. **Arch-Paketbau** - Builder-Benutzer ohne Root-Rechte, `actions/upload-artifact@v3` 2. **Container-Builds** - Debian-basierte Images, entferntes BuildKit 3. **K3s-Deployments** - Kubeconfig aus 1Password, kubectl-Operationen ## Historie - [2026-07-12] - Network Mode auf `host` umgestellt, um die Anbindung an den Actions Cache Server zu reparieren (ETIMEDOUT auf 172.18.0.2:39329) - [2026-07-25] - Entity-Seite aus dem Quellen-Ingest erstellt - [2026-08-30] - Ursache der bis dahin unerklärten Workflow-Fehlschläge geklärt: fehlendes `node` im gepinnten Job-Image, nicht ein falsches Runner-Label. `nodejs` vor dem Checkout und `actions/checkout@v7` als Abhilfe festgehalten[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30] ## Siehe auch - Host-System - [[Gitea]] - Git-Dienst - [[Gitea Actions]] - CI/CD-Plattform - Container-Plattform - Secrets-Verwaltung - Behebung des Actions-Cache-Server-Problems ## Fußnoten [^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]: [[Source - Conversation - Versioning CI-CD and Content Migration Session 2026-08-30]] ## Beziehungen - **uses:** [[Gitea]] - **hosts:** [[Gitea Actions]]