šŸ—™ 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.