This commit is contained in:
parent
92f2427e08
commit
c6ecfe0d34
1 changed files with 187 additions and 0 deletions
187
content/blog/ansible/forgejo-runner.md
Normal file
187
content/blog/ansible/forgejo-runner.md
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
---
|
||||||
|
title: 'Deploying a forgejo runner with ansible'
|
||||||
|
description: 'Some ansible code and a golden rule'
|
||||||
|
date: '2025-04-08'
|
||||||
|
tags:
|
||||||
|
- 'ansible'
|
||||||
|
- 'forgejo'
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
After [migrating my git.adyxax.org to forgejo]({{< ref "forgejo.md" >}}) a few
|
||||||
|
weeks back, I started experimenting with their CI offering: forgejo actions. It
|
||||||
|
is mostly a clone of GitHub actions, which means it is a mixed bag.
|
||||||
|
|
||||||
|
I am still relying on [eventline](https://www.exograd.com/products/eventline)
|
||||||
|
for all the important stuff I manage, but I wanted to get the actions
|
||||||
|
integration for some simple and non consequential CI jobs.
|
||||||
|
|
||||||
|
## The good and the bad
|
||||||
|
|
||||||
|
The good part is obviously the tight integration with forgejo's UI. Forgejo (or
|
||||||
|
gitea which forgejo forked from) developers also made the great decision of
|
||||||
|
adding runners dedicated to individual users, which allows me to open my forgejo
|
||||||
|
instance to other people without offering them access to a runner.
|
||||||
|
|
||||||
|
The bad part all has to do with trying to be a GitHub actions clone:
|
||||||
|
- The reliance on nodejs actions for everything.
|
||||||
|
- The non case sensitivity in weird places (the most damning example in my eyes
|
||||||
|
being `if: ${{ github.ref == 'refs/heads/main' }}` which looks like an
|
||||||
|
equality check, but it will match any case variation of `MaIn`).
|
||||||
|
- It is YAML soup, and workflow reuse is clunky at best.
|
||||||
|
|
||||||
|
## The golden rule
|
||||||
|
|
||||||
|
I find that the following golden rule applies to all CIs: avoid building any
|
||||||
|
actual logic into your workflows outside of the simple orchestration of the
|
||||||
|
tasks. [Here is an
|
||||||
|
example](https://git.adyxax.org/adyxax/www/src/branch/main/.forgejo/workflows/main.yaml)
|
||||||
|
workflow that illustrates this rule.
|
||||||
|
|
||||||
|
As you can see, I use simple (and often one liner) build, test or deploy
|
||||||
|
commands that call a Makefile to do the heavy lifting. This guarantees that I am
|
||||||
|
always able to build or deploy locally as well as debug more easily my
|
||||||
|
workflows.
|
||||||
|
|
||||||
|
## Making do without the runner containers
|
||||||
|
|
||||||
|
I greatly dislike the default forgejo runner containers: They package everything
|
||||||
|
and the kitchen sink, which is necessary given how clunky the whole nodejs
|
||||||
|
ecosystem is (which the actions rely on).
|
||||||
|
|
||||||
|
Fortunately I can do without these runner containers. The documentation will
|
||||||
|
warn about its dangers and I caution you too if you plan to follow in my
|
||||||
|
footsteps: You need to manage the proper isolation yourself and take care of not
|
||||||
|
making a mess of the host operating system!
|
||||||
|
|
||||||
|
Managing the proper isolation is not hard: instead of letting forgejo runner
|
||||||
|
spawn its own containers, I myself run it constrained inside either a container
|
||||||
|
or a jail.
|
||||||
|
|
||||||
|
Not making a mess of the host operating system requires discipline though
|
||||||
|
because the runner environment does not get cleaned on each run. Since I write
|
||||||
|
my workflows and actions myself and follow the previously mentioned golden rule,
|
||||||
|
with some discipline and experience I make it work.
|
||||||
|
|
||||||
|
## Ansible role
|
||||||
|
|
||||||
|
### Tasks
|
||||||
|
|
||||||
|
Here is an example `tasks.yaml` that deploys the forgejo runner on a Debian
|
||||||
|
system. It does not configure the runner itself, that I do manually once after
|
||||||
|
the first deployment.
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
---
|
||||||
|
- name: 'Install forgejo-runner dependencies'
|
||||||
|
package:
|
||||||
|
name:
|
||||||
|
- 'git-crypt'
|
||||||
|
- 'hugo'
|
||||||
|
- 'nodejs'
|
||||||
|
|
||||||
|
- name: 'Download forgejo runner {{ versions.forgejo_runner.tag }}'
|
||||||
|
get_url:
|
||||||
|
url: 'https://code.forgejo.org/forgejo/runner/releases/download/v{{ versions.forgejo_runner.tag }}/forgejo-runner-{{ versions.forgejo_runner.tag }}-linux-amd64'
|
||||||
|
dest: '/usr/local/bin/forgejo-runner'
|
||||||
|
mode: '0555'
|
||||||
|
notify: 'restart forgejo runner'
|
||||||
|
|
||||||
|
- name: 'Create forgejo-runner group on server'
|
||||||
|
group:
|
||||||
|
name: 'forgejo-runner'
|
||||||
|
system: 'yes'
|
||||||
|
|
||||||
|
- name: 'Create forgejo-runner user on server'
|
||||||
|
user:
|
||||||
|
name: 'forgejo-runner'
|
||||||
|
group: 'forgejo-runner'
|
||||||
|
shell: '/bin/sh'
|
||||||
|
home: '/srv/forgejo-runner'
|
||||||
|
createhome: 'yes'
|
||||||
|
system: 'yes'
|
||||||
|
password: '*'
|
||||||
|
|
||||||
|
- name: 'Deploy forgejo systemd service unit'
|
||||||
|
copy:
|
||||||
|
src: 'forgejo-runner.service'
|
||||||
|
dest: '/etc/systemd/system/'
|
||||||
|
owner: 'root'
|
||||||
|
group: 'root'
|
||||||
|
mode: '0440'
|
||||||
|
notify: 'systemctl daemon-reload'
|
||||||
|
|
||||||
|
- name: 'Start forgejo-runner and activate it on boot'
|
||||||
|
service:
|
||||||
|
name: 'forgejo-runner'
|
||||||
|
enabled: true
|
||||||
|
state: 'started'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Handlers
|
||||||
|
|
||||||
|
This role relies on two handlers:
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
---
|
||||||
|
- name: 'restart forgejo runner'
|
||||||
|
service:
|
||||||
|
name: 'forgejo-runner'
|
||||||
|
state: 'restarted'
|
||||||
|
|
||||||
|
- name: 'systemctl daemon-reload'
|
||||||
|
shell:
|
||||||
|
cmd: 'systemctl daemon-reload'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Files
|
||||||
|
|
||||||
|
Here is my `forgejo-runner.service` systemd unit file:
|
||||||
|
|
||||||
|
``` ini
|
||||||
|
###############################################################################
|
||||||
|
# \_o< WARNING : This file is being managed by ansible! >o_/ #
|
||||||
|
# ~~~~ ~~~~ #
|
||||||
|
###############################################################################
|
||||||
|
[Unit]
|
||||||
|
Description=Forgejo Runner
|
||||||
|
Documentation=https://forgejo.org/docs/latest/admin/actions/
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=forgejo-runner daemon
|
||||||
|
ExecReload=/bin/kill -s HUP $MAINPID
|
||||||
|
User=forgejo-runner
|
||||||
|
WorkingDirectory=/srv/forgejo-runner
|
||||||
|
Restart=on-failure
|
||||||
|
TimeoutSec=0
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual runner registration
|
||||||
|
|
||||||
|
There is an offline registration mechanism, but I did not attempt to use it.
|
||||||
|
Since this is not an action I will redo often, I am content with running once:
|
||||||
|
|
||||||
|
``` shell
|
||||||
|
su - forgejo-runner
|
||||||
|
forgejo-runner register
|
||||||
|
--instance https://git.adyxax.org \
|
||||||
|
--labels self-hosted:host://-self-hosted \
|
||||||
|
--name myth.adyxax.org \
|
||||||
|
--token XXXXXXXXXXX \
|
||||||
|
--no-interactive
|
||||||
|
exit
|
||||||
|
systemctl restart forgejo-runner
|
||||||
|
```
|
||||||
|
|
||||||
|
The registration token comes from my user settings page at
|
||||||
|
https://git.adyxax.org/user/settings/actions/runners/.
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
It works well, for now I am happy with it.
|
Loading…
Add table
Reference in a new issue