{"id":26491311,"url":"https://github.com/uncledecart/ansible-runners-infra","last_synced_at":"2026-05-08T11:11:49.443Z","repository":{"id":283333131,"uuid":"951379516","full_name":"uncleDecart/ansible-runners-infra","owner":"uncleDecart","description":"Ansible recipe to deploy your selfhosted GitHub runners in VMs ","archived":false,"fork":false,"pushed_at":"2025-06-23T14:58:10.000Z","size":64,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-23T15:47:49.611Z","etag":null,"topics":["ansible-playbook","github-runners","github-runners-management","self-hosted-runners"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uncleDecart.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-03-19T15:30:28.000Z","updated_at":"2025-06-23T14:58:15.000Z","dependencies_parsed_at":"2025-05-13T13:40:40.272Z","dependency_job_id":"0d070b80-bb16-457c-8bfc-01d4c9677693","html_url":"https://github.com/uncleDecart/ansible-runners-infra","commit_stats":null,"previous_names":["uncledecart/ansible-runners-infra"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/uncleDecart/ansible-runners-infra","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uncleDecart%2Fansible-runners-infra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uncleDecart%2Fansible-runners-infra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uncleDecart%2Fansible-runners-infra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uncleDecart%2Fansible-runners-infra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uncleDecart","download_url":"https://codeload.github.com/uncleDecart/ansible-runners-infra/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uncleDecart%2Fansible-runners-infra/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32777800,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"ssl_error","status_checked_at":"2026-05-08T08:22:45.650Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible-playbook","github-runners","github-runners-management","self-hosted-runners"],"created_at":"2025-03-20T08:28:07.290Z","updated_at":"2026-05-08T11:11:49.429Z","avatar_url":"https://github.com/uncleDecart.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ansible playbook to deploy self-hosted GitHub runners\n\n## What this repo is about?\n\nThis playbook connects to remote node, installs all needed packages,\ndeploys VMs, and registers each of them as a self-hosted runner for specified\norganisation using GitHub Access token\n\n## How to use it?\n\n#### Clone this repository\n\n```sh\ngit clone git@github.com:uncleDecart/ansible-runners-infra.git\n```\n\n#### Install ansible\n\nSee [this](https://docs.ansible.com/ansible/latest/installation_guide/index.html) doc for more information\n\n### Install ansible.posix collection\n\n```sh\nansible-galaxy collection install ansible.posix\n```\n\n#### Define your .env file and inventory file\n\nAnsible main concepts are invenotry and recipes recepies hold a collection of actions which are applied to\nspecific elements of inventory. Inventory describes machines and holds device specific configuration.\n\n```yaml\n    all:\n     x64: # for arm runners define them under arm\n      hosts: # ... all your machines should be defined under this section\n       # ...\n       # cool machine name, optional but highly recommended\n       kratos:\n         # Define your IP address and user in .env file\n         ansible_user: \"{{ lookup('env', 'KRATOS_USER') }}\"\n         ansible_host: \"{{ lookup('env', 'KRATOS_IP') }}\"\n\n         # Set this to true if you want to delete previously created runners\n         force_cleanup: false\n\n         vms:\n           # Applied to host instance\n           global:\n             disk:\n               # additional resize apart from base image; qemu-img format\n               size: 100G\n               # folder to store images; need to have same permissions\n               folder: \"/var/lib/libvirt/images\"\n\n             # folder where cloud init-related files will be stored\n             # including iso image\n             cloud_init_server_dir: /srv/cloud-init\n\n             # GitHub runner-related information\n             github_runner:\n               # %repo-owner or organisation%/%repository%\n               # can be different for different runners\n               url: \"{{ lookup('env', 'GH_URL')}}\"\n               # %repo-owner or organisation%/%repository%\n               token: \"{{ lookup('env', 'GH_PAT')}}\"\n               # URL to download the runner; contains version and architecture\n               download_url: \"https://github.com/actions/runner/releases/download/v2.323.0/actions-runner-linux-x64-2.323.0.tar.gz\"\n               # WARN: change this if changing VM user\n               user: ubuntu \n               # Labels which runner will be registered\n\n               labels: [ ubuntu-latest ]\n               # --runnergroup parameter on GitHub runner\n               # for more info check this\n               # https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/managing-access-to-self-hosted-runners-using-groups#automatically-adding-a-self-hosted-runner-to-a-group\n               group: \"default\"\n\n\n             # VM image for runners, should be cloud-init compatible\n             image_url: \"https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64-disk-kvm.img\"\n\n           # Individual virtual machine instances\n           instances:\n             # name of the runner, it will be registered\n             # under this name and the name of virtual machine will\n             # be the same. Should be unique across repositories\n             # to which they will be connected to\n             - name: kratos-runner-1\n               # number of VCPUs, which will be assigned to VM\n               cpu_count: 8\n               # RAM in megabytes assigned to VM\n               ram: 16384\n               # cpuset: this will tell VMM which pull of cores\n               # this particular VM should use CPUs from\n               # used for optimisation, leave empty to give VMM\n               # control over it\n               cpu: \"0-7\"\n               # labels are optional tags for each specific runner\n               # instance, should be a list even if one element,\n               # they are added in addition to labels specified\n               # in github_runner\n               labels: [cake-is-a-lie]\n             # ...\n```\n\nThen you have to define your .env file or write values directrly in inventory file\n\n```sh\nKRATOS_IP=%YOUR-DEVICE-REMOTE-IP%\nKRATOS_USER=%YOUR-REMOTE-DECIVE_USER%\n\nGH_REPO=%REPO-WHERE-YOU-WANT-YOUR-RUNNERS%\nGH_TAC=%GITHUB-ACCESS-TOKEN%\n```\n\n**Important:** checkout [this](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-fine-grained-personal-access-token) doc to know how you can get GitHub token. As for permissions\n\n- For repositories within a personal account: `repo`, `workflow`, `write:actions`, `admin`\n- For repositories in an organization: `write:actions`, `admin:org` (for organization-wide runners)\n\nNote that for ARM runners the deployment process is a bit different,\nso you need to separate them\n\nhost_setup will download VMs, deploy them with cloud-init, install all needed\ncomponents and register runner within your organisation/repository.\n\n#### Run playbook with invenotry file\nYou can run it like this\n\n```sh\nexport $(grep -v '^#' .env | xargs) \u0026\u0026 ansible-playbook -i inventory.yml playbook.yml\n```\n\n*Note:* export command can be run once per shell session\n\nOnce runners are registered in the GitHub repository (or organisation) run post installation recipe\n\n```sh\nexport $(grep -v '^#' .env | xargs) \u0026\u0026 ansible-playbook -i inventory.yml postinst.yml\n```\n\nThis will start the runners and install node_exporter and prometheus on host system\nfor runners monitoring\n\n### Important information\n\n- PAT token will be stored in VMs as well as on playbook it was ran on (host system of inventory machines, in /tmp directory)\n- When you run playbook it will delete _ALL_ previously created VMs on the host system\n- For each previously created VM on host system it will also delete runner with the same name for the given github url\n\n#### FAQ\n\n#### Q: Can I use it for org wide runners?\n\nA: Yes, just don't specify repository in GITHUB_URL\n\n#### Q: What if I want to deploy those runners locally?\nA: in playbook.yml change hosts:all to hosts:localhost\n\n#### Q: Where can I find my GitHub access token?\nA: Checkout [this](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-fine-grained-personal-access-token) doc. See permisssions question below as well\n\n#### Q: Why do you base64-encode cloud init script?\nA: Because encoding it is most version-compatible approach: depending on cloud-init version\none should or should not backslash $ symbol. And debugging cloud-init scripts is not trivial\n\n#### Q: What kind of permissions do I need for GitHub token?\nA:\n- For repositories within a personal account: `repo`, `workflow`, `write:actions`\n- For repositories in an organization: `write:actions`, `admin:org` (for organization-wide runners)\n\n#### Q: How can I update production system?\nA: Use rollout playbook. It contains script which will update one machine at a time.\n```sh\nexport $(grep -v '^#' .env | xargs) \u0026\u0026 ansible-playbook -i inventory.yml rollout.yml\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funcledecart%2Fansible-runners-infra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funcledecart%2Fansible-runners-infra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funcledecart%2Fansible-runners-infra/lists"}