kubevirt-actions-runner
is a custom GitHub Actions runner image designed for use with the Actions Runner Controller (ARC).
This runner provisions ephemeral virtual machines (VMs) using KubeVirt, extending the flexibility and security of your CI/CD workflows.
This is particularly useful for validating scenarios that are not supported by default GitHub-hosted runners, such as:
- Running Windows or macOS jobs
- Custom environments that require specific kernel modules or system services
- Jobs requiring strong isolation from the host system
- Ephemeral VM creation: Launch a fresh VM for every job and destroy it after completion
- Increased isolation: Ideal for untrusted code or complex system configurations
- Custom system-level configuration support
- Easily integrates with ARC and Kubernetes-native tooling
To use this project, ensure you have the following installed:
- A working Kubernetes cluster
- Actions Runner Controller
- KubeVirt
This template will be used to spawn VMs on-demand for each GitHub job. The base VirtualMachine
will never be started; instead, clones of it will be launched as VirtualMachineInstances
.
# Create namespace if it doesn't exist
! kubectl get namespace "${namespace}" && kubectl create namespace "${namespace}"
# Apply the VM template
kubectl apply -f scripts/vm_template.yml -n "${namespace}"
Example snippet from vm_template.yml
:
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: ubuntu-jammy-vm
spec:
runStrategy: Manual
template:
spec:
domain:
devices:
filesystems:
- name: runner-info
virtiofs: {}
The runner-info
volume is mounted at runtime and contains metadata required by the GitHub Actions runner, e.g.:
{
"name": "runner-abcde-abcde",
"token": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"url": "https://github.com/org/repo",
"ephemeral": true,
"groups": "",
"labels": ""
}
The service account used by the runner pods must be granted permissions to manage KubeVirt VMs.
apiVersion: v1
kind: ServiceAccount
metadata:
name: kubevirt-actions-runner
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: kubevirt-actions-runner
rules:
- apiGroups: ["kubevirt.io"]
resources: ["virtualmachines"]
verbs: ["get", "watch", "list"]
- apiGroups: ["kubevirt.io"]
resources: ["virtualmachineinstances"]
verbs: ["get", "watch", "list", "create", "delete"]
- apiGroups: ["cdi.kubevirt.io"]
resources: ["datavolumes"]
verbs: ["get", "watch", "list", "create", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cdi-cloner
rules:
- apiGroups: ["cdi.kubevirt.io"]
resources: ["datavolumes/source"]
verbs: ["create"]
Use Helm to install the GitHub Actions runner scale set.
Create a values.yml file:
githubConfigUrl: https://github.com/<your_enterprise/org/repo>
githubConfigSecret: <your_github_secret>
template:
spec:
serviceAccountName: kubevirt-actions-runner
containers:
- name: runner
image: electrocucaracha/kubevirt-actions-runner:latest
command: []
env:
- name: KUBEVIRT_VM_TEMPLATE
value: ubuntu-jammy-vm
- name: RUNNER_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
Install using Helm:
helm upgrade --create-namespace --namespace "${namespace}" \
--wait --install --values values.yml vm-self-hosted \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set
flowchart TD
subgraph GitHub
A[GitHub Job Triggered]
end
subgraph Kubernetes Cluster
B[Actions Runner Controller]
C[Create kubevirt-actions-runner Pod]
E[Mount runner-info.json]
F[Create VirtualMachineInstance from Template]
G[Boot VirtualMachineInstance]
end
subgraph Virtual Machine
H[Runner fetches GitHub job metadata]
I[Execute Job Steps]
J[Job Completion]
end
subgraph Teardown
K[Cleanup: Terminate VMI & Runner Pod]
end
A --> B --> C --> E --> F --> G --> H --> I --> J --> K
- macOS support: macOS virtualization is not supported via KubeVirt due to licensing constraints.
- Long job durations: Boot time of VMs may increase total runtime.
- Persistent state: Not designed for workflows requiring persisted state between jobs.
Contributions are welcome! Please open issues or submit PRs to help improve this project.
KCD Guadalajara 2025 – Migrating GitHub Actions with Nested Virtualization to the Cloud-Native Ecosystem
This project was presented at Kubernetes Community Days (KCD) Guadalajara 2025, showcasing how to extend GitHub Actions with KubeVirt and nested virtualization to support custom and complex CI/CD workflows in Kubernetes.
The presentation walks through:
- Challenges with standard GitHub-hosted runners
- Benefits of using KubeVirt for GitHub Actions runners
- Live demo deploying and running jobs inside ephemeral VMs
- Lessons learned and architectural considerations