Set up a Private GitLab Runner on Alpine Linux

Published: Saturday, Jan 29, 2022
Last modified: Sunday, Jan 30, 2022 (9285cfa)

GitLab has recently locked down the accessibility to free CI/CD minutes. You now need to provide a Credit Card to prove you’re a human. Apparently cryptofriends were using the CI/CD minutes to mine for cryptocurrencies. Huh… if I had lesser ethics I’d probably do the same thing! Kind of brilliant to be honest. Anyway, the end result is if you want users to contribute to your project they need to either provide a CC or better yet, you can set up private GitLab runners. Just make sure to disable usage of shared runners, or they’ll continue to get the CC nag, and their builds will autofail.

Another reason to use your own GitLab runners is they’ll probably be faster than the shared runners. Additionally if you have private GitLab projects, your CI/CD minutes are numbered.

§BTW - Here’s an Ansible playbook

Figure 1: screenshot demonstrating success using the playbook

Figure 1: screenshot demonstrating success using the playbook

I wrote a short playbook based off of the steps outlined below. You can check it out here:

§Set up the community repository

Edit /etc/apk/repositories. Uncomment the line that looks like This is needed for installing the needed software.

§Install docker

First you have to install docker and start it up:

apk add docker  # Install docker
rc-service docker start  # Start the service
rc-update add docker  # Start the service on subsequent boots

§Install GitLab runner

Next let’s install the gitlab-runner program. shadow which contains gpasswd which is a simple way to add a user to a group.

apk add gitlab-runner  # Install gitlab-runner
apk add shadow  # Needed for 'gpasswd'.

Next add the gitlab-runner user to the docker group.

gpasswd -a gitlab-runner docker

Register the GitLab Runner. You’ll need to specify a default docker image. I usually do alpine:latest, but it shouldn’t matter because the image should be specified in your .gitlab-ci.yml for maximum clarity. You will also need the registration token from your GitLab project’s CI/CD page. You can find it by clicking on Settings -> CI/CD -> expand “Runners”. This is also where your runners will be listed.

gitlab-runner \
     --non-interactive \
     --run-untagged \
     --url \
     --executor docker \
     --name 'name to identify your runner in the gitlab UI' \
     --docker-image alpine:latest \
     --registration-token your-registration-token-here

Now fix the permissions. It appears this file is not readable by the gitlab-runner user (though alpine does set this user up to utilize this file - weird!). Let’s change it so it belongs to the gitlab-runner group and is readable by that group:

chgrp gitlab-runner /etc/gitlab-runner
chmod 0750 /etc/gitlab-runner
chgrp gitlab-runner /etc/gitlab-runner/config.toml
chmod 0640 /etc/gitlab-runner/config.toml

Optional, add syslog logging. Add --syslog to your /etc/conf.d/gitlab-runner. The file should look like the following:

# Extra options passed to 'gitlab-runner run'
GITLAB_RUNNER_OPTS="--config /etc/gitlab-runner/config.toml --working-directory /var/lib/gitlab-runner --service gitlab-runner --syslog"

# Change to root if you want to run a system instance instead of a user one
# Same as above

Next, let’s start and enable the runner

rc-service gitlab-runner start
rc-update add gitlab-runner

§Now test if it works!

  1. Test if the runner is visible on the page where the registration token can be found (Runner settings).

  2. Trigger a gitlab CI job with the new runner.


Edit /etc/init.d/gitlab-runner. Add --debug --syslog between the “run” subcommand and the gitlab-runner program. So the relevant line should look like this:

command_args="--debug run --syslog ${GITLAB_RUNNER_OPTS}"

Now you can check /var/log/messages for errors.

§Final remarks

It’s a good idea to use a VM server to deploy a gitlab runner that can use docker. This way you can contain a lot of the security concerns to a single VM guest. You also do not need to expose your guest to the internet or even the local LAN - it only needs to dial out via a NAT.

Another cool thing learned when working on this is one can use the community.libvirt.libvirt_qemu connection plugin to manage guests without even needing SSH access or credentials. This uses the qemu guest agent, bypassing the need for suitable networking to manage guests.

Stay tuned for more infrastructure posts.

<< Previous post
Next post >>