Overview
This guide covers common issues with GitHub Actions Runner Controller in Kubernetes and how to diagnose and fix them.
Understanding GitHub Actions Runner Architecture
Key Concepts
- AutoscalingRunnerSet: Manages the overall runner configuration
- EphemeralRunner: Individual runner registrations with GitHub
- Pods: Created on-demand when jobs need to run
- minRunners: Number of runners registered with GitHub (NOT running pods)
Important: Pod Behavior
- Normal: No pods exist when no jobs are queued
- On-demand: Pods are created only when GitHub has jobs to run
- Ephemeral: Pods are destroyed after job completion
- minRunners ≠ running pods:
minRunners: 4means 4 registered runners, not 4 running pods
Common Issues and Troubleshooting
Issue 1: Stuck/Terminating Pods
Symptoms:
- Pod stuck in “Terminating” status for extended time
FailedKillPoderrors in events- Timeout errors during container termination
Diagnosis:
# Check pod status
kubectl get pods -n gh-actions-runners-set
# Describe the stuck pod
kubectl describe pod <pod-name> -n gh-actions-runners-set
# Check logs
kubectl logs <pod-name> -n gh-actions-runners-set --tail=50Solution:
# Force delete the stuck pod
kubectl delete pod <pod-name> -n gh-actions-runners-set --force --grace-period=0Issue 2: Failed EphemeralRunners
Symptoms:
- No pods being created for new jobs
failedEphemeralRunners > 0in AutoscalingRunnerSet status- EphemeralRunners stuck in “Failed” status
- Message: “Pod has failed to start more than 5 times”
Diagnosis:
# Check AutoscalingRunnerSet status
kubectl get autoscalingrunnerset mktech224-github-actions-runner-generic -n gh-actions-runners-set -o json | jq '.status'
# List all EphemeralRunners
kubectl get ephemeralrunner -n gh-actions-runners-set -o wide
# Check specific EphemeralRunner
kubectl describe ephemeralrunner <runner-name> -n gh-actions-runners-setSolution:
# Delete failed EphemeralRunners (they will be recreated automatically)
kubectl delete ephemeralrunner -l actions.github.com/scale-set-name=mktech224-github-actions-runner-generic -n gh-actions-runners-set
# Verify new ones are being created
kubectl get ephemeralrunner -n gh-actions-runners-set -o wideif deletion is stuck :
kubectl get ephemeralrunners -n gh-actions-runners-set -o name | xargs -I {} kubectl patch {} -n gh-actions-runners-set -p '{"metadata":{"finalizers":null}}' --type=mergeIssue 3: No Runners Available
Symptoms:
- GitHub Actions jobs stuck in “Queued” status
- No EphemeralRunners exist
currentRunners: 0in AutoscalingRunnerSet
Diagnosis:
# Check if AutoscalingRunnerSet exists and is healthy
kubectl get autoscalingrunnerset -n gh-actions-runners-set
# Check runner controller logs
kubectl logs -l app.kubernetes.io/name=gha-rs-controller -n gh-actions-runners
# Verify GitHub token secret
kubectl get secret github-actions-runner-token -n gh-actions-runners-set -o yamlDiagnostic Commands Reference
Quick Health Check
# Check overall runner set status
kubectl get autoscalingrunnerset -n gh-actions-runners-set
# Check current runners
kubectl get ephemeralrunner -n gh-actions-runners-set -o wide
# Check for any running pods
kubectl get pods -n gh-actions-runners-set
# Check recent events
kubectl get events -n gh-actions-runners-set --sort-by='.lastTimestamp' | tail -20Detailed Investigation
# Get AutoscalingRunnerSet details
kubectl describe autoscalingrunnerset mktech224-github-actions-runner-generic -n gh-actions-runners-set
# Check runner controller deployment
kubectl get deployment -n gh-actions-runners
# View controller logs
kubectl logs -l app.kubernetes.io/name=gha-rs-controller -n gh-actions-runners --tail=100
# Check for resource constraints
kubectl top nodes
kubectl top pods -n gh-actions-runners-setStep-by-Step Troubleshooting Process
Step 1: Identify the Problem
- Check if jobs are stuck in GitHub Actions UI
- Verify AutoscalingRunnerSet status
- List EphemeralRunners and their states
- Look for stuck or failed pods
Step 2: Gather Information
# Quick status overview
kubectl get autoscalingrunnerset,ephemeralrunner,pods -n gh-actions-runners-set
# Check for errors in events
kubectl get events -n gh-actions-runners-set --field-selector type=Warning
# Review controller logs
kubectl logs -l app.kubernetes.io/name=gha-rs-controller -n gh-actions-runners --since=1hStep 3: Apply Appropriate Fix
- Stuck pods: Force delete them
- Failed EphemeralRunners: Delete them (auto-recreated)
- Missing runners: Check controller and GitHub token
- Resource issues: Scale cluster or adjust resource requests
Step 4: Verify Resolution
# Wait for new runners to be created
kubectl get ephemeralrunner -n gh-actions-runners-set -w
# Test with a simple workflow
# Trigger a GitHub Actions job and verify pod creation
# Monitor pod lifecycle
kubectl get pods -n gh-actions-runners-set -wPrevention and Best Practices
Monitoring
- Set up alerts for failed EphemeralRunners
- Monitor pod termination times
- Track job queue times in GitHub
Maintenance
- Regularly clean up old failed runners
- Update runner images periodically
- Monitor cluster resource usage
Configuration
- Set appropriate resource requests/limits
- Configure proper storage classes for ephemeral volumes
- Use node selectors if needed for runner placement
Expected Behavior vs Issues
✅ Normal Behavior
- No pods when no jobs are queued
- Pods created quickly when jobs start
- EphemeralRunners in “Pending” status when idle
- Clean pod termination after job completion
❌ Problem Indicators
- Pods stuck in “Terminating” for >5 minutes
- EphemeralRunners in “Failed” status
- Jobs queued but no pods created
- Frequent pod creation failures
Emergency Recovery
If runners are completely broken:
# 1. Delete all failed runners
kubectl delete ephemeralrunner --all -n gh-actions-runners-set
# 2. Restart the runner controller
kubectl rollout restart deployment -l app.kubernetes.io/name=gha-runner-scale-set-controller -n actions-runner-system
# 3. If needed, recreate the runner set
helm uninstall <runner-set-name> -n gh-actions-runners-set
# Then reinstall with helm/fluxRemember: GitHub Actions Runner Controller is designed to be ephemeral and self-healing. Most issues resolve automatically when problematic resources are deleted and allowed to recreate.