Just lately, I discussed how I refactored the script that stored my GitHub profile up-to-date. Since Geecon Prague, I am additionally a contented proprietor of a Raspberry Pi:
Although the present setup works flawlessly — and is free, I needed to experiment with self-hosted runners. Listed below are my findings.
Context
GitHub presents a big free utilization of GitHub Actions:
GitHub Actions utilization is free for traditional GitHub-hosted runners in public repositories, and for self-hosted runners. For personal repositories, every GitHub account receives a specific amount of free minutes and storage to be used with GitHub-hosted runners, relying on the account’s plan. Any utilization past the included quantities is managed by spending limits.
But, the coverage can simply change tomorrow. Free tier insurance policies present a daily development of shrinking down when:
- A big sufficient share of customers use the product, lock-in
- Shareholders need extra income
- A brand new finance supervisor decides to chop prices
- The worldwide economic system shrinks down
- A mixture of the above
Forewarned is forearmed. I wish to attempt choices earlier than I would like to decide on one. Living proof: what if I must migrate?
The Idea
GitHub Actions comprise two parts:
- The GitHub Actions infrastructure itself.
It hosts the scheduler of jobs. - Runners, who run the roles
By default, jobs run on GitHub’s runners. Nonetheless, it is doable to configure one’s job to run on different runners, whether or not on-premise or within the Cloud: these are known as self-hosted runners.
The documentation concerning learn how to create self-hosted runners offers all the required info to construct one, so I will not paraphrase it.
I seen two non-trivial points, although. First, when you have jobs in several repositories, you want to arrange a job for every repository. Runner teams are solely accessible for group repositories. Since most of my repos rely upon my common account, I am unable to use teams. Therefore, you need to duplicate every repository’s package deal on the runner’s Pi.
As well as, there isn’t any devoted package deal: you need to untar an archive. This implies there isn’t any option to improve the runner model simply.
That being stated, I anticipated the migration to be one line lengthy:
jobs:
replace:
#runs-on: ubuntu-latest
  runs-on: self-hosted
It’s kind of extra concerned, although. Let’s element what steps I needed to undertake in my repo to make the job work.
The Apply
GitHub Actions rely upon Docker being put in on the runner. Due to this, I assumed jobs ran in a devoted picture: it is plain fallacious. No matter you script in your job occurs on the working system. Living proof, the preliminary script put in Python and Poetry.
jobs:
replace:
runs-on: ubuntu-latest
steps:
- identify: Arrange Python 3.x
makes use of: actions/setup-python@v5
with:
python-version: 3.12
- identify: Arrange Poetry
makes use of: abatilo/actions-poetry@v2
with:
     poetry-version: 1.7.1
Within the context of a brief container created throughout every run, it is sensible; within the context of a secure, long-running system, it would not.
Raspbian, the Raspberry default working system, already has Python 3.11 put in. Therefore, I needed to downgrade the model configured in Poetry. It is no massive deal as a result of I do not use any particular Python 3.12 function.
[tool.poetry.dependencies]
python = "^3.11"
Raspbian forbids the set up of any Python dependency within the main setting, which is a really sane default. To put in Poetry, I used the common APT package deal supervisor:
sudo apt-get set up python-poetry
The subsequent was to deal with secrets and techniques. On GitHub, you set the secrets and techniques on the GUI and reference them in your scripts through setting variables:
jobs:
replace:
runs-on: ubuntu-latest
steps:
- identify: Replace README
run: poetry run python src/foremost.py --live
env:
BLOG_REPO_TOKEN: ${{ secrets and techniques.BLOG_REPO_TOKEN }}
     YOUTUBE_API_KEY: ${{ secrets and techniques.YOUTUBE_API_KEY }}
It permits segregating particular person steps so {that a} step has entry to solely the environmental variables it wants. For self-hosted runners, you set setting variables in an current .env
file contained in the folder.
jobs:
replace:
runs-on: ubuntu-latest
steps:
- identify: Replace README
    run: poetry run python src/foremost.py --live
If you’d like safer setups, you are by yourself.
Lastly, the structure is a pull-based mannequin. The runner consistently checks if a job is scheduled. To make the runner a service, we have to use out-of-the-box scripts contained in the runner folder:
sudo ./svc.sh set up
sudo ./svc.sh begin
The script makes use of systemd
beneath.
Conclusion
Migrating from a GitHub runner to a self-hosted runner will not be a giant deal however requires altering some bits and items. Most significantly, you’ll want to perceive the script runs on the machine. This implies you’ll want to automate the provisioning of a brand new machine within the case of crashes. I am contemplating the advantages of working the runner inside a container on the Pi to roll again to my earlier steps. I would be blissful to listen to in the event you discovered and used such an answer. In any case, I am not migrating any extra jobs to self-hosted for now.