Skip to content
21 September 2026

Running GitHub Actions on a DIY Talos Linux Kubernetes Node

I swapped pricey cloud CI minutes for a home‑grown Kubernetes runner, saving money while learning a lot about Talos Linux and self‑hosted infrastructure.

Running GitHub Actions on a DIY Talos Linux Kubernetes Node

After a hiatus caused by personal setbacks and a demanding job, I found myself back at the keyboard with a new priority: reducing the recurring expense of GitHub Actions for my private game-development repository. The original workflow drained $5-10 each week, which would balloon to roughly $500 annually if left unchecked. Faced with those numbers, I asked myself whether the solution lay in better budgeting or in building something myself.

Why the existing CI pipeline was unsustainable

The monthly quota consumption stemmed from a series of automated tests that ran on every push. Each run spun up a fresh runner in the cloud, executed the test suite, and then terminated. While convenient, the pay-per-use model meant that even modest development activity quickly exceeded the free tier. I calculated the long-term impact: over a year, the cost would outstrip the price of a modest desktop computer. The financial pressure, combined with a desire to experiment with emerging technologies, pushed me toward a home-based alternative.

Choosing hardware and an OS built for Kubernetes

I scoured the second-hand market and settled on a refurbished Dell OptiPlex priced at around $300. The chassis offered enough room for upgrades, and its warranty gave peace of mind. For the operating system, I selected Talos Linux a minimal, immutable distro explicitly designed for running Kubernetes clusters. Talos eliminates traditional package management, replacing it with a declarative configuration model accessed through talosctl. This approach promised rapid deployment, low overhead, and a clear path to disaster recovery.

Flashing the machine and bringing the cluster online

Installation was remarkably quick: a USB stick, a few minutes of flashing, and the machine rebooted into a ready-to-configure state. Within the same evening I used talosctl apply-config to push a YAML file describing a single-node control plane. The result was a fully functional Kubernetes API that responded to kubectl commands in seconds. A typical health check looked like this:

kubectl top node
NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%)
talos-s13-64i 363m 6% 2032Mi 6%

Even when a GitHub Action consumed all available CPU, the node’s memory usage stayed below 30 %, confirming that the hardware could comfortably handle my workload.

Connecting GitHub Actions to the home cluster

To replace the cloud runners, I deployed the Actions Runner Controller (ARC) as a set of Kubernetes manifests. The controller registers the self-hosted runner with my GitHub repository, allowing jobs to be scheduled on the local node. Initial debugging took several hours because the runner needed access to the host’s network namespace and appropriate permissions. After tweaking the security context and exposing the necessary Docker socket, the pipeline executed successfully, and the weekly cost dropped to zero.

Managing storage and persistent volumes

The biggest surprise came when I tried to cache build artifacts using MinIO and the gha-cache-server. Talos’s immutable root filesystem meant that conventional persistent volume claims behaved unexpectedly. I first attempted Rancher’s local-path-provisionerassuming a single-node setup would simplify matters, but the provisioner could not create the required mount points due to Talos’s read-only root. The solution involved adding an extraMounts section to the machine configuration and using a dedicated SSD for data storage. Once the mount was recognized, MinIO served as a reliable caching layer, cutting build times by nearly half.

Secrets, backup strategy, and the “pet” trap

Talos stores the entire control-plane configuration—including cluster certificates—in a single YAML file. Exposing this file in a public repository would be a security disaster, so I wrote a short script that uploads the file to a secret manager (currently 1Password). A complementary script retrieves the secret on a fresh machine, restores the configuration, and re-creates the cluster in under an hour. This declarative, repeatable process turned a traditional “home lab”—often a one-off experiment—into a recoverable service.

Despite the successes, I remain wary of the pet infrastructure syndrome. The temptation to keep tweaking Kubernetes resources, tune scheduler parameters, or experiment with advanced storage backends can quickly turn a cost-saving tool into a hobby that consumes more time than it saves. To avoid that, I treat the cluster as a static CI runner: I lock the manifest versions, limit access to read-only dashboards, and focus any future upgrades on scaling hardware rather than adding features.

Looking ahead: scaling and lessons learned

At present the OptiPlex operates at roughly 50 % of its CPU capacity during peak CI runs, leaving headroom for additional projects. If my development pipeline expands, I plan to purchase a second refurbished box and link the two nodes with a lightweight overlay network, effectively doubling the available resources while preserving the same Talos-based workflow. The key takeaway from this experiment is that a modest investment—both monetary and time-wise—can replace recurring cloud costs, provide full control over the CI environment, and deliver valuable hands-on experience with modern cloud-native tools.

Author

Beatrice Mitchell

Beatrice Mitchell, Manchester-rooted and classically elegant, famously commissioned a rebuttal series after a controversial council planning meeting in Stockport, insisting on community testimony. Holds a firm editorial line on accountability and narrative fairness, and collects vintage city planning maps as an idiosyncratic hobby.