Skip to content

Repository configuration

RunsOn supports describing various options through a configuration file. This file is located at .github/runs-on.yml (must be named exactly that) in the repository where you are using RunsOn runners.

The configuration file supports defining:

  • custom images
  • custom runners
  • the list of admins having SSH access to the runners
  • a global configuration file to extend from

Structure

The configuration file is a YAML file with the following top-level keys: _extends, runners, images, and admins.

.github/runs-on.yml
_extends: ...
runners: {...}
images: {...}
admins: [...string]

_extends

If set, the configuration file will inherit from the configuration file in the repository specified by the _extends value.

A common use case is to define a global configuration file in the .github-private repository of your organization, and then inherit from it in other repositories. Do not forget to allow the RunsOn GitHub App to access the repository hosting the global configuration file.

Example

.github/runs-on.yml
_extends: .github-private
runners:
...

In this example, the configuration file in the repository will inherit from the configuration file stored at .github/runs-on.yml in the .github-private repository.

runners

Mapping of custom runner names to runner configuration.

Available configuration options: cpu, ram, disk, family, spot, image, ssh, extras, private, retry, preinstall, tags.

For more details about each option, please refer to the job-level labels documentation.

Example

.github/runs-on.yml
runners:
docker_with_ipv6:
cpu: [2, 4]
ram: [2, 8]
disk: default
family: ["c7", "m7", "r7"]
spot: capacity-optimized
tags:
- custom-tag-key1:custom-tag-value1
- custom-tag-key2-no-value
preinstall: |
cat > /etc/docker/daemon.json <<EOF
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8:1::/64"
}
EOF
systemctl restart docker
other-runner:
...

And the runner will be available for use in the repository:

jobs:
test:
runs-on: runs-on=${{ github.run_id }}/runner=docker_with_ipv6

runners.family

Required. Array of strings. e.g ["c7", "m7"].

runners.image

Required. String. e.g ubuntu22-full-x64.

runners.cpu

Array of integers. e.g [2, 4].

runners.ram

Array of integers. e.g [2, 8].

runners.disk

String. e.g default.

runners.spot

Boolean or string. e.g capacity-optimized, co, lowest-price, lp, price-capacity-optimized, pco, true, false.

runners.ssh

Boolean. e.g true, false.

runners.extras

Array of strings. e.g ["s3-cache"].

runners.private

Boolean. e.g true, false.

runners.retry

String. e.g when-interrupted, false.

runners.preinstall

String. Script to run on the runner, before the GitHub Actions runner agent is executed (see images.preinstall for more details).

runners.tags

Array of strings containing custom key:value tags to apply to the runner underlying EC2 instance. e.g. ["custom-tag-key1:custom-tag-value1", "custom-tag-key2-no-value"].

Cannot start with the runs-on- prefix. Tag keys and values will be automatrically sanitized to remove any special characters (/ is allowed for values).

images

Mapping of custom image names to image configuration.

Available configuration options: name, ami, platform, arch, owner, preinstall, tags.

Example

.github/runs-on.yml
images:
custom:
owner: "123456789"
name: "my-org/my-image-name-*"
arch: x64
platform: linux
tags:
# filter with specific value
is-production-ready: "true"
# allow any value
other-tag: "*"
fixed-ami:
ami: "ami-0abcd159cbfafefgh"

And you can use the image in your workflows like this:

jobs:
test:
runs-on: runs-on=${{ github.run_id }}/image=custom
# or
runs-on: runs-on=${{ github.run_id }}/image=fixed-ami

images.name

Required (unless ami is set). String. Can include wildcards, in which case RunsOn will pick the most recent image matching the pattern.

images.ami

Required (unless name is set). String. If set, the image will be pinned to the specified AMI, irrespective of the name option.

images.platform

String. Either linux or windows. Not required if ami is set.

images.arch

String. Either x64 or arm64. Not required if ami is set.

images.owner

String. AWS account ID where the image is hosted.

images.preinstall

String. Script to run on the runner, before the GitHub Actions runner agent is executed. Takes precedence over the preinstall option at the runner level if both are set.

Useful to perform pre-authentication steps, such as logging into private registries. Installing additional software will make your runner boot time slower, it is recommended that you create your own AMI instead.

If the preinstall script fails, the job will fail. You will find the preinstall exit status and logs in the “Set up runner” section of the job logs.

Platform behaviour:

  • On Linux, the preinstall script is executed as the root user, before the GitHub Actions runner agent is launched. The script must be a valid bash script, and will be executed with bash -e (so any failure will fail the script immediately).

  • This option is not yet available for Windows images.

images.tags

Mapping of key-value tags to filter the image when searching for it.

admins

List of GitHub usernames that have SSH access to the runners launched for this repository. They come in addition to the admins defined at the CloudFormation stack level.

Example

.github/runs-on.yml
admins:
- crohr
- other-github-user

Full example

.github/runs-on.yml
_extends: .github-private
images:
mycustomimage:
platform: "linux"
arch: "x64"
owner: "099720109477"
# will take the most recent AMI matching the wildcard pattern
name: "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
otherimage:
platform: "linux"
arch: "x64"
ami: "ami-0abcd159cbfafefgh"
runners:
cheap:
# Useful for workflows that do not require a lot of CPU / RAM.
ram: [2, 4, 8]
# Burstable instances, valid for both x64 and arm64
family: ["t3", "t4"]
image: otherimage
ssh: false
fast:
cpu: 32
disk: large
family: ["c7a", "m7a"]
spot: false
# reference custom image defined above
image: mycustomimage
preinstall: |
echo "doing some stuff before the GitHub Actions runner agent is executed..."
echo "For instance, disabling the host's IPv6 if needed"
sysctl -w net.ipv6.conf.all.disable_ipv6=1
admins:
- crohr
- other-github-user

Using the configuration in a GitHub Workflow

.github/workflows/my-workflow.yml
job: Test
runs-on: [runs-on,runner=2cpu-linux-x64,image=mycustomimage]
.github/workflows/my-workflow.yml
job: Test
runs-on: [runs-on,runner=2cpu-linux-x64,image=otherimage]
.github/workflows/my-workflow.yml
job: Test
runs-on: [runs-on,runner=cheap]
.github/workflows/my-workflow.yml
job: Test
runs-on: [runs-on,runner=fast]

Sharing configuration across repositories

RunsOn comes with a feature that allows a local configuration file to inherit from a globally defined configuration file, by using the _extends directive.

The recommendation is to store the global configuration file in the special .github-private repository of your organization, but you can choose any other repository as well (public or private).

Example:

your-repo/.github/runs-on.yml
_extends: .github-private
.github-private/.github/runs-on.yml
runners:
cheap-arm64:
cpu: [1, 2]
family: ["t4g"]
image: ubuntu22-full-arm64