🗙 Gitea Actions - Jekyll Workflow
Nachdem ich in diesem Projekt meinen eigenen, kleinen Server aufgesetzt und mit den entsprechenden Programmen zum Hosten meines Blogs ausgestattet habe, möchte ich ihn nun in die Lage versetzen, die Website automatisch zu bauen.
Gewünschter Ablauf
Ich möchte folgendes erreichen: Sobald Gitea eine push
-Aktion auf dem Blog-Repository verzeichnet, soll ein Action Runner in einem eigenen Docker-Container loslaufen und Ruby, Bundler, Jekyll sowie sämtliche Abhängigkeiten nachladen. Dann soll der Runner meine Quelldateien für den Blog kopieren und dem bundle exec jekyll build
Prozess zur Verfügung stellen, welcher dann die Website baut und schließlich im _site
-Ordner ablegt. Anschließend soll der Runner sich selbst beenden und alle in Anspruch genommenen Ressourcen wieder freigeben.
An dieser Stelle möchte ich nachkontrollieren können, ob die Website fehlerfrei gebaut wurde und in Zukunft eventuell noch ein paar weitere Prüfungen darüberlaufen lassen - z.B. kaputte Links erkennen, nicht angezeigte Bilder markieren, Rechtschreibprüfung durchführen.
Die Freigabe sowie die Veröffentlichung soll dann ein anderer Prozess übernehmen, um den ich mich später kümmere.
Ausgangspunkt: Github Actions
Wie üblich wildere ich erst einmal bei anderen Menschen, die ein ähnliches Problem für sich bereits gelöst haben. Ich wurde im Github Actions starter-workflows Repository von Github selbst fündig und habe die Workflowdatei für Jekyll mit leichten Modifikationen direkt mal mit meiner Gitea-Instanz ausprobiert:
# jekyll-build-pages.yml
# Sample workflow for building and deploying a Jekyll site
name: Deploy Jekyll site
run-name: $ builds Jekyll site
on: [push]
jobs:
# Build job
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Ruby
uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
with:
ruby-version: '3.1' # Not needed with a .ruby-version file
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
cache-version: 0 # Increment this number if you need to re-download cached gems
#[...]
Nachdem ich diesen Workflow in mein Blogverzeichnis unter workflows/jekyll.yml
hochgeladen hatte, lief der Runner tatsächlich direkt los:
Probleme mit der Ruby-Installation
Schon mal prima. Allerdings wenig erbaulich, dass bereits bei der Installation von Ruby etwas nicht passt. Werfen wir einen Blick in die Logs:
::error::The current runner (debian-11-x64) was detected as self-hosted because the platform does not match a GitHub-hosted runner image
(or that image is deprecated and no longer supported).
In such a case, you should install Ruby in the $RUNNER_TOOL_CACHE yourself, for example using https://github.com/rbenv/ruby-build
You can take inspiration from this workflow for more details:
https://github.com/ruby/ruby-builder/blob/master/.github/workflows/build.yml
Na, das ist doch mal eine hilfreiche Fehlermeldung!
Der Runner läuft um Ressourcen zu sparen standardmäßig im Docker mit einem abgespeckten Image basierend auf Debian namens node:16-bullseye
(Referenz). Scheinbar ist dieser nicht kompatibel mit dem unter Ubuntu22 betriebenen Github Actions Runner. Ich habe also ein paar Lösungsmöglichkeiten zur Verfügung:
Möglichkeiten zur Fehlerbehebung
- Den Runner über seine “Labels” auf Ubuntu22.04 umsatteln.
- Ren Runner nicht im Docker, sondern nativ auf dem Server laufen lassen.
- Wie in der Fehlermeldung vorgeschlagen, Ruby im Cache des Runners vorinstallieren.
- Ein Jekyll-Dockerimage verwenden, welches Jekyll bereits im Gepäck hat und nicht erst die Installation benötigt.
Den Runner mit Ubuntu22 statt Node16 betreiben
Das entsprechende Dockerimage existiert zwar. Aber es kostet aber einen Haufen Speicherplatz auf meinem Server, benötigt durch seinen größeren Funktionsumfang mehr RAM und braucht vor allem länger, bis es hochgefahren ist.
Und Zeit ist bei Runnern wertvoll, schließlich will ich ja möglichst schnell wissen, ob das Bauen geklappt hat.
Den Runner direkt auf der Hostmaschine (Ubuntu22) laufen lassen
Ist sicherheitstechnisch nicht so sehr zu empfehlen (Bei einem ungeschützten Branch würde der Runner von Dritten per git push --force
hochgeschobenen Schadcode unbesehen auf meiner Hostmaschine ausführen) und zudem ginge die Portabilität flöten, weil ich das Zielsystem des Runners dann fest verdrahte.
Gitea act_runner direkt auf dem Host laufen lassen
Für den zweiten Ansatz habe ich mir per Anleitung eine Konfiguration für den runner
angelegt und darin das bestehende label-mapping so geändert, dass nicht mehr in Richtung Docker, sondern auf dem Ubuntu des Servers selbst gebaut wird. Dafür genügt es in meinem Fall, das Label ubuntu-latest:host
statt ubuntu-latest
in die Konfiguration zu schreiben. Leider erhielt ich hier Fehlermeldungen bei den Zugriffsrechten des Runners, welcher aus Docker heraus auf dem Hostsystem laufen müsste.
Nicht so schlimm, ich wollte diese Lösung wegen der oben beschriebenen möglichen Probleme sowieso nicht dauerhaft verwenden. Also investiere ich hier keine weitere Zeit.
Ruby im Cache vorinstallieren
Wie von der Fehlermeldung empfohlen habe ich dieser Anleitung folgend in der docker-compose.yml
von Gitea ein Volume angelegt für den Tool Cache des runners und das Zielverzeichnis in der Umgebungsvariable RUNNER_TOOL_CACHE
abgelegt.
# gitea/docker-compose.yml
# [...]
runner:
image: gitea/act_runner:nightly
environment:
- GITEA_INSTANCE_URL=<redacted>
- GITEA_RUNNER_NAME=<redacted>
- RUNNER_TOOL_CACHE=/opt/hostedtoolcache
- GITEA_RUNNER_REGISTRATION_TOKEN= <redacted>
volumes:
- ./runner/data:/data
- /opt/hostedtoolcache:/opt/hostedtoolcache
- /var/run/docker.sock:/var/run/docker.sock
Hiermit wird dem in Docker laufenden Runner der Ordner /opt/hostedtoolcache
im Dateisystem des Hosts unter dem Namen /opt/hostedtoolcache
zur Verfügung gestellt.
Nun probiere ich mal, Ruby direkt dort hinein zu installieren.
Also lade ich das ruby-build
repository herunter (git clone
) und lasse das Installerscript mit ./ruby-build/install.sh
durchlaufen.
Danach führe ich den Build mit dem in der Fehlermeldung angegebenen Pfad aus: ruby-build 3.1.4 /opt/hostedtoolcache/Ruby/3.1.4/x64
==> Downloading openssl-3.1.4.tar.gz...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 14.8M 100 14.8M 0 0 81.3M 0 --:--:-- --:--:-- --:--:-- 81.1M
==> Installing openssl-3.1.4...
BUILD FAILED (Ubuntu 22.04 on x86_64 using ruby-build 20231114)
Probleme mit prebuilt-Ruby
Das Log zeigt das Problem:
[...] No C compiler found, please specify one with the environment variable CC [...]
Also tippe ich apt install build-essential
und stelle dann mit which gcc
fest, dass er nun unter /usr/bin/gcc
installiert ist. Auf ein Neues!
crypto/comp/c_zlib.c:36:11: fatal error: zlib.h: No such file or directory
Dann schnell apt install libz-dev
eingeben und erneut probieren. Dieses mal läuft er recht lange, dann:
*** Following extensions are not compiled:
openssl:
Could not be configured. It will not be installed.
/tmp/ruby-build.20231205114312.9174.0gmhNf/ruby-3.1.4/ext/openssl/extconf.rb:100: OpenSSL library could not be found. You might Check ext/openssl/mkmf.log for more details.
readline:
Could not be configured. It will not be installed.
/tmp/ruby-build.20231205114312.9174.0gmhNf/ruby-3.1.4/ext/readline/extconf.rb:62: Neither readline nor libedit was found
Check ext/readline/mkmf.log for more details.
*** Fix the problems, then remove these directories and try again if you want.
[...]
OK, nun ist es openssl. Fix nachinstallieren mit apt install libssl-dev
sowie apt install libreadline-dev
und endlich 🎉:
Installed ruby-3.1.4 to /opt/hostedtoolcache/Ruby/3.1.4/x64
Noch immer Fehler beim Bauen mit dem Github-Acitons script
Merkwürdig, das Log spuckt mir immer noch denselben Fehler aus:
💬 ::debug::isExplicit: 3.1.4
gitea-runner-1 | [Deploy Jekyll site/build] 💬 ::debug::checking cache: /opt/hostedtoolcache/Ruby/3.1.4/x64
gitea-runner-1 | [Deploy Jekyll site/build] | ::debug::checking cache: /opt/hostedtoolcache/Ruby/3.1.4/x64
gitea-runner-1 | [Deploy Jekyll site/build] 💬 ::debug::not found
gitea-runner-1 | [Deploy Jekyll site/build] | ::debug::not found
gitea-runner-1 | [Deploy Jekyll site/build] ❗ ::error::The current runner (debian-11-x64) was detected as self-hosted
Das geht auf folgende Abfage in der ausführenden Action zurück:
// setup-ruby/ruby-builder.js
if (common.shouldUseToolCache(engine, version)) {
inToolCache = common.toolCacheFind(engine, version)
if (inToolCache) {
rubyPrefix = inToolCache
} else {
const toolCacheRubyPrefix = common.getToolCacheRubyPrefix(platform, engine, version)
if (common.isSelfHostedRunner()) {
const rubyBuildDefinition = engine === 'ruby' ? version : `${engine}-${version}`
core.error( [...] )
Update Jan-2024
Es es gibt zwei weitere Möglichkeiten dafür, dass der toolcache
nicht gefunden wird:
- Ich habe das Volume nicht der Action, sondern dem Runner zur Verfügung gestellt. Ich bin mir nicht sicher, dass die Daten auch in der Action verfügbar sind.
- Der
toolcache
-Pfad ist nicht in der Konfigurationsdatei des runners unter dem Eintragvalid_volumes
enthalten. Eine pull request Kommunikation lässt mich jedoch vermuten, dass dies automatisch passiert. Dennoch bin ich mir nicht 100% sicher, ob die Information noch dem Stand der Dinge entspricht.
Docker volume überprüfen
Mist. Prüfen wir schnell mal, ob Ruby in dem Volume auch wirklich verfügbar ist. Dafür suchen wir mit docker ps
die Container ID des runners heraus und geben sie bei folgendem Kommando ein:
docker exec -it <containerID> bash
Dann navigiere ich in den gesuchten Ordner cd /opt/hostedtoolcache
, liste dort den Inhalt mit ls
und siehe da: Ruby
. Es liegt also alles vor, nur wird es nicht gefunden.
Misserfolg anerkennen
So komme ich hier also nicht weiter 😖. Daher öffne ich mein Problem für die Community unter dem Titel act_runner cannot find hostedtoolcache und probiere
Problemursache
Der Support der Action setup-ruby
für selbsgehostete CI-Pipelines wie meinen act_runner
wurde wohl eingestellt. Die Dokumentation mit den Hinweisen zur Fehlerbehebung bei Verwendung selbstgehosteter Runner allerdings zum Zeitpunkt der Verwendung durch meine Wenigkeit war aber noch nicht auf Stand gebracht worden.