Deploy Lightning-Fast GitHub Actions Runners on UpCloud’s Managed Kubernetes: Part 1
GitHub Actions Runners are the backbone of GitHub’s CI/CD workflows, executing jobs defined in your pipelines. While GitHub provides hosted runners, many teams opt for self-hosted runners for faster build times, cost efficiency, and custom environments tailored to their workloads. Self-hosted runners are particularly useful for resource-intensive jobs, proprietary software builds, or workflows requiring specific tools or configurations.
In this four-part series, you’ll learn how to deploy and optimize lightning-fast GitHub Actions Runners on UpCloud’s Managed Kubernetes service. We’ll cover everything from provisioning the cluster to advanced configurations, troubleshooting, and security best practices.
In Part 1, we’ll focus on setting up the foundation: provisioning an UpCloud Kubernetes Cluster and installing the GitHub Actions Runner controller. You’ll find step-by-step instructions to get your runners up and running, ready to execute workflows from your repositories. Let’s dive in and get started!
Prerequisites
Before we begin provisioning the UpCloud Kubernetes cluster and installing the GitHub Actions Runner controller, make sure that you have the following ready:
- UpCloud Account: Make sure to sign up at upcloud.com.
kubectl
Installed and Configured: Download and installkubectl
to manage your Kubernetes cluster. Ensure it’s added to your system’sPATH
.- Helm 3.x Installed: Helm is a package manager for Kubernetes. Install Helm and verify the installation using
helm version
. - GitHub Personal Access Token (PAT): Create a PAT with the following scopes from your GitHub account:
repo
(Full control)workflow
(Full control)
- [Optional]:
upctl
installed locally to simplify managing thekubeconfig.yaml
file of your cluster.
With these prerequisites in place, you are ready to deploy your self-hosted runners on UpCloud’s Managed Kubernetes. Let’s proceed to the first step—creating the managed Kubernetes cluster!
Setting up the Managed Kubernetes Cluster on UpCloud
To get started, head over to the Kubernetes Clusters page on the UpCloud console and click on the Create new cluster button:

You will be taken to the New Kubernetes Cluster page:

On this page, you will configure the Kubernetes cluster you need for self-hosting GitHub Actions runners. To be able to run GitHub Actions Runners, you need to set up a Kubernetes cluster with the following minimum specifications:
- Cluster size: 1 node
- Node specifications: 4 vCPU, 8GB RAM
- Storage: 20 GB per node
To start, choose a location for your managed Kubernetes cluster. Next, choose the cluster plan. For now, you can let it be Development, but for production use-cases, make sure to choose Production:

Next, you need to create a private network for your cluster to use for connecting to its worker nodes. Click on the + Create Private network button to create a new private network:

You can choose the default configuration for the new private network and click on the Create Private Network button:

Next, you need to configure the node group. Start by choosing the plan with 4 CPU cores, 8 GB memory, and 160 GB storage. You’ll find it under the General purpose tab. Also, set the number of nodes to 1 to create just one node for now. In production use-cases, this number will depend on your scalability and other relevant requirements:

Next, you will need to create and add an SSH key to the cluster. Doing this will allow you to SSH into the node group nodes once they’re ready.

If you have existing SSH keys that you used with UpCloud earlier, you can use them by selecting them from the list. You can also create a new SSH key pair by running the command ssh-keygen -t rsa
. You can then print the public key by running the command cat ~/.ssh/id_rsa.pub
. You will need to paste this value into UpCloud when adding a new SSH key to it.
Next, you can choose the Kubernetes version (leave it as v1.29 for now) and enable the Allow access from all IP addresses switch to allow the kubectl
tool to connect to your cluster from any machine.

In production use-cases, you would want to add the IPv4 address or CIDR block of your development machine into this section to only allow your (trusted) machine to be able to connect to this cluster via kubectl
.
At the end, you can choose a name for your cluster. Once done, click the Create cluster button.

Now, you need to wait for a few minutes while UpCloud provisions resources and spins up your cluster. Once it’s ready, you will notice the Running status under the name of the cluster on the cluster details page:

