https://github.com/kekyo/ga_runner
GitHub Actions Self-hosted immutable runner
https://github.com/kekyo/ga_runner
github immutable podman self-hosted-runner
Last synced: about 2 months ago
JSON representation
GitHub Actions Self-hosted immutable runner
- Host: GitHub
- URL: https://github.com/kekyo/ga_runner
- Owner: kekyo
- License: mit
- Created: 2025-03-06T06:58:02.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-03-07T08:11:08.000Z (over 1 year ago)
- Last Synced: 2025-03-07T08:28:53.999Z (over 1 year ago)
- Topics: github, immutable, podman, self-hosted-runner
- Language: Shell
- Homepage:
- Size: 141 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# GitHub Actions Self-hosted immutable runner
[](https://www.repostatus.org/#wip)
Tested Actions runner version: [2.322.0](https://github.com/actions/runner/releases) [2025/3/6]
----
[](https://github.com/kekyo/ga_runner/blob/main/README_ja.md)
## What is this?
GitHub Actions self-hosted runners are convenient, but have you ever thought about running them in an immutable way?
The runners hosted by GitHub are immutable, and are destroyed each time a build is run,
so you can assume a clean build environment.
However, because self-hosted runners cannot directly mimic this behavior,
it is quite troublesome to set up a clean build environment.
This script configures GitHub Actions self-hosted runners to run immutably.
It is very easy to use, and the prepared runner instance is reset each time a job is executed, which improves the reproducibility of CI/CD.
This is a good fit for people with the following issues:
* You quickly use up the free quota of runners hosted by GitHub.
* You are not satisfied with the performance of runners hosted by GitHub.
* You want to host them on your own server machine, but it is a hassle.
* You are troubled by the fact that you can't customize the image, even though there are too many requirements for the runner.
## How it works
This script has been tested on Ubuntu 24.04 host
(it is probably also compatible with recent Ubuntu and Debian, but this has not been tested).
And the runner runs based on [Ubuntu 24.04 docker image](https://hub.docker.com/_/ubuntu/).
The script installs [`podman` (an OSS implementation compatible with Docker)](https://podman.io/)
and builds a self-hosted runner instance on a container.
When the runner finishes executing the job, this container also terminates,
the container is deleted on the spot, and the container is executed again.
At each startup, `ga_runner` uses your GitHub personal access token (PAT) to request
a fresh registration token and register an ephemeral runner for a single job.

`podman` runs as the superuser, but runs as a normal user inside the container (you can also use `sudo`).
This series of actions is registered as a `systemd` service,
so once the host OS starts up, everything is handled automatically.
In other words, as the administrator of the host machine, you don't have to do anything! ...maybe ;)
## How to use it
The script has `sudo` inserted appropriately, so you can start working as a normal user.
We will explain the repository that wants to install the self-hosted runner as `https://github.com/kekyo/foobar`:
1. Clone `ga_runner` repository on your host machine.
The local repository contains the scripts that `systemd` refers to.
Since you will need to maintain the local repository after installation, please decide on a location based on that assumption:
```bash
$ cd
$ git clone https://github.com/kekyo/ga_runner
```
2. Build `podman` image (You have to run only once per the host).
It will be installed `curl`, `uidmap` and `podman` automatically:
```bash
$ cd ga_runner
$ ./build.sh
```
3. Create a fine-grained GitHub personal access token (PAT) for the target repository.
Grant `Administration: Read and write` under "Repository permissions".
The token is used only to request short-lived runner registration tokens automatically.
Please refer to the following screenshot:


4. Install runner service by:
`install.sh `. For example:
```bash
$ ./install.sh kekyo foobar "" github_pat_************************
```
That's all! ("Instance postfix" argument is specified as an empty string. Will explain this later.)
The `systemd` service is named as `github-actions-runner_kekyo_foobar`.
Therefore, to check the service in operation:
```bash
$ sudo systemctl status github-actions-runner_kekyo_foobar
```
## Storing configuration information
The GitHub URL, runner name, and GitHub PAT are stored in the `scripts/config/` directory.
Each time the container starts, `ga_runner` uses the PAT to request a fresh short-lived registration token
and registers a new ephemeral runner for a single job.
If the PAT expires, is rotated, or something goes wrong, run `install.sh` again with a new PAT.
If you want to start over completely, delete the service using `remove.sh` and install it again.
## Installed packages on the job container
The number of packages installed in the container is minimal.
The list is shown below:
```
sudo, uidmap, fuse-overlays, slirp4netns, ca-certificates,
tzdata, locales, curl, libxml2-utils, git, unzip, libicu-dev
```
See [Dockerfile](scripts/Dockerfile) for detail.
If necessary, you can install additional packages using `apt-get` or other tools within the Actions job YAML script.
In other words, you can control it using only the YAML script without having to rebuild the container image.
Alternatively, you can edit the `Dockerfile` directly to build and run an image with many packages pre-installed.
## Install multiple runner instance
Yes, you can run multiple runner instance on one host OS.
Execute `install.sh` multiple time with different user/repository name.
If you want to run multiple runner instances on the same host for the same repository, you need to specify the "Instance postfix" argument and run `install.sh`.
For example, to run multiple instances for the `https://github.com/kekyo/foobar` repository:
```bash
$ ./install.sh kekyo foobar "instance1" github_pat_************************
$ ./install.sh kekyo foobar "instance2" github_pat_************************
$ ./install.sh kekyo foobar "instance3" github_pat_************************
```
Please identify them using "Instance postfix".
As a result, the service names for `systemd` will be as follows:
* `github-actions-runner_kekyo_foobar_instance1`
* `github-actions-runner_kekyo_foobar_instance2`
* `github-actions-runner_kekyo_foobar_instance3`
These are recognized as different services.
## Package caching feature
Every time the Actions Runner is started, it downloads the latest package version
`actions-runner-linux-x64-*.tar.gz` from the official
[GitHub Actions runner release repository](https://github.com/actions/runner/releases)
and automatically caches it in the directory `scripts/runner-cache/`.
If these files are up to date, the Runner will reuse them.
The distribution files and packages for APT(Ubuntu), NPM(Node.js), .NET runtime, NuGet(.NET) and Pip(Python) are also cached.
If you think that the cached content is causing a problem, delete the files under `scripts/runner-cache/`.
Each instance also has a cache configuration file at `scripts/config//config.ini`.
You can enable or disable each cache independently:
```ini
[cache]
runner_package = enabled
apt = enabled
npm = enabled
nuget = enabled
dotnet = enabled
maven = enabled
home_cache = enabled
```
`home_cache` controls `/home/runner/.cache`, which includes Pip and other user-level caches.
If `config.ini` is missing, or a key is omitted, the cache remains enabled to preserve the previous behavior.
If you run `install.sh` again, the existing `config.ini` is kept as-is.
## Redirect HTTP/HTTPS to the proxy server
You may want to cache the HTTP/HTTPS access that the job performs.
These can be redirected to your nearest local proxy server, which will then cache them.
This will speed up the download of packages and content.
Of course, you can also use it to get tunneling firewalls.
The URL to the proxy server is specified as the optional fifth argument to `install.sh`:
```bash
$ ./install.sh kekyo foobar "" github_pat_************************ http://proxy.example.com:3128
```
The URL you specify must be a valid hostname that can be accessed from within the runner container.
In other words, please note that `localhost` cannot be used.
### Using squid proxy server
Here is an example configuration for the [`squid` proxy server](https://www.squid-cache.org/) that can be used for this purpose.
This is an example of co-locating `squid` with maximum 1000MB (files each 100MB) disk cache on the machine that hosts `podman`:
```bash
$ sudo apt install squid
$ echo "http_access allow localnet" | sudo tee /etc/squid/conf.d/localnet.conf
$ echo "cache_dir ufs /var/spool/squid 1000 16 256" | sudo tee /etc/squid/conf.d/cache_dir.conf
$ echo "maximum_object_size 100 MB" | sudo tee -a /etc/squid/conf.d/cache_dir.conf
$ sudo systemctl restart squid
```
`podman` can specify the host's virtual network address by using the special `host.containers.internal` FQDN, so you can specify the URL as follows:
```bash
$ ./install.sh kekyo foobar "" github_pat_************************ http://host.containers.internal:3128
```
## Remove the runner service
`remove.sh `. For example:
```bash
$ ./remove.sh kekyo foobar ""
```
----
## License
MIT