![](/_next/image?url=%2Fimages%2Fprofile.jpg&w=384&q=75)
Martin Koníček
Blog
Self Hosted GitHub Action Runner on Kubernetes
![Showcase image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2F93eujfo6%2Fproduction%2F68ee9595b2f0e02e486bc42a4c08952d887d8fbf-1024x1024.png%3Frect%3D0%2C128%2C1024%2C768%26w%3D1024%26h%3D768%26fit%3Dmax%26auto%3Dformat&w=2048&q=75)
Introduction
I recently set up a self-hosted GitHub Action Runner on Kubernetes using the Action Runner Controller, aiming for more control over my CI/CD pipeline. This involved configuring Kubernetes with DNS, ingress, and microk8s, and securing my private Docker registry with TLS and a custom Certificate Authority.
Create GitHub app and secrets
![](https://cdn.sanity.io/images/93eujfo6/production/c608fd733a4d014fc0e80b1ebd9f06c3f98d1285-1465x1088.png?max-h=768&max-w=1024&fit=clip&auto=format)
On repository click on Developer settings and create and install an app. You should get all details below for creating a secret
kubectl create secret generic controller-manager -n actions \
--from-literal=github_app_id=YOUR_GITHUB_APP_ID \
--from-literal=github_app_installation_id=YOUR_INSTALLATION_ID \
--from-literal=github_app_private_key=YOUR_PRIVATE_KEY
Helm Chart Values
githubWebhookServer:
enabled: true
replicaCount: 1
secret:
enabled: true
create: true
name: "github-webhook-server"
### GitHub Webhook Configuration
github_webhook_secret_token: "GITHUB_WEBHOOK_TOKEN"
...
ingress:
enabled: true
ingressClassName: ""
annotations:
kubernetes.io/ingress.class: traefik-ingress-class
kubernetes.io/tls-acme: "true"
hosts:
- host: github-runner.yourdomain.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: github-runner-cert
hosts:
- github-runner.yourdomain.com
When setting up your GitHub Action Runner on Kubernetes, focus on two crucial steps: First, update the ingress section in your YAML with your actual domain name, ensuring GitHub can reach your webhook server. Second, use tls-acme: "true" to integrate cert-manager.
GitHub Webhook
![](https://cdn.sanity.io/images/93eujfo6/production/b59ddca718bc2e93f31ce9373aeba5cfe91a264e-1196x982.png?max-h=768&max-w=1024&fit=clip&auto=format)
One would input github-runner.yourdomain.com as the Payload URL, corresponding to yours Kubernetes-hosted GitHub Action Runner's address. The webhook settings are found under the repository's "Settings" tab, and choosing "Webhooks" from the sidebar will navigate to this page.
image:
repository: "summerwind/actions-runner-controller"
actionsRunnerRepositoryAndTag: "summerwind/actions-runner:latest"
dindSidecarRepositoryAndTag: "docker:dind"
pullPolicy: IfNotPresent
certManagerEnabled: true
The certManagerEnabled: true parameter activates Cert-Manager within the Kubernetes cluster, which automates the issuance and renewal of TLS certificates for secure communications. The image section outlines the Docker images used by the self-hosted GitHub Actions runner, including the controller, runner, and Docker-in-Docker sidecar images, to manage and execute CI/CD jobs.
Install Helm Chart
helm repo add actions-runner-controller https://actions-runner-controller.github.io/actions-runner-controller
helm repo update
This will add a helm repo
helm fetch actions-runner-controller/actions-runner-controller --untar --untardir ./mychart
cp ./mychart/actions-runner-controller/values.yaml ./custom-values.yaml
Now you will get helm chart values and you can modify it with values above
helm install actions-runner-controller actions-runner-controller/actions-runner-controller -f custom-values.yaml
Create runner deployment
kubectl create secret generic ca-cert --from-file=ca.crt -n actions
If you use private repository with SSL (I use ingress for SSL) you need to import SSL certificate into secret above.
apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
metadata:
annotations:
karpenter.sh/do-not-evict: "true"
name: self-hosted-runner-deployment
namespace: actions
spec:
template:
spec:
repository: githubuser/repository
labels:
- self-hosted-linux
resources:
requests:
cpu: 1500m
memory: 2000Mi
volumes:
- name: certs
secret:
secretName: ca-cert
items:
- key: ca.crt
path: ca.crt
dockerVolumeMounts:
- mountPath: /etc/docker/certs.d/yourprivaterepo.intranet
name: certs
readOnly: true
Create a file runnerdeployment.yml above with modifying yourprivaterepo.intranet and apply it.
kubectl apply -f runnerdeployment.yml
Scaling deployments
apiVersion: actions.summerwind.dev/v1alpha1
kind: HorizontalRunnerAutoscaler
metadata:
name: self-hosted-runner-deployment-autoscaler
namespace: actions
spec:
maxReplicas: 30
minReplicas: 0
scaleTargetRef:
kind: RunnerDeployment
name: self-hosted-runner-deployment
scaleUpTriggers:
- duration: 30m
githubEvent:
workflowJob: {}
This YAML configuration defines a HorizontalRunnerAutoscaler in Kubernetes, which dynamically adjusts the number of self-hosted GitHub Actions runners between 0 and 30. It scales up in response to workflow job events.
Testing with GitHub runners
![](https://cdn.sanity.io/images/93eujfo6/production/c4ea261aef4cdc469a284f33f81973370594b88a-1288x817.png?max-h=768&max-w=1024&fit=clip&auto=format)
After installing you should see when run CI/CD pipeline GitHub runners Online.
Here's how I can help:
- I am an experienced DevOps expert, ready to take over all your operational tasks.
- I’ll personally explain everything directly to your boss, ensuring a smooth transition.
- Say goodbye to the endless DevOps tasks and focus exclusively on what you love—coding.
- You’ll never have to worry about DevOps again, as I handle everything for you.
- I will ensure your boss is satisfied, and you'll receive the recognition you deserve.
![WebSocket connection to WireGuard](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2F93eujfo6%2Fproduction%2Fface723abf98ca77497d086dcc7356c74e6ebf1c-800x400.jpg%3Frect%3D200%2C0%2C400%2C400%26w%3D100%26h%3D100%26fit%3Dmax%26auto%3Dformat&w=256&q=75)