If you scroll down, you will find two commands that will help you download the kubeconfig.yaml
file for this cluster and set it as your KUBECONFIG
to be able to connect to the cluster via command line:

You can switch to the Manual tab to download the kubeconfig file manually if you wish to.
If you have upctl
installed and configured locally, copy the two commands and run them on a terminal window. If not, follow the instructions in the Manual tab. Once done, your terminal will be able to access the newly created cluster
Installing the Runner Controller
Now, let’s walk through setting up the Actions Runner Controller (ARC) on UpCloud’s Managed Kubernetes. You’ll use Helm to handle the installation to keep things quick and straightforward.
You will also need a GitHub repo to link your GitHub Actions runner with. If you are using an organization account, you can use the organization URL instead. For personal accounts, you will need a GitHub repo though. Feel free to fork this one to your GitHub account if you need it.
Now, let’s start!
Install the Operator and CRDs
First, choose a namespace for the ARC operator pods (for now, use arc-systems
):
NAMESPACE="arc-systems"
helm install arc \
--namespace "${NAMESPACE}" \
--create-namespace \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller
This command installs the latest ARC version. You can specify a version if needed using --version
.
Set Up a Runner Scale Set
Next, configure the runners. Here’s where you define how many runners to create and connect them to your GitHub repository or organization:
INSTALLATION_NAME="arc-runner-set"
NAMESPACE="arc-runners"
GITHUB_CONFIG_URL="https://github.com/<your_account>/<your_repo>"
GITHUB_PAT="<your_pat>"
helm install "${INSTALLATION_NAME}" \
--namespace "${NAMESPACE}" \
--create-namespace \
--set githubConfigUrl="${GITHUB_CONFIG_URL}" \
--set githubConfigSecret.github_token="${GITHUB_PAT}" \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set
Here’s what each variable means:
INSTALLATION_NAME
will match yourruns-on
value in workflows.NAMESPACE
needs to be the namespace where you want your pods to be created.GITHUB_CONFIG_URL
links the runners to your GitHub repo.GITHUB_PAT
is your personal access token for authentication.
Once this commands run successfully, you have successfully set up the runner. If you ran into any issues with this command, feel free to check out this troubleshooting guide from GitHub for Actions Runner Controller errors.
Now, you can test it by creating an example workflow file in your repo!
Testing It All Together
To try out the new runner, create a .github/workflows/demo.yml
file in your repository:
name: ARC Demo
on:
workflow_dispatch:
jobs:
Test-Runner:
runs-on: arc-runner-set
steps:
- run: echo "🎉 Self-hosted runner is up and running!"
Make sure to set the value of runs-on
as arc-runner-set
, which is the name of your runner scale group.
You can now trigger a workflow run to see the workflow wait for a runner instance to come up in the arc-runner-set
scale group and run the workflow when it’s ready.
Here’s what the workflow run logs will look like:

While the job runs, you can try running kubectl get pods -n arc-runners -w
to watch the runners spin up in real time:
gh-actions-runner-p1 git:(main) ✗ kubectl get pods -n arc-runners -w
NAME READY STATUS RESTARTS AGE
arc-runner-set-cpnd4-runner-27cwp 0/1 ContainerCreating 0 12s
arc-runner-set-cpnd4-runner-27cwp 1/1 Running 0 15s
arc-runner-set-cpnd4-runner-27cwp 0/1 Completed 0 29s
arc-runner-set-cpnd4-runner-27cwp 0/1 Terminating 0 29s
This shows that you have successfully set up the GitHub Actions runner on your UpCloud based managed Kubernetes instance!
Next Up
In this part, you learned how to provision an UpCloud Kubernetes cluster, install the Actions Runner Controller, configure a runner scale set, and test your deployment with a sample workflow. You now have a functional self-hosted runner setup ready to execute your GitHub Actions workflows!
In the next part of this series, we’ll dive into advanced configurations. You’ll learn how to customize runner pods with specific resources and tools, implement network policies, and set up security contexts. Additionally, we’ll cover monitoring runners using Prometheus and Grafana, discuss cost management strategies, and explore autoscaling policies to optimize performance and efficiency.
Stay tuned for part 2!