# Gitea-Actions-Runner einrichten Die Workflows unter `.gitea/workflows/` brauchen einen `act_runner`, der Docker erreichen kann. Diese Anleitung richtet ihn als Container auf `docker-srv001` ein. Sie ist vollständig – von der Tokenbeschaffung bis zur Fehlersuche. ## 1. Registrierungstoken holen Es gibt zwei Möglichkeiten: **Nur für dieses Repository** (empfohlen, wenn der Runner ausschließlich moneyfy bauen soll): 1. In Gitea das Repository `menzeljonas/moneyfy` öffnen. 2. *Settings → Actions → Runners* aufrufen. 3. **Create new Runner** anklicken. Gitea zeigt das Registrierungstoken an – eine Zeichenkette aus etwa 40 Zeichen. 4. Token kopieren. Es lässt sich nur einmal verwenden. **Instanzweit** (der Runner steht dann allen Repositories zur Verfügung): 1. Als Administrator anmelden. 2. *Site Administration → Actions → Runners* aufrufen. 3. Ebenfalls **Create new Runner**, Token kopieren. Falls Actions in der Instanz noch abgeschaltet sind, in der `app.ini` des Gitea-Servers ergänzen und Gitea neu starten: ```ini [actions] ENABLED = true ``` ## 2. Runner als Container betreiben Auf `docker-srv001` ein eigenes Verzeichnis anlegen: ```bash mkdir -p /opt/gitea-runner/data cd /opt/gitea-runner ``` `docker-compose.yml`: ```yaml name: gitea-runner services: act-runner: image: gitea/act_runner:0.2.11 container_name: gitea-act-runner restart: unless-stopped environment: GITEA_INSTANCE_URL: https://git.menzel.center GITEA_RUNNER_REGISTRATION_TOKEN: ${GITEA_RUNNER_REGISTRATION_TOKEN} GITEA_RUNNER_NAME: docker-srv001 # Muss zu den Labels in config.yaml passen. GITEA_RUNNER_LABELS: ubuntu-latest,ubuntu-22.04 CONFIG_FILE: /config.yaml volumes: # Der Runner startet die Job-Container über den Docker-Socket des Hosts. - /var/run/docker.sock:/var/run/docker.sock - ./config.yaml:/config.yaml:ro - ./data:/data ``` `.env` daneben: ```bash GITEA_RUNNER_REGISTRATION_TOKEN= ``` > Der gemountete Docker-Socket gibt dem Runner faktisch Root-Rechte auf dem Host. > Das ist für einen Runner, der eigene Images baut, üblich – betreibe ihn > deshalb nur mit vertrauenswürdigen Repositories. ## 3. `config.yaml` Im selben Verzeichnis anlegen: ```yaml log: level: info runner: file: /data/.runner capacity: 2 timeout: 3h # Die linke Seite ist das Label aus `runs-on`, rechts das Image, in dem der Job läuft. labels: - "ubuntu-latest:docker://node:20-bookworm" - "ubuntu-22.04:docker://node:20-bookworm" cache: enabled: true dir: /data/cache # Adresse, unter der die Job-Container den Cache-Server des Runners erreichen. # Leer lassen heißt: automatisch ermitteln. Bei mehreren Netzen hier die IP # des Hosts im Runner-Netz eintragen. host: "" port: 0 container: # Job-Container in dasselbe Netz hängen wie der Runner. network: bridge privileged: false # Nötig, damit `actions/cache` und `docker/build-push-action` Pfade einblenden dürfen. valid_volumes: - /data/cache docker_host: "-" # Bei selbstsigniertem Zertifikat auf true setzen, siehe Abschnitt 6. force_pull: false ``` `docker_host: "-"` bedeutet: den Socket des Runners an die Job-Container weiterreichen. Genau das braucht `build.yml`, um Images zu bauen. Starten: ```bash docker compose up -d docker compose logs -f ``` Beim ersten Start registriert sich der Runner und legt `/data/.runner` an. Ab dann wird das Registrierungstoken nicht mehr gebraucht. ## 4. Repo-Secret `REGISTRY_TOKEN` anlegen Der Build-Workflow lädt Images in die Gitea-Registry und braucht dafür ein Token mit Schreibrecht auf Pakete: 1. In Gitea auf *Benutzereinstellungen → Applications → Generate New Token*. 2. Namen vergeben, etwa `moneyfy-registry`. 3. Unter *Select permissions* bei **package** auf `Read and Write` stellen. 4. **Generate Token**, Wert kopieren – er wird nur einmal angezeigt. 5. Im Repository *Settings → Actions → Secrets → Add Secret*: - Name: `REGISTRY_TOKEN` - Wert: das kopierte Token Der Workflow meldet sich mit `${{ github.actor }}` an, also mit dem Benutzer, der den Lauf ausgelöst hat. Dieser Benutzer muss Schreibrecht auf die Pakete des Namensraums `menzeljonas` haben. ## 5. Verifikation 1. **Runner erscheint als „idle“:** in Gitea unter *Settings → Actions → Runners*. Dort stehen Name (`docker-srv001`), Labels und Status. 2. **Testworkflow läuft:** einen Commit auf einen beliebigen Branch schieben. Unter *Actions* muss `CI` starten und beide Jobs grün abschließen. 3. **Image landet in der Registry:** auf `main` pushen und danach `https://git.menzel.center/menzeljonas/-/packages` öffnen. Dort müssen `moneyfy-backend` und `moneyfy-frontend` mit den Tags `main` und `sha-` auftauchen. 4. **Versions-Tag prüfen:** ```bash git tag -a v0.1.0 -m "Erste Version" git push origin v0.1.0 ``` Danach müssen zusätzlich `0.1.0`, `0.1` und `latest` vorhanden sein. 5. **Image von Hand ziehen** (prüft nebenbei die Registry-Anmeldung): ```bash docker login git.menzel.center docker pull git.menzel.center/menzeljonas/moneyfy-backend:latest ``` ## 6. Fehlersuche ### `docker: command not found` im Job Das Job-Image bringt keinen Docker-Client mit. Zwei Wege: - In `config.yaml` sicherstellen, dass `docker_host: "-"` gesetzt ist – der Runner reicht dann seinen Socket weiter. - Für Jobs, die Docker brauchen, ein Image mit Client verwenden, etwa das Label `ubuntu-latest:docker://catthehacker/ubuntu:act-22.04`. Die Actions `docker/setup-buildx-action` und `docker/build-push-action` bringen den Rest mit. Prüfen lässt sich das mit einem Wegwerf-Schritt: ```yaml - run: docker version ``` ### Registry-Anmeldung schlägt mit selbstsigniertem Zertifikat fehl Meldung: `x509: certificate signed by unknown authority`. Auf dem Host das CA-Zertifikat hinterlegen und den Docker-Daemon neu starten: ```bash mkdir -p /etc/docker/certs.d/git.menzel.center cp menzel-center-ca.crt /etc/docker/certs.d/git.menzel.center/ca.crt systemctl restart docker ``` Zusätzlich muss der Runner-Container die CA kennen, weil buildx im Container läuft. Im Compose des Runners einblenden: ```yaml volumes: - /usr/local/share/ca-certificates/menzel-center-ca.crt:/usr/local/share/ca-certificates/menzel-center-ca.crt:ro ``` und im Runner einmalig `update-ca-certificates` ausführen. Ein gültiges Let's-Encrypt-Zertifikat auf dem Gitea-Host erspart diesen ganzen Abschnitt. ### `DOCKER_HOST` im DinD-Betrieb Wer statt des Host-Sockets einen Docker-in-Docker-Dienst betreibt, ergänzt diesen als zweiten Service und setzt im Runner: ```yaml environment: DOCKER_HOST: tcp://docker-in-docker:2376 DOCKER_CERT_PATH: /certs/client DOCKER_TLS_VERIFY: "1" volumes: - ./certs:/certs ``` In `config.yaml` dann `docker_host: tcp://docker-in-docker:2376`. DinD ist langsamer und der Schichten-Cache geht bei jedem Neustart verloren – der gemountete Host-Socket ist für ein Homelab die pragmatischere Wahl. ### Der Cache des Runners frisst Speicherplatz `/opt/gitea-runner/data/cache` und die Build-Schichten wachsen mit jedem Lauf. Belegung ansehen: ```bash du -sh /opt/gitea-runner/data/cache docker system df ``` Aufräumen: ```bash # Nicht mehr referenzierte Schichten und Build-Cache älter als eine Woche docker buildx prune --filter "until=168h" -f docker image prune -f # Cache-Verzeichnis des Runners leeren docker compose -f /opt/gitea-runner/docker-compose.yml down rm -rf /opt/gitea-runner/data/cache/* docker compose -f /opt/gitea-runner/docker-compose.yml up -d ``` Regelmäßig per Cron: ```cron 0 4 * * 0 docker buildx prune --filter "until=168h" -f >/dev/null 2>&1 ``` ### Job bleibt in „waiting“ hängen Die Labels stimmen nicht überein. `runs-on: ubuntu-latest` im Workflow braucht ein Label `ubuntu-latest` am Runner. Nach einer Änderung in `config.yaml` muss der Runner neu registriert werden: ```bash docker compose down rm data/.runner # neues Registrierungstoken in .env eintragen docker compose up -d ```