Skip to content

Commit

Permalink
githubrunner: add documentation and fix template arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
Kamilcuk committed Oct 22, 2024
1 parent 18430bb commit 863d67f
Show file tree
Hide file tree
Showing 4 changed files with 295 additions and 131 deletions.
132 changes: 132 additions & 0 deletions doc/githubruner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# githubrunner

<!-- vim-markdown-toc GFM -->

* [What it does?](#what-it-does)
* [How it works?](#how-it-works)
* [How start the scheduler?](#how-start-the-scheduler)
* [Nomad job template](#nomad-job-template)
* [How to use it from Github workflow?](#how-to-use-it-from-github-workflow)
* [Example workflow:](#example-workflow)

<!-- vim-markdown-toc -->

# What it does?

Runs a specific Nomad job matching the labels requested by pending GitHub actions jobs.
Controls the number of Nomad jobs depending on the number of pending GithHub actions jobs.

# How it works?

- Every CONFIG.pool seconds
- Get all actions workflow runs with the following algorithm:
- For each entry configured CONFIG.repos
- If the repository has no /
- Get all repositories under this organization or user
- else use the repository
- For each such repository
- For each repository actions workflow
- For each repository actions workflow run
- If the workflow run has status queued or in_progress
- Add it to the list
- Get all Nomad jobs with the following algorithm:
- For all Nomad jobs in CONFIG.nomad.namespace
- If the job name starts with CONFIG.nomad.jobprefix + "-"
- If the `job["Meta"][CONFIG.nomad.meta]` is a valid JSON
- Add it to the list
- Group Github workflow runs and Nomad runners in groups indexed by repository url and runner labels
- For each such group:
- If there are more Github workflow runs than non-dead Nomad runners:
- If there are less non-dead Nomad runners than CONFIG.max_runners
- Generate Nomad job specification from Jinja2 template.
- Start the job
- If there are less Github workflow runs than non-dead Nomad runners:
- Stop a Nomad job
- For each dead Nomad job:
- purge it when associated timeout if reached

# How start the scheduler?

Create a file `config.yml` with the following content:

---
github:
token: the_access_token_or_set_GH_TOKEN_env_variable
repos:
# for single repos
- user/repo1
- user/repo2
# for all repositories of this user
- user

Run the command line:

nomadtools githubrunner -c ./config.yml run

The default configuration can be listed with `nomadtools githubrunner -c $'{}\n' dumpconfig`.

The configuration description is in source code.

# Nomad job template

The following variables are available in the Jinja2 template:

- CONFIG
- The whole parsed YAML configuration.
- RUN
- Dictionary with important generated values.
- RUN.RUNNER_NAME
- The Nomad job name and runner name, to be consistent.
- RUN.REPO_URL
- The repository the runner should connect to.
- RUN.LABELS
- Comma separated list of labels the runner should register to.
- RUN.REPO
- Like REPO_URL but without domain
- RUN.INFO
- Generated string with some information about the state of scheduler at the time the runner was requested to run.
- RUNSON
- The `runson:` labels in the workflow are parsed with `shlex.split` `k=v` values
- For example, `nomadtools mem=1000` results in RUNSON={"nomadtools": "", "mem": "1000"}.
- The values used by the default template:
- RUNSON.tag
- docker image tag
- RUNSON.cpu
- RUNSON.mem
- RUNSON.maxmem
- SETTINGS
- Dictionary composed of, in order:
- CONFIG.template_default_settings
- CONFIG.template_settings
- nomadlib.escape
- Replace `${` by `$${` and `%{` by `%%{` . For embedding string in template.

# How to use it from Github workflow?

jobs:
build:
runs_on: nomadtools mem=16000

would template the job with `RUNSON={"nomadtools": "", "mem": "16000"}` .

The value of `RUNSON.mem` is then used as the memory settings in the Jinja2 template.

## Multiple elements in runs_on

I do not know what will happen with multiple elements in runs_on, like:

runs_no:
- self-hosted
- nomadtools mem=16000

## Comma in labels

The config.sh github runner configuration script takes comma separated list of elements.

So comma will split the labels into multiple.

Do not use comma in `runs_on:`.

# Example workflow:

https://github.com/Kamilcuk/runnertest/tree/main/.github/workflows
145 changes: 82 additions & 63 deletions src/nomad_tools/entry_githubrunner/default.nomad.hcl
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
job "{{ param.JOB_NAME }}" {
{{ param.extra_job }}
locals {
INFO = <<EOFEOF
This is a default runner shipped with nomadtools based on myoung34/github-runner image.
type = "batch"
meta {
INFO = <<EOF
This is a runner based on {{ image }} image.
{% if param.docker == "dind" %}
It also starts a docker daemon and is running as privileged
{% elif param.docker == "host" %}
It also mounts a docker daemon from the host it is running on
{% endif %}
User requested labels were parsed to the following:
{{ nomadlib.escape(RUNSON | tojson) }}
EOF
The following parameters were generated for this job:
{{ nomadlib.escape(RUN | tojson) }}
{% if param.debug %}
PARAM = <<EOF
{{param | tojson}}
EOF
Job is running with the following settings:
{{ nomadlib.escape(SETTINGS | tojson) }}
{% if SETTINGS.docker == "dind" %}
The container runs with --privileged and starts a docker-in-docker instance.
{% elif SETTINGS.docker == "host" %}
The container mounts the /var/run/docker.sock from the host.
{% endif %}
}
group "{{ param.JOB_NAME }}" {
{{ param.extra_group }}
{% if RUN.nodocker is defined %}
The user requested to run without docker.
{% endif %}
EOFEOF
}

job "{{ RUN.RUNNER_NAME }}" {
{{ SETTINGS.extra_job }}
type = "batch"

group "{{ RUN.RUNNER_NAME }}" {
{{ SETTINGS.extra_group }}

reschedule {
attempts = 0
Expand All @@ -31,80 +39,91 @@ EOF
mode = "fail"
}

task "{{ param.JOB_NAME }}" {
{{ param.extra_task }}
task "{{ RUN.RUNNER_NAME }}" {
{{ SETTINGS.extra_task }}

driver = "docker"
kill_timeout = "5m"
config {
{{ param.extra_config }}
{{ SETTINGS.extra_config }}

image = "{{ param.image | default('myoung34/github-runner:latest') }}"
image = "myoung34/github-runner:{{ RUNSON.tag | default('latest') }}"
init = true
entrypoint = ["bash", "/local/nomadtools_startscript.sh"]
{% if SETTINGS.entrypoint %}
entrypoint = ["${NOMAD_TASK_DIR}/nomadtools_entrypoint.sh"]
{% endif %}

{% if param.cachedir %}
{% if SETTINGS.cachedir %}
mount {
type = "bind"
source = "{{ param.cachedir }}"
source = "{{ SETTINGS.cachedir }}"
target = "/_work"
readonly = false
}
{% endif %}
{% endif %}

{% if param.docker == "dind" %}
{% if not RUNSON.nodocker %}
{% if SETTINGS.docker == "dind" %}
privileged = true
{% elif param.docker == "host" %}
{% elif SETTINGS.docker == "host" %}
mount {
type = "bind"
source = "/var/run/docker.sock"
target = "/var/run/docker.sock"
}
{% endif %}
{% endif %}
{% endif %}

}

env {
ACCESS_TOKEN = "{{ CONFIG.github.token }}"
REPO_URL = "{{ param.REPO_URL }}"
RUNNER_NAME = "{{ param.JOB_NAME }}"
LABELS = "{{ param.LABELS }}"
RUNNER_SCOPE = "repo"
DISABLE_AUTO_UPDATE = "true"
{% if not param.RUN_AS_ROOT %}
RUN_AS_ROOT = "false"
{% endif %}
{% if param.ephemeral %}
EPHEMERAL = "true"
{% endif %}
{% if param.docker == "dind" %}
ACCESS_TOKEN = "{{ SETTINGS.access_token or CONFIG.github.token }}"
REPO_URL = "{{ RUN.REPO_URL }}"
RUNNER_NAME = "{{ RUN.RUNNER_NAME }}"
RUNSON = "{{ RUN.LABELS }}"
RUNNER_SCOPE = "repo"
DISABLE_AUTO_UPDATE = "true"
{% if not SETTINGS.run_as_root %}
RUN_AS_ROOT = "false"
{% endif %}
{% if SETTINGS.ephemeral %}
EPHEMERAL = "true"
{% endif %}
{% if not RUNSON.nodocker %}
{% if SETTINGS.docker == "dind" %}
START_DOCKER_SERVICE = "true"
{% endif %}
{% if param.debug %}
DEBUG_OUTPUT = "true"
{% endif %}
{% endif %}
{% endif %}
{% if SETTINGS.debug %}
DEBUG_OUTPUT = "true"
{% endif %}
}
{% if param.cpu or param.mem or param.maxmem %}

resources {
{% if param.cpu %}
cpu = {{ param.cpu }}
{% endif %}
{% if param.mem %}
memory = {{ param.mem }}
{% endif %}
{% if param.maxmem %}
memory_max = {{ param.maxmem }}
{% endif %}
{% if RUNSON.cpu %}
cpu = {{ RUNSON.cpu }}
{% endif %}
{% if RUNSON.mem %}
memory = {{ RUNSON.mem }}
{% endif %}
{% if RUNSON.maxmem %}
memory_max = {{ RUNSON.maxmem }}
{% endif %}
}
{% endif %}

{% if SETTINGS.entrypoint %}
template {
destination = "local/nomadtools_startscript.sh"
destination = "local/nomadtools_entrypoint.sh"
change_mode = "noop"
left_delimiter = "QWEQWEQEWQEEQ"
right_delimiter = "ASDASDADSADSA"
data = <<EOF
{% if not param.startscript %}{{ 1/0 }}{% endif %}
{{ escape(param.startscript) }}
EOF
perms = "755"
data = <<EOFEOF
{{ nomadlib.escape(SETTINGS.entrypoint) }}
EOFEOF
}
{% endif %}

}
}
}
Loading

0 comments on commit 863d67f

Please sign in to comment.