GitHub Runner as container (Docker) using Moonrepo task as launcher
One command to set up a runner and handle jobs
Prerequisites
- Full understanding of Moonrepo tasks system (and a Moon project) (moonrepo.dev)
- Full understanding of GitHub Actions (And a repository, with the Moon project inside; obvious? Just saying ๐)
- Full understanding of Docker (and Docker installed; did you guess it?)
- Basic knowledge of bash/sh scripting
What is the goal?
The goal is to be able to launch a GitHub Runner as a container from any development computer (running Docker). Additionally, integrate it inside a Moonrepo monorepo repository (๐ค) and have a task to launch it (or them) locally.
And because it's fun to start playing with monorepos and see how helpful those tools are when running in CI.
At Alpsify, we work with a monorepo powered by Moonrepo. We launch self-hosted GitHub Runners on local machines because we can't afford big Kubernetes clusters to auto-scale a fleet of runners. So, we have a fleet of approximately 5 runners across our computers. It's like free CPU time, as our computers never hit the limit and are always on during working time. It's just our way of doing it to save costs.
Note: This approach is not a perfect fit for everyone. We're just sharing something that works for us and may work for others.
GitHub Runner as a Container
Create a folder inside your Moonrepo repository (๐ฎโ๐จ) and name it as you wish. I'll refer to it as <project-name>
afterwards.
Register it in your .moon/workspace.yml
if needed (depends on your config).
This part is inspired by a discussion on GitHub (https://github.com/actions/runner/issues/367#issuecomment-1507331413)
Create a Dockerfile inside <project-name>
# <project-name>/Dockerfile
FROM ghcr.io/actions/actions-runner:latest
RUN sudo apt update -y && sudo apt install build-essential git curl -y #(whatever you need)
COPY ./runner.sh .
RUN sudo chmod +x runner.sh
CMD ["./runner.sh"]
Create the runner.sh
file inside
# <project-name>/runner.sh
#!/bin/sh
./config.sh --url https://github.com/<repo-name> --token $TOKEN --name $NAME --unattended
./run.sh
At this step, you can actually run your first GitHub Runner:
Inside your <project-name>
folder, run docker build --no-cache -t docker/github-runner
. to build your image.
Then run docker run docker/github-runner
.
Don't forget to replace $TOKEN
or $NAME
with the actual values. You can find your $TOKEN
at this link: github.com//settings/actions/runners/new. Don't replace it inside the runner.sh
as it's going to be versioned. And believe me, you don't want your private secret $TOKEN
to be versioned.
Moonrepo Task Configuration
Create a moon.yml
file inside <project-name>
folder
# <project-name>/moon.yml
...
project:
name: 'GitHub Runner in Docker'
description: 'GitHub Runner (as container) launcher'
...
tasks:
build:
command: 'docker build --no-cache -t docker/github-runner .'
platform: 'system'
local: true
run:
#-- -n -t
deps:
- 'build'
command: 'bash ./launch-container.sh'
platform: 'system'
local: true
Create the launch-container.sh
file
# <project-name>/launch-container.sh
#!/bin/bash
while getopts n:t: flag
do
case "${flag}" in
n) name=${OPTARG};;
t) token=${OPTARG};;
esac
done
docker run -d -e NAME=$name -e TOKEN=$token --name $name docker/github-runner
The --name $name
is to quickly identify which container it is (compared to GitHub Runner registration name). Sometimes you get errors, and you need to go deep into the details, so auto-generated names are not that useful in this kind of situation. ๐ฅน
Enjoy
Run the command moon <project-name>:run -- -t $TOKEN -n my-awesome-runner-1
(still need $TOKEN to be replaced)
Run it again with another name -n my-lovely-runner-1
! Voilร ! You got another one up and running, ready to take care of your CI jobs.
Don't forget to add runs-on: 'self-hosted'
in your .github/workflows/<whatever>.yml
file for your CI to use it.
Look at the page https://github.com/<your-repo-name>/settings/actions/runners and enjoy your new GitHub Runners! ๐ฅณ