🗙 Gitea Actions - Jekyll Workflow

6 minute read

After setting up my own little server in this project and adding all necessary applications to serve my blog, I now want to automatically build, integrate, and deploy.

Desired outcome

This is how I want it to be: When my Gitea instance detects a git push to the remote origin of my blog’s repository, I want an action runner to start a Docker container. That container shall load Ruby, Bundler, Jekyll, and all other required dependencies. Then it shall checkout the blog’s source files and then run the bundle exec jekyll build command. When its output is ready in the _site folder, I want the runner to self-terminate and to free all occupied resources.

At this point I’d like to manually check my blog’s integrity, maybe also add some automated checks like detecting broken links or similar.

Finally, I want to be able to have the site deployed and thus made available to the public with another simple command.

Starting point: Github Actions

As usual, I first search other people’s solutions for the same problem. I found the Github Actions starter-workflows Repository, created by Github themselves, and copied most of it into my action as a first shot:

# 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
#[...]

After uploading this workflow to my blog at workflows/jekyll.yml, the runner indeed started its work:

Image: Gitea action runner returns error on ruby install

Problems installing Ruby

That was a quick win. On the other hand, the runner wasn’t even able to successfully install Ruby. Here’s the corresponding log:

::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

The error message looks reasonable and is well-placed.

Background: My runner operates in Docker which uses a stripped-down Debian image named node:16-bullseye (Referenz). Looks like it is incompatible with the Github Actions Runner which executes atop Ubuntu22.

There are quite some options to resolve:

Troubleshooting options

  • Run the runner on Ubuntu22, use labels for that.
  • Don’t use Docker but have the runner operate on the host’s operating system
  • Use prebuilt Ruby, installed in the runner’s cache
  • Use an out-of-the-box Jekyll-Dockerimage to not require additional installation steps

Operate the runner with Ubuntu22 instead of Node16

There is a matching Dockerimage, but it will take a lot more disk space and RAM than a minimalistic one. Plus, it takes a little more time until it is live. Let’s see whether there is a more simple solution.

Run the runner on the host’s operating system

This has considerable security drawbacks as unprotected branches might allow third-party injected runners via git push --force. In an extreme case, it would blindly execute malware right on my server system. In addition, I’d kill portability by hardwiring the runner to a machine’s OS.

Use pre-built Ruby in runner toolcache

As proposed by the error message, I followed another manual to map a volume containing prebuilt ruby on my host using Gitea’s docker-compose.yml. In addition, I assigned the targeted folder to the RUNNER_TOOL_CACHE environment variable:

# 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

Here, I map the host’s filesystem path /opt/hostedtoolcache to Docker’s /opt/hostedtoolcache. Docker creates the folders automatically “on both sides” if they are not yet existing on next docker compose up.

Let’s try to install Ruby on the host machine.

So I download the ruby-build repository via git clone and have the installer run ./ruby-build/install.sh. Then, I execute the build with the requested target path from the error message: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)

Problems with prebuilt-Ruby

The logs shows the problem:

[...] No C compiler found, please specify one with the environment variable CC [...]

So I type apt install build-essential and confirm with which gcc that I now have a C compiler installed at /usr/bin/gcc Let’s try again!

crypto/comp/c_zlib.c:36:11: fatal error: zlib.h: No such file or directory

Hmm, let’s load it via apt install libz-dev and re-run the insall. This time it takes a while, then:

*** 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, openssl this time. Get it with apt install libssl-dev and apt install libreadline-dev and finally :

Installed ruby-3.1.4 to /opt/hostedtoolcache/Ruby/3.1.4/x64

!🎉!

Still no success with the action

Strange, it is the same error all over again:

💬  ::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

This results from the following Action code:

//  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

Not 100% sure but the fact that the Action cannot find Ruby in the toolcache could be due to two things:

  1. I didn’t mount the volume to the Action, but to the runner (where I still need to check if it is available to the Action at runtime)
  2. I did not add the toolcache path to the runner configuration’s valid_volumes list. According to a pull request thread it is auto-added, though. Still, I’m not sure if that information is outdated as I’m migrating at a phase where the runner is in active development.

Docker volume überprüfen

Hmpf. Let’s see whether Ruby is really available in that volume. To do this, I use docker ps to get the runner’s container ID and enter it here:

docker exec -it <containerID> bash

Then I navigate to cd /opt/hostedtoolcache, list its contents with ls and there it is: Ruby. It is there but still cannot be found in the Action.

Accept my failure

No way to proceed for me at this point 😖. I opened this problem to the community as act_runner cannot find hostedtoolcache and will try

Another option.

Root cause

Looks like the support of setup-ruby action for self-hosted runners like mine might have been discontinued. Maybe the documentation, creating the above error message, has not been updated accordingly.