In this guide we will show you how you can run self-hosted Github Actions Runners on the cheap and with minimal maintenance using Gigahatch Managed Kubernetes, starting at just 4.87€ per month.
To follow along, you will need the following:
To start with, we need to create a cluster to run our runners. If you already have one, you can skip this step.
Create cluster
.Github Actions Runners
and choose a node size. For this example we will be using one replica of the smallest SharedI1 with 2 CPUs and 4GB RAM. If you need more power for your runners, or you would like to run multiple of them, you can use larger node sizes.Create Cluster
and wait a few minutes for your cluster to be created.After your cluster has finished creating, click the Get Kubeconfig
button. This will download a yaml
file that you need to connect to your cluster. Save it somewhere secure and open your terminal. Now you need to tell your kubectl
cli where to find this file. The easiest way is to set it as the KUBECONFIG
environment variable.
In bash this looks like so:
export KUBECONFIG='PATH_TO_YAML'
In powershell this looks like so:
$env:KUBECONFIG = "PATH_TO_YAML"
# Or if its in the current directory:
$env:KUBECONFIG = "$(Get-Location)\<NAME_OF_YAML>.yaml"
If you would rather not use the environment variable, you can pass it as the --kubeconfig
flag to the kubectl
cli.
For example:
kubectl --kubeconfig 'PATH_TO_YAML' get nodes
To check if you can access the cluster, run:
kubectl get nodes
You should now get a list of nodes like so:
NAME STATUS ROLES AGE VERSION
41488847-47e9-4f03-90df-7fb5f7f8e15f-l2ljs-qx8mf Ready <none> 37s v1.31.0+k3s1
9b43501b-f5d8-4cce-bdab-b5fdcb777325-control-plane-n67gv Ready control-plane,etcd,master 3m56s v1.31.0+k3s1
If this doesn’t work, try using the cli flag.
In this guide we will setup the runners for our whole organisation. If you want to restrict them to a single repo, please consult the official documentation about the differences.
To authenticate the runners with our Github organisation, we will create a Github App.
Your organizations
. (if you want to create the app in your personal account, click Settings
and skip the next step)Settings
on the organisation in the list you want to use.Developer settings
-> GitHub Apps
in the left menu bar.New GitHub App
.Gigahatch ARC
.https://github.com/actions/actions-runner-controller
as the Homepage URL
.Webhook
and deactivate the Active
checkbox.Permissions
, open Repository permissions
and select Metadata: Read-only
.Organization permissions
and select Self-hosted runners: Read and write
.Create GitHub App
.Now we need to install the app and note down the connection settings for our runners.
App ID
. We will need this a bit later.Private keys
, click Generate a private key
and save the .pem
file somewhere safe.Install app
and click Install
next to your organisation.https://github.com/organizations/ORGANIZATION/settings/installations/INSTALLATION_ID
. We will need this value later too.Now we can create the runners in the cluster. First, we need to install the helm charts with the Actions Runner Controller
(https://github.com/actions/actions-runner-controller). To do this, create the following two files:
arc.yaml
apiVersion: v1
kind: Namespace
metadata:
name: arc-system
---
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: arc
namespace: kube-system
spec:
chart: oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller
targetNamespace: arc-system
and
arc-runners.yaml
apiVersion: v1
kind: Namespace
metadata:
name: arc-runners
---
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: arc-runner-set
namespace: kube-system
spec:
chart: oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set
targetNamespace: arc-runners
valuesContent: |-
githubConfigUrl: https://github.com/<ORGANISATION> # <- Replace this with your organisation url
githubConfigSecret: pre-defined-secret
maxRunners: 5
minRunners: 1
template:
spec:
initContainers:
- name: init-dind-externals
image: ghcr.io/actions/actions-runner:latest
command: ["cp", "-r", "-v", "/home/runner/externals/.", "/home/runner/tmpDir/"]
volumeMounts:
- name: dind-externals
mountPath: /home/runner/tmpDir
containers:
- name: runner
image: ghcr.io/actions/actions-runner:latest
command: ["/home/runner/run.sh"]
env:
- name: DOCKER_HOST
value: unix:///var/run/docker.sock
volumeMounts:
- name: work
mountPath: /home/runner/_work
- name: dind-sock
mountPath: /var/run
- name: dind
image: docker:dind
args:
- dockerd
- --host=unix:///var/run/docker.sock
- --group=$(DOCKER_GROUP_GID)
- --mtu=1450
- --default-network-opt=bridge=com.docker.network.driver.mtu=1450
env:
- name: DOCKER_GROUP_GID
value: "123"
securityContext:
privileged: true
volumeMounts:
- name: work
mountPath: /home/runner/_work
- name: dind-sock
mountPath: /var/run
- name: dind-externals
mountPath: /home/runner/externals
volumes:
- name: work
emptyDir: {}
- name: dind-sock
emptyDir: {}
- name: dind-externals
emptyDir: {}
Make sure to replace the githubConfigUrl
with the correct URL to your organisation. You can also change the maxRunners
and minRunners
config to your liking. They change how many runners can run at the same time and how many runners will be kept around even if there are currently no jobs.
Then run the following command to deploy the helm charts:
kubectl kubectl apply -f .
Make sure to pass the --kubeconfig
flag if not using the environment variable.
Now we have to create the secret that the runners will use to connect to Github:
kubectl create secret generic pre-defined-secret --namespace=arc-runners --from-literal=github_app_id=<APP_ID_HERE> --from-literal=github_app_installation_id=<INSTALLATION_ID_HERE> --from-file=<PATH_TO_PEM_FILE_HERE>
Wait a few moments and then check to see if the pods are running now by running the following commands:
kubectl get pods -n arc-system
kubectl get pods -n arc-runners
You should get outputs like the following:
NAMESPACE NAME READY STATUS RESTARTS AGE
arc-system arc-gha-rs-controller-78d9bbf976-jvr25 1/1 Running 0 43m
arc-system arc-runner-set-754b578d-listener 1/1 Running 0 5m53s
NAMESPACE NAME READY STATUS RESTARTS AGE
arc-runners arc-runner-set-nq9kv-runner-zthk5 2/2 Running 0 14s
If the status isn’t running yet, wait a few minutes and try getting the pods again.
We have now successfully setup the runners so let’s run our workflows with them.
To run a workflow on the new runners, just change the runs-on
property in the workflows yaml to arc-runner-set
. An example workflow would look like this:
name: Actions Runner Controller Demo
on:
workflow_dispatch:
jobs:
Explore-GitHub-Actions:
# You need to use the INSTALLATION_NAME from the previous step
runs-on: arc-runner-set
steps:
- run: echo "🎉 This job uses runner scale set runners!"
Now try running your workflow on your new runners.
You have now successfully setup your Github Actions Runners on Gigahatch Managed Kubernetes. If you have any questions or are stuck somewhere, please write us at info@gigahatch.ch. We look forward to hearing from you.