Zum Inhalt

Gitea Actions & Runners

Diese Seite beschreibt Gitea Actions auf dem aktuellen Stand (Stand: Gitea 1.27, Runner v3.1.0 vom 06.2026):

  • die Grundlagen (Runner-Architektur, Label-System, Image-Flavours)
  • wie man eigene Job-Images für das Team baut (Ubuntu 26.04 + OracleLinux 9, Java 25 + Kotlin + Maven + gitflow)
  • wie Alles ohne externe Quellen läuft: Actions-Mirror auf eigener Gitea, Job-Images aus eigener Registry
  • wie die Ansible-Rolle gitea_runner das pro Runner bzw. pro Tag einbindet
  • wie man automatisch patcht: Renovate + wöchentlicher Build + Cache-Prune

Alle Beispiele nutzen die eigene Registry gitea.rwcloud.ch und den eigenen Runner.

Gitea Actions – Überblick

Gitea Actions ist der GitHub-Actions-kompatible CI/CD-Arm von Gitea (seit Gitea 1.19). Die wichtigsten Unterschiede zu GitHub:

Thema Gitea GitHub
workflow_dispatch Inputs ✅ seit 1.23, alle Typen ✅
jobs.<id>.environment ⚠️ wird ignoriert ✅
complex runs-on (Matrix) ⚠️ nur runs-on: xyz oder [xyz] ✅
permissions: (Job-Token) ✅ mit Gitea-scopes (code, releases, wiki, projects) ✅
Go-Actions ✅ native ❌
Absolute Action-URLs ✅ uses: https://gitea.com/owner/repo@tag ✅ (rel. owner/repo@tag)
Problem Matchers ⚠️ ignoriert ✅
always() Expression ✅ einzige unterstützte ✅ alle
Pre/Post-Schritte im UI ⚠️ keine eigene Sektion ✅
schedule: @daily/@weekly ✅ zusätzlich zu Cron ❌

Aktivieren

In app.ini der Gitea-Instanz (falls noch nicht aktiviert – seit 1.21 standardmäßig an):

1
2
[actions]
ENABLED = true

Im Repository unter Settings → Actions ist zusätzlich Enable Repository Actions zu aktivieren.

Runner-Architektur & Label-System

Der Runner (getrennt vom Gitea-Server betrieben) empfängt Jobs und führt sie aus. Wichtig zu verstehen ist die Trennung:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
┌─────────────────┐         gRPC over HTTP          ┌─────────────────┐
│  Gitea Server   │ ◄─────────────────────────────► │     Runner      │
│                 │        (Job-Aufträge)           │  (basic-flv)    │
└─────────────────┘                                  └────────┬────────┘
                                                              │ startet
                                                              ▼
                                                     ┌─────────────────┐
                                                     │  Job-Container  │
                                                     │  (custom-image) │
                                                     └─────────────────┘

Der Runner startet für jeden Job einen Container aus einem Docker-Image. Welches Image verwendet wird, entscheidet das Label-System:

1
<name>[:<schema>[:<args>]]
Schema Bedeutung Beispiel
docker://<image> Job läuft in Container aus <image> java-25:docker://gitea.rwcloud.ch/homelab/runner-java-25-ubuntu-26.04:latest
host Job-Schritte laufen direkt auf Host shell:host
(leer) Standard host ubuntu-latest → läuft auf Host mit dort installierten Tools

