Set Up GitHub Actions Self-Hosted Runner (CentOS Stream 10)ΒΆ

This guide walks you through setting up a CentOS Stream 10 self-hosted runner for the Qubinode KVM Host Setup Collection CI/CD pipeline.

PrerequisitesΒΆ

  • Fresh CentOS Stream 10 installation

  • Root or sudo access

  • Network connectivity to GitHub

  • Minimum 4 CPU cores, 8GB RAM, 50GB storage (recommended)

OverviewΒΆ

The CI/CD pipeline requires a self-hosted runner with:

Component

Requirement

OS

CentOS Stream 10

Python

Python 3.12 (default)

Container Runtime

Podman 5.x (with cgroup v2 support)

Virtualization

KVM/libvirt for integration tests

Step 1: Install Required PackagesΒΆ

Core Container PackagesΒΆ

sudo dnf install -y \
  podman \
  podman-docker \
  buildah \
  skopeo

Git and GitHub CLIΒΆ

# Install via dnf (NOT third-party repo)
sudo dnf install -y \
  git \
  gh

Note: Installing gh via dnf avoids the GPG verification issues encountered with third-party repositories on Rocky Linux 9.

Python DevelopmentΒΆ

sudo dnf install -y \
  python3-pip \
  python3-devel \
  python3-libselinux

Virtualization TestingΒΆ

sudo dnf install -y \
  qemu-kvm \
  libvirt \
  virt-install

Build ToolsΒΆ

sudo dnf install -y \
  gcc \
  make

All-in-One InstallationΒΆ

sudo dnf install -y \
  podman podman-docker buildah skopeo \
  git gh \
  python3-pip python3-devel python3-libselinux \
  qemu-kvm libvirt virt-install \
  gcc make

Step 2: Configure PodmanΒΆ

Enable Rootless PodmanΒΆ

# Enable lingering for the runner user
sudo loginctl enable-linger $(whoami)

# Verify cgroup v2 delegation is enabled
cat /sys/fs/cgroup/cgroup.controllers
# Expected output: cpuset cpu io memory hugetlb pids rdma misc

Configure StorageΒΆ

Ensure adequate storage for container images:

# Check available space
df -h /var/lib/containers

# If needed, configure additional storage
# Edit /etc/containers/storage.conf

Enable Podman Socket (Docker Compatibility)ΒΆ

# For the runner user
systemctl --user enable --now podman.socket

# Verify socket is active
systemctl --user status podman.socket

Step 3: Configure SELinuxΒΆ

SELinux should remain in enforcing mode for accurate testing:

# Verify SELinux is enforcing
getenforce

# If not enforcing, enable it
sudo setenforce 1
sudo sed -i 's/SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config

Step 4: Configure LibvirtΒΆ

Start and Enable ServicesΒΆ

For CentOS Stream 10, libvirt uses modular daemons (see ADR-0016):

# Enable socket-activated services
sudo systemctl enable --now virtqemud.socket
sudo systemctl enable --now virtnetworkd.socket
sudo systemctl enable --now virtstoraged.socket

# Verify services
sudo systemctl status virtqemud.socket

Add Runner User to libvirt GroupΒΆ

sudo usermod -aG libvirt $(whoami)

# Log out and back in, or use newgrp
newgrp libvirt

Step 5: Create Service AccountΒΆ

Create a dedicated service account for the runner:

# Create runner user
sudo useradd -m -s /bin/bash github-runner

# Add to required groups
sudo usermod -aG libvirt github-runner
sudo usermod -aG wheel github-runner  # For sudo access

# Configure sudo for CI operations
echo "github-runner ALL=(ALL) NOPASSWD: /usr/bin/dnf, /usr/bin/podman" | \
  sudo tee /etc/sudoers.d/github-runner
sudo chmod 440 /etc/sudoers.d/github-runner

# Enable lingering for rootless podman
sudo loginctl enable-linger github-runner

Step 6: Install GitHub Actions RunnerΒΆ

Download RunnerΒΆ

# Switch to runner user
sudo -u github-runner -i

# Create runner directory
mkdir -p ~/actions-runner && cd ~/actions-runner

# Download latest runner (check GitHub for current version)
RUNNER_VERSION="2.321.0"
curl -o actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz -L \
  https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz

# Extract
tar xzf actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz

Configure RunnerΒΆ

Get the registration token from GitHub:

  1. Go to Repository Settings > Actions > Runners

  2. Click New self-hosted runner

  3. Copy the registration token

# Configure the runner
./config.sh --url https://github.com/Qubinode/qubinode_kvmhost_setup_collection \
  --token <YOUR_REGISTRATION_TOKEN> \
  --name "centos-stream-10-runner" \
  --labels "self-hosted,Linux,X64,centos-stream-10" \
  --work "_work"

Install as ServiceΒΆ

# Exit back to root/admin user
exit

# Install runner service
cd /home/github-runner/actions-runner
sudo ./svc.sh install github-runner

# Start the service
sudo ./svc.sh start

# Enable on boot
sudo systemctl enable actions.runner.Qubinode-qubinode_kvmhost_setup_collection.centos-stream-10-runner.service

Step 7: Verify InstallationΒΆ

Check Runner StatusΒΆ

# Verify service is running
sudo ./svc.sh status

# Check systemd service
sudo systemctl status actions.runner.*.service

Verify on GitHubΒΆ

  1. Go to Repository Settings > Actions > Runners

  2. Confirm the new runner shows as Idle (green)

Step 8: Test CI PipelineΒΆ

Trigger a test workflow run:

gh workflow run ansible-test.yml --repo Qubinode/qubinode_kvmhost_setup_collection

Expected ResultsΒΆ

Job

Expected

lint

Pass

test (2.18, 3.11)

Pass

test (2.19, 3.11)

Pass

centos-stream10-test

Pass

security

Pass

TroubleshootingΒΆ

Podman Permission IssuesΒΆ

# Verify subuid/subgid ranges
grep github-runner /etc/subuid /etc/subgid

# If missing, add ranges
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 github-runner

SELinux DenialsΒΆ

# Check for denials
sudo ausearch -m avc -ts recent

# Generate policy module if needed
sudo audit2allow -a -M my-runner-policy
sudo semodule -i my-runner-policy.pp

Container Storage IssuesΒΆ

# Reset podman storage
podman system reset

# Verify storage driver
podman info | grep -A5 "graphDriverName"

Runner Connectivity IssuesΒΆ

# Test GitHub connectivity
curl -I https://github.com
curl -I https://api.github.com

# Check runner logs
journalctl -u actions.runner.*.service -f

MaintenanceΒΆ

Regular UpdatesΒΆ

# Weekly system updates
sudo dnf update -y

# Monthly container cleanup
podman system prune -af

# Quarterly runner updates
# Check https://github.com/actions/runner/releases

MonitoringΒΆ

Monitor these paths for disk usage:

  • /var/lib/containers - Container images and layers

  • /home/github-runner/_work - Workflow workspaces

  • /tmp - Temporary build files

ReferencesΒΆ