# GitHub Runner as container (Docker) using Moonrepo task as launcher

## Prerequisites

* Full understanding of Moonrepo tasks system (and a Moon project) ([moonrepo.dev](https://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](https://github.com/actions/runner/issues/367#issuecomment-1507331413))

Create a Dockerfile inside `<project-name>`

```dockerfile
# <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>

```bash
# <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: https://github.com/<your-repo-name>/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

```yaml
# <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

```bash
# <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/&lt;your-repo-name&gt;/settings/actions/runners](https://github.com/alpsify/alpsify/settings/actions/runners) and enjoy your new GitHub Runners! 🥳