Wichtig: Wenn du runs-on: ubuntu-latest in deinem Workflow schreibst UND der Runner nur das Label ubuntu-latest (ohne docker://) kennt, läuft der Job auf dem Host des Runners – nicht in einem Container! Das ist häufiger Grund für "warum ist Java nicht da, obwohl ich's doch installiert habe?".

Wenn kein Label passt, fällt der Runner auf docker.gitea.com/runner-images:ubuntu-latest zurück (default). Genau dorthin will man also nicht gelangen.

Runner-Image-Flavours

Das offizielle gitea/runner-Image gibt's in drei Varianten:

Tag Basis Docker-daemon Prozess-Monitoring Nutzt
latest (basic) alpine extern (Host-Socket bind-mount required) tini Root, --privileged nicht nötig
latest-dind docker:dind eingebaut s6 Root, --privileged nötig
latest-dind-rootless docker:dind-rootless eingebaut (rootless) s6 UID 1000, rootless-Limits

Für dieses Setup: basic (Status-Quo). Der Runner bindet /var/run/docker.sock vom Host. Vorteile: - keine Privilegien, einfacher - der Docker-daemon mit allen Caches läuft auf dem Host (perfekt für docker image prune via post_task_script) - Job-Images werden per docker://image aus labels gezogen, können also deine eigene Registry sein

Eigene Job-Images: Konzept

Anstatt jedes Mal uses: actions/setup-java@v3 (der von github.com lädt) zu nutzen, bauen wir ein Job-Image, in dem alle Tools schon installiert sind. Das ist:

  1. schneller – kein Setup-Schritt pro Job
  2. offline-fähig – DEFAULT_ACTIONS_URL=self + eigenes Image = kein github.com
  3. kontrolliert – exakt die Versionen, die das Team braucht

Was muss in das Image?

Für ein Java 25/26 + Kotlin + Vaadin Flow + Maven + gitflow Setup:

Komponente Warum
git Version Control (immer)
curl, wget, jq, zsh Basis-Tools
ca-certificates, unzip TLS & de-archivers
JDK 25 (Temurin) Vaadin Flow, mvn, Kotlin
Kotlin 2.1.x (kotlinc) Kotlin-Compiler (falls nicht via Maven nur)
Maven Build & Dependency-Management für Vaadin
gitflow-avh avh-Wrapper um git flow fürs Team
docker client (optional) falls Job docker build braucht
make einfache Build-Schritte
openssh-client Deploy-Ziele
uv (optional) Python-Tooling, falls im Workflow

Hinweis zu Vaadin / Vaadin Flow: Das eigentliche Vaadin ist nur ein Maven-Plugin (com.vaadin:vaadin-maven-plugin), keine eigene Binary. Maven + JDK genügt. Für Vaadin 24+ braucht man Node.js, das Plugin lädt das aber selbst (via npm/pnpm).

Dockerfile – Ubuntu 26.04 (Beispiel)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# syntax=docker/dockerfile:1
ARG UBUNTU_TAG=26.04
FROM ubuntu:${UBUNTU_TAG}

ARG JAVA_VERSION=25
ARG KOTLIN_VERSION=2.1.20
ARG MAVEN_VERSION=3.9.9

ENV DEBIAN_FRONTEND=noninteractive \
    JAVA_HOME=/opt/java/openjdk \
    MAVEN_HOME=/opt/maven \
    KOTLIN_HOME=/opt/kotlinc \
    PATH=$PATH:/opt/java/openjdk/bin:/opt/maven/bin:/opt/kotlinc/bin

# Basis + Node.js LTS (für Vaadin-Plugin + gitflow-avh)
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \
    apt-get install -y --no-install-recommends nodejs

RUN apt-get update && apt-get install -y --no-install-recommends \
    git curl wget jq zsh ca-certificates unzip make openssh-client git-remote-https \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# Temurin JDK via Adoptium APT-Repo
# Key wird via gpg auf Debian-Schreibweise in eine .gpg-Datei gelegt (apt-key ist weg)
RUN curl -fsSL https://packages.adoptium.net/artifactory/api/key/live/deb/key \
        | gpg --dearmor -o /etc/apt/keyrings/adoptium.gpg \
    && echo "deb [signed-by=/etc/apt/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/api/repository/12/deb/ $(lsb_release -cs) main" \
        > /etc/apt/sources.list.d/adoptium.list \
    && apt-get update \
    && apt-get install -y temurin-${JAVA_VERSION}-jdk \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# Maven (tarball, Symlink /opt/maven → /opt/apache-maven-…)
RUN curl -fsSL "https://dlcdn.apache.org/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" -o /tmp/maven.tar.gz \
    && gunzip -c /tmp/maven.tar.gz | tar -x -C /opt \
    && ln -sfn /opt/apache-maven-${MAVEN_VERSION} /opt/maven \
    && rm -f /tmp/maven.tar.gz

# Kotlin (GitHub-Release, Fallback auf npm wenn GitHub nicht erreichbar)
RUN curl -fsSL "https://github.com/JetBrains/kotlin/releases/download/v${KOTLIN_VERSION}/kotlin-compiler-${KOTLIN_VERSION}.zip" -o /tmp/kotlin.zip \
        && unzip -o /tmp/kotlin.zip -d /opt/ && rm -f /tmp/kotlin.zip \
    || npm install -g kotlin-compiler@${KOTLIN_VERSION}

# gitflow-avh + git-flow
RUN npm install -g gitflow-avh \
    && apt-get update && apt-get install -y git-flow && apt-get clean && rm -rf /var/lib/apt/lists/*

WORKDIR /workspace

# Nicht-root-User
RUN useradd -m -s /bin/zsh builder && chown -R builder:builder /workspace
USER builder

Dockerfile – OracleLinux 9 (Beispiel)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# syntax=docker/dockerfile:1
FROM oraclelinux:9

ARG JAVA_VERSION=25
ARG KOTLIN_VERSION=2.1.20
ARG MAVEN_VERSION=3.9.9

ENV DEBIAN_FRONTEND=noninteractive \
    JAVA_HOME=/opt/java/openjdk \
    MAVEN_HOME=/opt/maven \
    KOTLIN_HOME=/opt/kotlinc \
    PATH=$PATH:/opt/java/openjdk/bin:/opt/maven/bin:/opt/kotlinc/bin

# Basis
RUN dnf install -y \
        git curl jq unzip make ca-certificates openssh-cli nodejs npm \
    && dnf clean all

# Temurin JDK via Adoptium DNF-Repo
# (9-Repo liefert "temurin-25-jdk" als -jre/-jdk-Variante)
RUN dnf module enable -y nodejs:22 || true \
    && dnf install -y java-25-openjdk-devel || \
       (curl -fsSL https://packages.adoptium.net/artifactory/api/key/live/rpm/key \
          | rpm --import - && \
         echo "adoptium main https://packages.adoptium.net/artifactory/api/repository/12/rpm/9/main/" > /etc/yum.repos.d/adoptium.repo && \
         dnf install -y temurin-${JAVA_VERSION}-jdk)

# Maven (tarball extrahiert /opt/apache-maven-…, Symlink dorthin)
RUN curl -fsSL "https://dlcdn.apache.org/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" -o /tmp/maven.tar.gz \
    && gunzip -c /tmp/maven.tar.gz | tar -x -C /opt \
    && ln -sfn /opt/apache-maven-${MAVEN_VERSION} /opt/maven \
    && rm -f /tmp/maven.tar.gz

# Kotlin
RUN curl -fsSL https://github.com/JetBrains/kotlin/releases/download/v${KOTLIN_VERSION}/kotlin-compiler-${KOTLIN_VERSION}.zip -o /tmp/kotlin.zip && \
    unzip -o /tmp/kotlin.zip -d /opt/ && rm /tmp/kotlin.zip || \
    npm install -g kotlin-compiler@${KOTLIN_VERSION}

# gitflow-avh (npm-basiert)
RUN npm install -g gitflow-avh && \
    dnf install -y git-flow && dnf clean all

WORKDIR /workspace
RUN useradd -m -s /bin/bash builder && chown -R builder:builder /workspace
USER builder

Achtung: Oracle Linux 9 hat nodejs im AppStream-Repo ab der 9.3. Wenn nodejs nicht gefunden wird: dnf config-manager --enable "ubi-9-kmods-rpms ubi-9-crs-rpms ol9_codeready_builder" oder die Version explizit dnf install nodejs:22.

Naming & Push

1
2
3
gitea.rwcloud.ch/homelab/runner-java-25-ubuntu-26.04:latest
gitea.rwcloud.ch/homelab/runner-java-25-ubuntu-26.04:25.0.4
gitea.rwcloud.ch/homelab/runner-java-25-oraclelinux-9:latest
  • latest wird wöchentlich neu gebaut (siehe Auto-Patch)
  • Versionstags (z. B. 25.0.4) sind immutabil – gut für Rollbacks

Build-Workflow (Beispiel)

.gitea/workflows/runner-java-build.yml im docker-builds-Repo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
name: Runner Java 25 Image Build

on:
  workflow_dispatch:
  push:
    paths:
      - 'runner-java/**'
  schedule:
    - cron: '15 2 * * 4'  # Donnerstag 02:15 UTC

jobs:
  build:
    runs-on: java-25-builder   # Label auf deinem Build-Runner (docker-CLI im Job-Image!)
    strategy:
      matrix:
        include:
          - base: runner-java/ubuntu-26.04
            tag: ubuntu-26.04
          - base: runner-java/oraclelinux-9
            tag: oraclelinux-9
    steps:
      - uses: https://gitea.rwcloud.ch/actions/checkout@v4

      - name: Login to Registry
        run: |
          echo "${{ secrets.BUILDUSER_AUTHTOKEN }}" | docker login gitea.rwcloud.ch -u "${{ secrets.BUILDUSER_USERNAME }}" --password-stdin

      - name: Build and push
        run: |
          IMG="gitea.rwcloud.ch/homelab/runner-java-25-${{ matrix.tag }}"
          # Versionstag nur bei push/dispatch, nicht bei schedule (sonst 1 Tag pro Woche)
          PUSH_VERSION_TAG=""
          [ "$GITHUB_EVENT_NAME" != "schedule" ] && PUSH_VERSION_TAG="$GITHUB_RUN_NUMBER"

          TAGS="-t $IMG:latest"
          [ -n "$PUSH_VERSION_TAG" ] && TAGS="$TAGS -t $IMG:$PUSH_VERSION_TAG"

          docker build -f "${{ matrix.base }}/Dockerfile" \
            --build-arg JAVA_VERSION=25 \
            --build-arg KOTLIN_VERSION=2.1.20 \
            --build-arg MAVEN_VERSION=3.9.9 \
            $TAGS \
            .
          docker push "$IMG:latest"
          [ -n "$PUSH_VERSION_TAG" ] && docker push "$IMG:$PUSH_VERSION_TAG"

Beachte: - runs-on: java-25-builder muss ein Label sein, dessen docker://-Image docker-CLI enthält (basic-Runner hat kein). - actions/checkout@v4 wird hier über eine absolute URL angepumpt, damit er von deiner Gitea kommt, nicht von github.com (dafür muss die Action dort gemirrorrt sein – DEFAULT_ACTIONS_URL=self ist optional, aber sinnvoll).

Actions ohne github.com

Gitea lädt uses: actions/checkout@v4 per Default von github.com. Für ein volles internes Setup brauchst du:

1. Actions auf eigene Gitea spiegeln

Einmaliges Setup via Gitea Mirror-Repositories:

1
2
3
4
5
6
7
8
9
# für jede benutzte Action ein Mirror anlegen:
tea repos create --mirror \
  --remote-url "https://github.com/actions/checkout" \
  actions/checkout

tea repos create --mirror --remote-url "https://github.com/actions/upload-artifact" \
  actions/upload-artifact

# … usw. für jede Action, die in Workflows steht

Gitea zieht bei jedem push/pull automatisch die neue Version (sofern Enable mirror sync aktiviert).

2. Gitea-Server-Setting

In app.ini:

1
2
3
4
[actions]
ENABLED = true
; "self" = nur von eigener Gitea, "github" = von github.com (Default)
DEFAULT_ACTIONS_URL = self

3. Optional: absolute uses:-URLs

Wenn du für eine Action ganz sicherstellen willst, dass sie lokal kommt (unabhängig vom DEFAULT_ACTIONS_URL):

1
- uses: https://gitea.rwcloud.ch/actions/checkout@v4

4. Registry-Login ohne docker/login-action

docker/login-action@v3 ist eine JS-Action (kommt von github.com). Alternativen, die komplett intern sind:

a) Direkter run:-Step (einfachste, empfohlene Variante):

1
2
3
4
- name: Login to Registry
  env:
    REGISTRY_PW: ${{ secrets.BUILDUSER_AUTHTOKEN }}
  run: echo "$REGISTRY_PW" | docker login gitea.rwcloud.ch -u "${{ secrets.BUILDUSER_USERNAME }}" --password-stdin

Voraussetzung: das runs-on-Label zeigt auf ein Job-Image, das docker-CLI + /var/run/docker.sock bind-mounted hat (bei basic-Runner ist der Socket bereits verfügbar; docker-CLI muss im Job-Image sein).

b) container.env im Workflow (secrets, die nur beim Login gebraucht werden):

1
2
3
4
5
6
7
8
jobs:
  build:
    runs-on: java-25
    container:
      env:
        REGISTRY_PW: ${{ secrets.BUILDUSER_AUTHTOKEN }}
    steps:
      - run: echo "$REGISTRY_PW" | docker login gitea.rwcloud.ch -u builder --password-stdin

c) runner.hooks.job_started (wenn es bei jedem Job passieren soll):

Wichtig: Hooks laufen wo die Steps laufen – im Job-Container bei docker://-Labels, auf dem Host bei host-Labels. Ein docker login braucht docker-CLI im Job-Image:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# runner config.yaml
runner:
  hooks:
    job_started: |
      set -e
      # docker-CLI im Job-Image vorausgesetzt + REGISTRY_PW via container.env gesetzt
      if [ -n "$REGISTRY_PW" ]; then
        echo "$REGISTRY_PW" | docker login "$REGISTRY_HOST" -u "$REGISTRY_USER" --password-stdin
      fi
      # zusätzlich: ::add-mask:: für Secrets, die im Job-Leak landen
      [ -n "$SECRET_TO_MASK" ] && echo "::add-mask::${SECRET_TO_MASK}"
    job_completed: |
      # cleanup, logrotate (im Job-Kontext)
      true

Kein docker login ohne docker-CLI im Job-Image. Wenn's dein Job-Image nicht hat, verwende (a) oder (b) mit einem Builder-Image, das docker-CLI enthält.

Auto-Patching: der Mechanismus

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 Renovate (PR im docker-builds-Repo)
   │ JAVA_VERSION, KOTLIN_VERSION …
   ▼
 Gitea-Workflow (push auf Dockerfile-Änderung + wöchentlicher Cron)
   │ docker build + push → gitea.rwcloud.ch
   ▼
 Gitea-Registry (neues :latest, altes :N bleibt als Rollback)
   ▼
 Host Docker-daemon (hat das Image im Local Cache)
   ▼
 Runner job (nutzt `label:docker://...:latest` → nutzt den Cache)
   ▼
 Problem: Runner job bekommt ALLEIN das neue Image,
          wenn der Local Cache es noch hat → OK.
 Problem: Der Cache kann ALTE Jobs mit ALTEM Image haben
          (z. B. der Runner wurde down, neu aufgesetzt, …).
   ▼
 Lösung: `runner.post_task_script` pruned den Cache periodisch
          + der Runner job zieht beim Start immer `latest`

Cache-Prune via post_task_script

Runner unterstützt ein optionales Skript, das nach jedem Job-Cleanup läuft – perfekt für docker image prune:

Im Ansible-Inventory (group_vars):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
gitea_runners:
  - name: runner-1
    token: !vault |
      $ANSIBLE_VAULT;1.2;AES256;rwcloud
      <…>
    tags:
      - java-25:docker://gitea.rwcloud.ch/homelab/runner-java-25-ubuntu-26.04:latest
      - ubuntu-latest:docker://gitea.rwcloud.ch/homelab/runner-builder:latest
    post_task_script_body: |
      #!/bin/sh
      set -e
      docker image prune -f 2>/dev/null || true
      docker container prune -f 2>/dev/null || true
      docker network prune -f 2>/dev/null || true
      docker builder prune -f 2>/dev/null || true
    post_task_script_timeout: 5m
    state: present

Die Rolle schreibt das Skript nach /etc/gitea-runner/<name>/post-task.sh, mountet es read-only in den Runner-Container unter /usr/local/bin/gitea-post-task.sh und setzt in der config.yaml automatisch:

1
2
3
4
runner:
  # … labels etc.
  post_task_script: /usr/local/bin/gitea-post-task.sh
  post_task_script_timeout: 5m

Wichtig: Während post_task_script läuft, meldet sich der Runner nicht bei Gitea (Heartbeat pausiert). Das Skript braucht docker-CLI in der Runner-Umgebung – basic-Flavour hat keins, also dafür gitea/runner:latest-dind oder ein Custom-Image mit Docker-CLI wählen. Ein 2>/dev/null || true am Ende jeder Zeile hält das Skript robust, falls der Daemon nicht erreichbar ist.

Renovate-Trigger im docker-builds-Repo

In renovate.json (ergänzend zum Bestehenden):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:base"],
  "customManagers": [
    {
      "customType": "regex",
      "fileMatch": ["^runner-java/.*Dockerfile$"],
      "matchStrings": [
        "ARG\\s+JAVA_VERSION\\s*=\\s*(?<currentValue>[^\\s]+)\\s*$",
        "ARG\\s+KOTLIN_VERSION\\s*=\\s*(?<currentValue>[^\\s]+)\\s*$"
      ],
      "datasourceTemplate": "github-releases"
    }
  ]
}

→ Renovate erstellt PRs mit JAVA_VERSION = 26 oder KOTLIN_VERSION = 2.2.0. Merge → Workflow-Triggert → neuer Build → latest aktualisiert.

Ansible-Rolle gitea_runner – Nutzung

Die Rolle legt pro Runner config.yaml, das Volume und den Container an. Die Labels kommen aus gitea_runners:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# playbooks/proxmox/group_vars/gitea_runner.yml
gitea_runners:
  - name: runner-1
    token: !vault |
      $ANSIBLE_VAULT;1.2;AES256;rwcloud
      <…>
    tags:
      # Name ist was in `runs-on:` steht. docker://Image ist was ausgeführt wird.
      - java-25:docker://gitea.rwcloud.ch/homelab/runner-java-25-ubuntu-26.04:latest
      - java-25-oracle:docker://gitea.rwcloud.ch/homelab/runner-java-25-oraclelinux-9:latest
      - ansible:docker://gitea.rwcloud.ch/my-repos/ansible-runner
      - shell:host
    state: present

  - name: runner-2
    token: !vault |
      <…>
    tags:
      - ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-24.04
      - linux-amd64:host
    state: present

Workflow dann:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# .gitea/workflows/build-vadn.yml
name: Vaadin Build
on: [push, pull_request, workflow_dispatch]
jobs:
  build:
    runs-on: java-25   # ← nutzt das Java-25-Ubuntu-26.04 Image
    steps:
      - uses: https://gitea.rwcloud.ch/actions/checkout@v4
      - run: mvn -B -ntp clean verify
      - run: mvn -ntp vaadin:build-frontend
      - run: avh version   # gitflow-avh ist im Image

Häufige Stolpersteine

Problem Ursache Fix
Job läuft auf Host, nicht in Image Label ohne docker:// java-25:docker://…
actions/checkout lädt von github.com DEFAULT_ACTIONS_URL fehlt [actions] DEFAULT_ACTIONS_URL=self + Mirror
Java im Job fehlt setup-java nicht im Image Temurin im Dockerfile
Cache hängt an alten Images fest Local Daemon-Cache + latest post_task_script_body → docker image prune
Runner nimmt neue Labels nicht an .runner-Datei hat alte Labels in config.yaml + config re-write bei Start, oder .runner neu register
uses:-Action gibt 404 Mirror fehlt / DEFAULT_ACTIONS_URL=github Mirror anlegen oder absolute URL
docker build im Job nicht möglich Basic-Runner ohne Daemon /var/run/docker.sock bind-montiert, oder dind-Flavour

Weiterführende Quellen

Checklist beim Onboard neuer Workflows

  • [ ] gitea_runners (Ansible) enthält Label mit docker://<dein-image>
  • [ ] Das Image ist in gitea.rwcloud.ch gebaut (Build-Workflow + Registry)
  • [ ] Workflows nutzen runs-on: <label> (nacktes Wort = runs-on-Match)
  • [ ] Keine uses: actions/*-Actions, die nicht in gitea.rwcloud.ch gemirrorrt sind
  • [ ] app.ini hat DEFAULT_ACTIONS_URL = self
  • [ ] post_task_script_body im Ansible-Runner gesetzt (optional, empfohlen)
  • [ ] Renovate-Repo für das Image aktiviert