Deploying GitHub Actions Self-Hosted runners on Koyeb
Tags: github, docker, serverless, devops
Published: 2021-05-26 14:19:07


GitHub Actions allows you to automate your software development workflow lifecycle right in your GitHub repository.
The workflows you deployed let you compose a multitude of jobs including CI/CD.

A GitHub Actions workflow is made of a YAML file containing all the configuration and commands to execute on specific events. The workflow execution is made on runners.
A runner is the application that runs a job from a GitHub Actions workflow. While GitHub natively provides managed runners, it can be interesting to deploy your own in various cases:

- Need different CPU, disk, and memory resources than the runners offered by GitHub.
- Need to execute workflows on specific operating systems not offered by GitHub.
- Require to execute workflows on specific hardware or processor architectures: GPUs, ARM, etc.
- Need to interact with resources GitHub runners can't access, i.e. services in a virtual private network, etc.
- Want to control where the workflow execution is performed

In this guide, we will showcase how to deploy GitHub Actions self-hosted runners on Koyeb and run a basic "Hello World!" GitHub Actions workflow.

## Requirements

 To successfully follow and complete this guide you need:
- A [Koyeb account](https://www.koyeb.com) to deploy and run the GitHub Actions, self-hosted runner
- A [GitHub account](https://www.github.com) with an existing repository and a GitHub Actions workflow you want to run on a self-hosted runner

## Steps

To deploy a self-hosted GitHub Actions runner on Koyeb you need to follow these steps:

1. [**Build the GitHub Actions runner Docker Image**](#build-the-git-hub-actions-runner-docker-image)
2. [**Push the Docker Image on the GitHub Container Registry**](#push-the-docker-image-on-the-git-hub-container-registry)
3. [**Configure your GitHub repository to use a self-hosted GitHub runner**](#configure-your-git-hub-repository-to-use-a-self-hosted-git-hub-actions-runner)
3. [**Deploy the self-hosted GitHub runner on Koyeb**](#deploy-the-self-hosted-git-hub-runner-on-koyeb)
3. [**Run a GitHub Actions workflow using a self-hosted GitHub runner**](#run-a-git-hub-actions-workflow-using-a-self-hosted-git-hub-runner)

## Build the GitHub Actions runner Docker Image

The first step is to create a Dockerfile to install GitHub Action runner. We will then build the Docker image and push it to the GitHub container registry.
As Koyeb allows you to horizontally scale the number of services, you will be able to deploy as many as you need GitHub runners on Koyeb.


To get started, created a new folder we will create the Dockerfile:

```bash
mkdir gh-self-hosted-runner
cd gh-self-hosted-runner
```

In the directory we created, create a `Dockerfile` file and paste the content below:

```dockerfile
FROM ubuntu:latest

ENV RUNNER_VERSION=2.278.0

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
    ca-certificates \
    curl \
    libicu-dev \
    netcat

WORKDIR /gh-runner

RUN curl -o actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz -L \
            https://github.com/actions/runner/releases/download/v2.278.0/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz

RUN tar xzf actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz

COPY entrypoint.sh .

RUN adduser --no-create-home ghrunner -uid 1001
RUN chown -R ghrunner:ghrunner /gh-runner

USER ghrunner

EXPOSE 3000
ENTRYPOINT ["/gh-runner/entrypoint.sh"]
```

You may notice we are installing netcat in the Dockerfile. We realize this operation as the Koyeb platform performs TCP health checks on services you deployed to ensure they are up and running.
We use netcat to expose the port 3000 in our GitHub Actions runner application so Koyeb can ensure it is up and running properly.

In the same directory, create an `entrypoint.sh` file. This file contains the script our container will execute at boot time:

```bash
#!/bin/bash

if [ -z ${GH_RUNNER_TOKEN+x} ]; then
  echo "GH_RUNNER_TOKEN environment variable is not set"
  exit 1
fi

if [ -z ${GH_REPOSITORY+x} ]; then
  echo "GH_REPOSITORY environment variable is not set."
  exit 1
fi

nohup nc -lk 3000 &

/gh-runner/config.sh --url https://github.com/$GH_REPOSITORY --token $GH_RUNNER_TOKEN
/gh-runner/run.sh
```

Build the Docker image by executing the following command:

```bash
docker build . -t ghcr.io/<YOUR_GITHUB_USERNAME>/gh-self-hosted-runner
```

*Take care to replace `<YOUR_GITHUB_USERNAME>` with your GitHub username*

## Push the Docker Image on the GitHub Container Registry

With our Docker image is built, we can now upload it to the GitHub container registry. In your terminal run the command below to push the image.

```bash
docker push ghcr.io/<YOUR_GITHUB_USERNAME>/gh-self-hosted-runner
```

Within a few minutes, you will see your Docker image available on the GitHub container registry: `https://github.com/<YOUR_GITHUB_USERNAME>?tab=packages`.

## Configure your GitHub repository to use a self-hosted GitHub Actions runner

On GitHub, go to the repository you want to use the self-hosted GitHub Actions runner and click the **Settings** tab. On the left-side menu, click **Actions** and select **runners** in the submenu.

You land on the **runners** settings page. Click the **Add runner** button to add a new self-hosted runner, the runner configuration page appears.

In the **Configure** section, copy the token, i.e. here: `AATHLD2AEXMPRBIPVTZVHMTAVTEOR`, and save it a safe place. You will need it in the next section when deploying the GitHub Actions runner on Koyeb.

```
./config.sh --url https://github.com/edouardb/runner-test --token AATHLD2AEXMPRBIPVTZVHMTAVTEOR
```

## Deploy the self-hosted GitHub runner on Koyeb

To deploy the self-hosted GitHub runner on Koyeb, go to the Koyeb Control Panel and click the **Create App** button.

In the form, fill the `Docker image` field with the name of the image we previously created which should look like `ghcr.io/<YOUR_GITHUB_USERNAME>/gh-self-hosted-runner`.

Check the box `Use a private registry` and, in the select field, click **Create Registry Secret**.

A modal opens asking for:

* a name for the Secret which will be created, for instance `gh-registry-secret`
* the registry provider to generate the secret containing your private registry credentials, in our case GitHub
* your GitHub username and a valid GitHub token having registry read/write permissions as password
Once you've filled all the fields, click the **Create** button.

In the *Ports* section, change the export port from `80` to `3000` and from protocol `HTTP` to `TCP`. This setting is required to let Koyeb performs health checks and ensure your service is up and running properly.

In the *Environment variables* section created two environment variables:

- GH_REPOSITORY: having for value the name of your GitHub repository, i.e. `org-name/repo-name`
- GH_RUNNER_TOKEN: having for value the GitHub runner token you created in the previous section. We strongly recommend to use an environment variable of type Secret to store it.

Give your App a name, i.e `gh-self-hosted-runner`, and click **Create App**

*You can add more regions to deploy your applications, and define the horizontal scaling according to your needs.*

Yours GitHub Actions self-hosted runner app is now deployed and running. In the next section, we will deploy a **Hello World!** GitHub Actions workflow executing on our self-hosted runner.


## Run a GitHub Actions workflow using a self-hosted GitHub runner


### Execute a new GitHub Actions workflow on a self-hosted GitHub runner

If you do not have any GitHub Actions workflow, in your git repository create a new folder to store our GitHub Actions workflow:

```bash
mkdir -p github/workflows
cd github/workflows
```

Create a new file to store our example workflow called `main.yaml` and paste the content below:


```yaml
name: CI
on: [push]

jobs:
  build:
    runs-on: self-hosted
    steps:
    - run: echo "Hello from Koyeb runner!"
```

The workflow above execute on the runner hosted on Koyeb and display "Hello from Koyeb runner!" each time a push occurs on your repository.

To test it, commit and push changes to your repository, in the **Actions** tabs of your repository on GitHub, you will see the result of the workflow executed by your GitHub runner running on Koyeb.

### Execute an existing GitHub Actions workflow on a self-hosted GitHub runner

In your workflow YAML file, edit the `runs-on` section of your workflow and set its value to `self-hosted` to run a self-hosted GitHub runner:

```yaml
name: CI
on: [push]

jobs:
  build:
    runs-on: self-hosted
    ...
```

In this guide, we demonstrated the benefit of using GitHub actions self-hosted runners and how to deploy them on Koyeb. If you have any questions or suggestions to improve this guide,
feel free to reach us out on [Slack](https://slack.koyeb.com).