Enhances PickPlatform to validate schema when runs-on includes explicit mode (e.g., "linux:host" or "ubuntu:docker"). Parses schema suffix from runs-on values and ensures it matches the runner's configured schema for that label. Returns empty string on schema mismatch to prevent jobs from running in wrong environment (e.g., workflow requesting :host but runner only has :docker). Adds test coverage for schema matching, mismatches, and backward compatibility with schema-less runs-on values.
GitCaddy Runner
A Gitea Actions runner with enhanced capability detection and reporting for AI-friendly workflow generation.
GitCaddy Runner is a hard fork of Gitea's act_runner, rebranded and enhanced with automated capability detection to enable AI tools to generate compatible workflows based on available resources.
Features
- Automated Capability Detection: Automatically identifies OS, architecture, installed tools, and available resources
- Concurrent Job Execution: Configure runner capacity to handle multiple jobs simultaneously
- Docker Support: Full support for Docker and Docker Compose workflows
- Xcode Integration: Detects Xcode installations, SDKs, and simulators on macOS
- Tool Detection: Identifies installed tools (Node.js, Python, .NET, Go, Ruby, Swift, etc.)
- AI-Friendly API: Exposes capabilities through Gitea's API for automated workflow generation
- Cache Support: Built-in workflow cache support for faster builds
Installation
Pre-built Binaries
Download the latest release for your platform from the releases page:
macOS:
# Apple Silicon (M1/M2/M3/M4)
curl -L -o gitcaddy-runner https://git.marketally.com/gitcaddy/gitcaddy-runner/releases/download/v1.0.0/gitcaddy-runner-1.0.0-darwin-arm64
chmod +x gitcaddy-runner
# Intel
curl -L -o gitcaddy-runner https://git.marketally.com/gitcaddy/gitcaddy-runner/releases/download/v1.0.0/gitcaddy-runner-1.0.0-darwin-amd64
chmod +x gitcaddy-runner
Linux:
# x86_64
curl -L -o gitcaddy-runner https://git.marketally.com/gitcaddy/gitcaddy-runner/releases/download/v1.0.0/gitcaddy-runner-1.0.0-linux-amd64
chmod +x gitcaddy-runner
# ARM64
curl -L -o gitcaddy-runner https://git.marketally.com/gitcaddy/gitcaddy-runner/releases/download/v1.0.0/gitcaddy-runner-1.0.0-linux-arm64
chmod +x gitcaddy-runner
Windows:
# Download the Windows executable
# https://git.marketally.com/gitcaddy/gitcaddy-runner/releases/download/v1.0.0/gitcaddy-runner-1.0.0-windows-amd64.exe
Build from Source
git clone https://git.marketally.com/gitcaddy/gitcaddy-runner.git
cd gitcaddy-runner
make build
Quick Start
1. Enable Gitea Actions
In your Gitea app.ini:
[actions]
ENABLED = true
2. Generate Configuration
./gitcaddy-runner generate-config > config.yaml
3. Configure the Runner
Edit config.yaml to customize settings. Important configuration options:
log:
level: info
runner:
file: .runner
capacity: 2 # Number of concurrent jobs (default: 1)
timeout: 3h
shutdown_timeout: 3m # Grace period for running jobs on shutdown
insecure: false
fetch_timeout: 5s
fetch_interval: 2s
labels:
- "ubuntu-latest:docker://node:16-bullseye"
- "ubuntu-22.04:docker://node:16-bullseye"
cache:
enabled: true
dir: ""
container:
network: ""
privileged: false
options: ""
valid_volumes: []
docker_host: ""
force_pull: false
host:
workdir_parent: ""
Capacity Configuration
The capacity setting controls how many jobs the runner can execute simultaneously:
- Default: 1 (one job at a time)
- Recommended: 2-4 for multi-core systems
- Considerations:
- Each job consumes CPU, memory, and disk I/O
- iOS/macOS builds are resource-intensive (start with 2)
- Lighter builds (Node.js, Go) can handle higher capacity (4-6)
- Monitor system load and adjust accordingly
Example for different workloads:
# Light builds (web apps, APIs)
runner:
capacity: 4
# Mixed builds
runner:
capacity: 2
# Heavy builds (iOS/macOS, large containers)
runner:
capacity: 1
4. Register the Runner
./gitcaddy-runner register \
--instance https://your-gitea-instance.com \
--token YOUR_REGISTRATION_TOKEN \
--name my-runner \
--labels ubuntu-latest:docker://node:16-bullseye
The registration token can be obtained from:
- Gitea Admin Panel > Actions > Runners
- Or repository Settings > Actions > Runners
5. Start the Runner
Important: Always specify the config file path with -c flag:
./gitcaddy-runner daemon -c config.yaml
Without the -c flag, the runner will use default settings and ignore your config.yaml!
Running as a Service
macOS (launchd)
Create ~/Library/LaunchAgents/com.gitcaddy.runner.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.gitcaddy.runner</string>
<key>ProgramArguments</key>
<array>
<string>/path/to/gitcaddy-runner</string>
<string>daemon</string>
<string>-c</string>
<string>/path/to/config.yaml</string>
</array>
<key>WorkingDirectory</key>
<string>/path/to/runner/directory</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/path/to/runner.log</string>
<key>StandardErrorPath</key>
<string>/path/to/runner.err</string>
</dict>
</plist>
Load the service:
launchctl load ~/Library/LaunchAgents/com.gitcaddy.runner.plist
Linux (systemd)
Create /etc/systemd/system/gitcaddy-runner.service:
[Unit]
Description=GitCaddy Actions Runner
After=network.target
[Service]
Type=simple
User=runner
WorkingDirectory=/home/runner/gitcaddy-runner
ExecStart=/home/runner/gitcaddy-runner/gitcaddy-runner daemon -c /home/runner/gitcaddy-runner/config.yaml
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable gitcaddy-runner
sudo systemctl start gitcaddy-runner
Windows (NSSM or Native Service)
GitCaddy Runner has native Windows service support. When running as a service, it automatically detects the Windows Service Control Manager (SCM) and handles stop/shutdown signals properly.
Option 1: Using NSSM (Recommended)
Install NSSM via Chocolatey:
choco install nssm -y
Create the service:
# Install the service
nssm install GiteaRunnerSvc C:\gitea-runner\gitcaddy-runner.exe daemon --config C:\gitea-runner\config.yaml
# Set working directory
nssm set GiteaRunnerSvc AppDirectory C:\gitea-runner
# Set environment variables
nssm set GiteaRunnerSvc AppEnvironmentExtra HOME=C:\gitea-runner USERPROFILE=C:\gitea-runner
# Configure auto-restart on failure
sc failure GiteaRunnerSvc reset=86400 actions=restart/60000/restart/60000/restart/60000
# Start the service
sc start GiteaRunnerSvc
Option 2: Native sc.exe (requires wrapper)
Create a wrapper batch file C:\gitea-runner\start-runner.bat:
@echo off
set HOME=C:\gitea-runner
set USERPROFILE=C:\gitea-runner
cd /d C:\gitea-runner
C:\gitea-runner\gitcaddy-runner.exe daemon --config C:\gitea-runner\config.yaml
Service Management:
# Check service status
sc query GiteaRunnerSvc
# Start service
sc start GiteaRunnerSvc
# Stop service
sc stop GiteaRunnerSvc
# View service logs (if using NSSM with log rotation)
Get-Content C:\gitea-runner\logs\runner.log -Tail 50
Environment Variables for Windows Services:
| Variable | Description | Example |
|---|---|---|
GITEA_RUNNER_SERVICE_NAME |
Override service name detection | GiteaRunnerSvc |
Capability Detection
GitCaddy Runner automatically detects and reports system capabilities:
Platform Information
- Operating system (darwin, linux, windows)
- Architecture (amd64, arm64)
Container Runtime
- Docker availability and version
- Docker Compose support
- Container runtime type
Development Tools
- Node.js, npm, yarn
- Python, pip
- Go
- .NET
- Ruby
- Rust
- Java
- Swift (macOS)
- Git, Make
macOS-Specific
- Xcode version and build
- Available SDKs (iOS, macOS, tvOS, watchOS, visionOS)
- Simulators
- Code signing tools (codesign, pkgbuild)
- Package managers (Homebrew, CocoaPods, Fastlane)
System Resources
- CPU cores
- Load average
- Disk space and usage
- Network bandwidth
Example Capabilities Output
{
"os": "darwin",
"arch": "arm64",
"capacity": 2,
"docker": true,
"docker_compose": true,
"container_runtime": "docker",
"xcode": {
"version": "15.2",
"build": "15C500b",
"sdks": ["iOS 17.2", "macOS 14.2"]
},
"tools": {
"node": ["20.11"],
"python": ["3.11"],
"swift": ["5.9"]
},
"build_tools": ["fastlane", "cocoapods", "codesign"],
"cpu": {
"num_cpu": 10,
"load_percent": 25.5
},
"disk": {
"free_bytes": 54199226368,
"used_percent": 77.89
}
}
Configuration Reference
Runner Section
| Option | Type | Default | Description |
|---|---|---|---|
capacity |
int | 1 | Maximum concurrent jobs |
timeout |
duration | 3h | Maximum job execution time |
shutdown_timeout |
duration | 3m | Grace period for jobs to complete on shutdown |
insecure |
bool | false | Allow insecure HTTPS |
fetch_timeout |
duration | 5s | Timeout for fetching tasks |
fetch_interval |
duration | 2s | Interval between task fetches |
labels |
[]string | [] | Runner labels for job matching |
env_file |
string | .env | Environment variables file |
Cache Section
| Option | Type | Default | Description |
|---|---|---|---|
enabled |
bool | true | Enable cache support |
dir |
string | "" | Cache directory path |
host |
string | "" | External cache server host |
port |
int | 0 | External cache server port |
Container Section
| Option | Type | Default | Description |
|---|---|---|---|
network |
string | "" | Docker network for containers |
privileged |
bool | false | Run containers in privileged mode |
docker_host |
string | "" | Custom Docker host |
force_pull |
bool | false | Always pull latest images |
Troubleshooting
Capacity Not Being Applied
Problem: Runner shows "capacity":1 even though config.yaml has capacity: 2
Solution: Ensure you're using the -c flag when starting the daemon:
# ✅ Correct
./gitcaddy-runner daemon -c /path/to/config.yaml
# ❌ Wrong - uses defaults
./gitcaddy-runner daemon
Verify the config is being loaded:
# Check runner process
ps aux | grep gitcaddy-runner
# Should show: gitcaddy-runner daemon -c /path/to/config.yaml
Docker Not Detected
Problem: Capabilities show "docker":false but Docker is installed
Solution:
-
Ensure Docker Desktop/daemon is running:
docker ps -
Restart the runner after starting Docker:
./gitcaddy-runner daemon -c config.yaml -
Check Docker socket permissions:
ls -l /var/run/docker.sock
Jobs Not Running Concurrently
Problem: Jobs queue instead of running in parallel
Checklist:
- Verify capacity in capabilities output (check runner logs)
- Confirm config.yaml has
capacity > 1 - Ensure runner was started with
-c config.yamlflag - Check system resources aren't maxed out
- Restart runner after config changes
Runner Not Starting
Problem: Runner exits immediately or fails to start
Common causes:
- Invalid config.yaml syntax
.runnerfile missing (runregisterfirst)- Permission issues on working directory
- Invalid Gitea instance URL or token
Debug steps:
# Check config syntax
./gitcaddy-runner generate-config > test-config.yaml
diff config.yaml test-config.yaml
# Test with verbose logging
./gitcaddy-runner daemon -c config.yaml --log-level debug
# Verify registration
cat .runner
Environment Variables
GitCaddy Runner supports environment variable configuration:
| Variable | Description | Example |
|---|---|---|
GITEA_RUNNER_CAPACITY |
Override capacity setting | GITEA_RUNNER_CAPACITY=2 |
GITEA_RUNNER_ENV_FILE |
Custom env file path | GITEA_RUNNER_ENV_FILE=.env.prod |
API Integration
Query runner capabilities via Gitea API:
curl -H "Authorization: token YOUR_TOKEN" \
https://your-gitea.com/api/v1/runners
Use capabilities to generate compatible workflows:
# Example: Use capabilities to select appropriate runner
name: Build
on: [push]
jobs:
build:
runs-on: ${{ capabilities.os == 'darwin' && 'macos-latest' || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@v3
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
License
MIT License - see LICENSE for details.
Support
- Issues: https://git.marketally.com/gitcaddy/gitcaddy-runner/issues
- Discussions: https://git.marketally.com/gitcaddy/gitcaddy-runner/discussions
Acknowledgments
GitCaddy Runner is a hard fork of Gitea's act_runner, rebranded and enhanced with automated capability detection and reporting features for AI-friendly workflow generation.
GitCaddy Runner - User Guide
A CI/CD runner for Gitea Actions that executes workflows defined in .gitea/workflows/ directories. This runner connects to your Gitea instance and picks up jobs to execute them in Docker containers or directly on the host machine.
Table of Contents
- Installation
- Getting Started
- Registration
- Running the Daemon
- Configuration
- Labels and Execution Environments
- Docker Deployment
- Kubernetes Deployment
- Common Workflows
- Artifact Upload Helper
- Disk Space Management
- Cache Server
- Troubleshooting
- Best Practices
Installation
From Binary
Download the latest release for your platform:
# Linux AMD64
wget https://git.marketally.com/gitcaddy/gitcaddy-runner/releases/download/v1.0.0/gitcaddy-runner-1.0.0-linux-amd64
# macOS ARM64
wget https://git.marketally.com/gitcaddy/gitcaddy-runner/releases/download/v1.0.0/gitcaddy-runner-1.0.0-darwin-12-arm64
# Windows AMD64
wget https://git.marketally.com/gitcaddy/gitcaddy-runner/releases/download/v1.0.0/gitcaddy-runner-1.0.0-windows-amd64.exe
Make the binary executable:
chmod +x gitcaddy-runner-1.0.0-linux-amd64
sudo mv gitcaddy-runner-1.0.0-linux-amd64 /usr/local/bin/gitcaddy-runner
From Source
Requirements:
- Go 1.23 or later
- Docker (if using Docker-based workflows)
git clone https://git.marketally.com/gitcaddy/gitcaddy-runner.git
cd gitcaddy-runner
make build
sudo mv gitcaddy-runner /usr/local/bin/
Verify Installation
gitcaddy-runner --version
Getting Started
Prerequisites
- Gitea Instance: You need a running Gitea instance (v1.21 or later recommended)
- Docker (optional but recommended): For running workflows in containers
- Registration Token: Obtain from your Gitea instance:
- Go to your repository → Settings → Actions → Runners
- Click "Create new runner" and copy the registration token
Quick Start
- Generate a configuration file:
gitcaddy-runner generate-config > config.yaml
- Register the runner:
gitcaddy-runner register \
--instance https://gitea.example.com \
--token YOUR_REGISTRATION_TOKEN \
--name my-runner \
--labels "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
- Start the runner daemon:
gitcaddy-runner daemon
Registration
The runner must be registered with your Gitea instance before it can execute jobs.
Interactive Registration
Run the registration command without flags for an interactive setup:
gitcaddy-runner register
You'll be prompted for:
- Gitea instance URL:
https://gitea.example.com/ - Registration token: Obtained from Gitea UI
- Runner name: Defaults to hostname if left empty
- Labels: Comma-separated list of labels (or press Enter for defaults)
Non-Interactive Registration
For automation or scripts:
gitcaddy-runner register \
--no-interactive \
--instance https://gitea.example.com \
--token YOUR_TOKEN \
--name production-runner \
--labels "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest,ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
Ephemeral Runners
For single-use runners (useful for auto-scaling):
gitcaddy-runner register \
--ephemeral \
--instance https://gitea.example.com \
--token YOUR_TOKEN \
--name ephemeral-runner
Ephemeral runners automatically unregister after completing one job.
Registration File
Registration information is stored in .runner (by default). This file contains:
- Runner UUID and token
- Runner name
- Configured labels
- Gitea instance address
Important: Keep this file secure as it contains authentication credentials.
Running the Daemon
Basic Usage
Start the runner daemon to begin accepting jobs:
gitcaddy-runner daemon
With a custom configuration file:
gitcaddy-runner daemon --config /path/to/config.yaml
Run Once Mode
Execute a single job and then exit:
gitcaddy-runner daemon --once
This is useful for:
- Testing runner setup
- Ephemeral runners in auto-scaling environments
- Scheduled job execution
Background Execution
Run as a background service using systemd:
Create /etc/systemd/system/gitcaddy-runner.service:
[Unit]
Description=GitCaddy Runner
After=network.target docker.service
Requires=docker.service
[Service]
Type=simple
User=gitea-runner
WorkingDirectory=/home/gitea-runner
ExecStart=/usr/local/bin/gitcaddy-runner daemon --config /home/gitea-runner/config.yaml
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable gitcaddy-runner
sudo systemctl start gitcaddy-runner
sudo systemctl status gitcaddy-runner
Configuration
Generate Default Configuration
gitcaddy-runner generate-config > config.yaml
Configuration File Structure
log:
level: info # trace, debug, info, warn, error, fatal
runner:
file: .runner # Registration file path
capacity: 1 # Number of concurrent jobs
timeout: 3h # Job timeout
shutdown_timeout: 0s # Graceful shutdown timeout
insecure: false # Skip TLS verification
fetch_timeout: 5s # Job fetch timeout
fetch_interval: 2s # Job fetch interval
github_mirror: '' # Mirror for GitHub actions
envs: # Extra environment variables
NODE_ENV: production
env_file: .env # Load environment from file
labels: # Runner labels
- "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
cache:
enabled: true
dir: "" # Cache directory (default: $HOME/.cache/actcache)
host: "" # Cache server host (auto-detected)
port: 0 # Cache server port (0 = random)
external_server: "" # External cache server URL
container:
network: "" # Docker network (empty = auto-create)
privileged: false # Run containers in privileged mode
options: "" # Additional docker run options
workdir_parent: workspace # Parent directory for job workspaces
valid_volumes: # Allowed volume mounts (glob patterns)
- '**'
docker_host: "" # Docker daemon socket (auto-detected)
force_pull: true # Always pull images
force_rebuild: false # Rebuild images even if present
require_docker: false # Require Docker daemon
docker_timeout: 0s # Docker daemon startup timeout
host:
workdir_parent: "" # Host workspace directory (default: $HOME/.cache/act)
Environment Variables
Legacy environment variables (deprecated but still supported):
GITEA_DEBUG: Enable debug loggingGITEA_TRACE: Enable trace loggingGITEA_RUNNER_CAPACITY: Set runner capacityGITEA_RUNNER_FILE: Set registration file pathGITEA_RUNNER_ENVIRON: Set environment variables (comma-separatedkey:value)GITEA_RUNNER_ENV_FILE: Load environment from file
Note: Configuration file settings take precedence over environment variables.
Labels and Execution Environments
Labels determine which jobs a runner can execute and how they run.
Label Format
label-name:schema:argument
- label-name: Identifier used in workflow
runs-on - schema: Execution environment (
dockerorhost) - argument: Additional configuration (e.g., Docker image)
Docker Labels
Run jobs in Docker containers:
labels:
- "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
- "ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
- "node:docker://node:18"
- "python:docker://python:3.11"
Workflow usage:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: echo "Running in Ubuntu container"
Host Labels
Run jobs directly on the host machine:
labels:
- "self-hosted:host"
- "linux:host"
- "macos:host"
Workflow usage:
jobs:
build:
runs-on: self-hosted
steps:
- uses: actions/checkout@v3
- run: echo "Running on host"
Custom Images
Use custom Docker images:
labels:
- "custom-env:docker://registry.example.com/my-build-env:latest"
Multiple Labels
A runner can have multiple labels to support different job types:
labels:
- "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
- "ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
- "self-hosted:host"
- "gpu:host"
Docker Deployment
Basic Docker Run
docker run -d \
--name gitcaddy-runner \
-e GITEA_INSTANCE_URL=https://gitea.example.com \
-e GITEA_RUNNER_REGISTRATION_TOKEN=YOUR_TOKEN \
-e GITEA_RUNNER_NAME=docker-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /data/runner:/data \
marketally/gitcaddy-runner:latest
Docker Compose
Create docker-compose.yml:
version: '3'
services:
runner:
image: marketally/gitcaddy-runner:latest
environment:
- GITEA_INSTANCE_URL=https://gitea.example.com
- GITEA_RUNNER_REGISTRATION_TOKEN=YOUR_TOKEN
- GITEA_RUNNER_NAME=compose-runner
- GITEA_RUNNER_LABELS=ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./runner-data:/data
restart: unless-stopped
Start:
docker-compose up -d
Docker-in-Docker (DinD)
For isolated Docker environments:
version: '3'
services:
runner:
image: marketally/gitcaddy-runner:latest-dind
privileged: true
environment:
- GITEA_INSTANCE_URL=https://gitea.example.com
- GITEA_RUNNER_REGISTRATION_TOKEN=YOUR_TOKEN
- DOCKER_TLS_CERTDIR=/certs
volumes:
- runner-data:/data
- docker-certs:/certs
restart: unless-stopped
volumes:
runner-data:
docker-certs:
Rootless Docker
For enhanced security:
version: '3'
services:
runner:
image: marketally/gitcaddy-runner:latest-dind-rootless
environment:
- GITEA_INSTANCE_URL=https://gitea.example.com
- GITEA_RUNNER_REGISTRATION_TOKEN=YOUR_TOKEN
- DOCKER_HOST=unix:///run/user/1000/docker.sock
volumes:
- runner-data:/data
restart: unless-stopped
security_opt:
- seccomp:unconfined
volumes:
runner-data:
Kubernetes Deployment
Using Docker-in-Docker
See examples/kubernetes/dind-docker.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gitcaddy-runner-vol
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Secret
metadata:
name: runner-secret
type: Opaque
data:
token: <base64-encoded-registration-token>
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitcaddy-runner
spec:
replicas: 1
selector:
matchLabels:
app: gitcaddy-runner
template:
metadata:
labels:
app: gitcaddy-runner
spec:
volumes:
- name: docker-certs
emptyDir: {}
- name: runner-data
persistentVolumeClaim:
claimName: gitcaddy-runner-vol
containers:
- name: runner
image: git.marketally.com/gitcaddy/gitcaddy-runner:latest
command: ["sh", "-c", "while ! nc -z localhost 2376 </dev/null; do echo 'waiting for docker daemon...'; sleep 5; done; /sbin/tini -- run.sh"]
env:
- name: DOCKER_HOST
value: tcp://localhost:2376
- name: DOCKER_CERT_PATH
value: /certs/client
- name: DOCKER_TLS_VERIFY
value: "1"
- name: GITEA_INSTANCE_URL
value: http://gitcaddy-http.gitcaddy.svc.cluster.local:3000
- name: GITEA_RUNNER_REGISTRATION_TOKEN
valueFrom:
secretKeyRef:
name: runner-secret
key: token
volumeMounts:
- name: docker-certs
mountPath: /certs
- name: runner-data
mountPath: /data
- name: daemon
image: docker:23.0.6-dind
env:
- name: DOCKER_TLS_CERTDIR
value: /certs
securityContext:
privileged: true
volumeMounts:
- name: docker-certs
mountPath: /certs
Apply:
kubectl apply -f dind-docker.yaml
Using Rootless Docker
See examples/kubernetes/rootless-docker.yaml for a more secure rootless setup.
Common Workflows
Basic CI Workflow
Create .gitea/workflows/ci.yaml:
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Run tests
run: go test ./...
- name: Build
run: go build -v ./...
Multi-Platform Build
name: Build
on: [push]
jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: make build-linux
build-macos:
runs-on: macos
steps:
- uses: actions/checkout@v3
- run: make build-macos
build-windows:
runs-on: windows
steps:
- uses: actions/checkout@v3
- run: make build-windows
Using Caching
name: Build with Cache
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Cache dependencies
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Build
run: go build ./...
Using Artifacts
Important: GitCaddy Runner does not support actions/upload-artifact@v4 or actions/download-artifact@v4. Use v3 instead:
name: Build and Upload
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build
run: make build
- name: Upload artifact
uses: actions/upload-artifact@v3 # Note: v3, not v4
with:
name: my-artifact
path: dist/
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download artifact
uses: actions/download-artifact@v3 # Note: v3, not v4
with:
name: my-artifact
path: dist/
- name: Deploy
run: ./deploy.sh
Using Services
name: Integration Tests
on: [push]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- name: Run integration tests
env:
DATABASE_URL: postgres://postgres:postgres@postgres:5432/test
run: go test -tags=integration ./...
Artifact Upload Helper
For large files or unreliable networks, use the built-in upload helper with retry logic:
gitcaddy-upload \
-url https://gitea.example.com/api/v1/repos/owner/repo/releases/1/assets \
-token YOUR_TOKEN \
-file ./large-artifact.zip \
-retries 10
Options:
-url: Upload endpoint URL-token: Authentication token-file: File to upload-retries: Maximum retry attempts (default: 5)
The upload helper automatically:
- Retries on network failures
- Pre-warms connections
- Uses chunked uploads for large files
- Provides detailed progress logging
Disk Space Management
The runner includes automatic disk space monitoring and cleanup capabilities.
Automatic Cleanup
The runner automatically monitors disk usage and triggers cleanup when:
- Disk usage exceeds 85% (warning threshold)
- Disk usage exceeds 95% (critical threshold)
Cleanup targets:
- Old cache directories (>24 hours)
- Old work directories (>48 hours)
- Old artifact staging files (>72 hours)
- System temp files (>24 hours)
- Build tool caches (>7 days): Go, npm, pip, Maven, Gradle, NuGet, Cargo, etc.
Manual Cleanup
Trigger cleanup manually:
gitcaddy-runner cleanup --config config.yaml
Output example:
Cleanup completed: freed 15728640000 bytes, deleted 1234 files in 5.2s
Monitoring Disk Space
The runner reports disk space in its capabilities:
{
"disk": {
"path": "/workspace",
"total_bytes": 107374182400,
"free_bytes": 32212254720,
"used_bytes": 75161927680,
"used_percent": 70.0
}
}
Best Practices
- Monitor disk usage: Check runner logs for disk space warnings
- Configure cleanup: Adjust cache retention in config.yaml
- Use ephemeral runners: For auto-scaling environments
- Separate volumes: Use dedicated volumes for runner data
Cache Server
The runner includes a built-in cache server for actions/cache.
Automatic Cache Server
Enabled by default in the configuration:
cache:
enabled: true
dir: "" # Default: $HOME/.cache/actcache
host: "" # Auto-detected
port: 0 # Random available port
The cache server URL is automatically provided to jobs via ACTIONS_CACHE_URL.
External Cache Server
Use an external cache server:
cache:
enabled: true
external_server: "http://cache.example.com:8080/"
Standalone Cache Server
Run the cache server independently:
gitcaddy-runner cache-server \
--dir /path/to/cache \
--host 0.0.0.0 \
--port 8080
Options:
--dir: Cache storage directory--host: Listen address--port: Listen port
Troubleshooting
Runner Not Picking Up Jobs
Check registration:
cat .runner
Verify the runner appears in Gitea UI (Settings → Actions → Runners).
Check labels: Ensure workflow runs-on matches a runner label.
Check logs:
gitcaddy-runner daemon --config config.yaml
Look for connection errors or authentication issues.
Docker Connection Issues
Error: Cannot ping the docker daemon
Solutions:
- Verify Docker is running:
docker ps
- Check Docker socket path:
ls -la /var/run/docker.sock
- Add user to docker group:
sudo usermod -aG docker $USER
newgrp docker
- Specify Docker host in config:
container:
docker_host: "unix:///var/run/docker.sock"
Timeout Issues
Error: Job timeout after 3 hours
Solution: Increase timeout in config:
runner:
timeout: 6h
Disk Space Issues
Error: No space left on device
Solutions:
- Run manual cleanup:
gitcaddy-runner cleanup
-
Increase disk space or use dedicated volume
-
Configure more aggressive cleanup:
cache:
dir: /path/to/larger/disk
SSL/TLS Certificate Issues
Error: x509: certificate signed by unknown authority
Solution (not recommended for production):
runner:
insecure: true
Better solution: Install proper CA certificates:
sudo cp your-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
Actions Not Found
Error: unable to resolve action
Solution: Configure GitHub mirror if needed:
runner:
github_mirror: 'https://github.mirror.example.com'
Artifact Upload Failures
Error: actions/upload-artifact@v4 not supported
Solution: Use v3 instead:
- uses: actions/upload-artifact@v3 # Not v4
with:
name: my-artifact
path: dist/
For large files with unreliable networks, use the upload helper:
gitcaddy-upload -url $URL -token $TOKEN -file artifact.zip
Best Practices
Security
- Keep registration file secure: The
.runnerfile contains authentication credentials - Use secrets: Never hardcode sensitive data in workflows
- Limit volume mounts: Restrict
valid_volumesin configuration - Use rootless Docker: When possible, use rootless containers
- Regular updates: Keep runner and Docker images up to date
Performance
- Use caching: Cache dependencies to speed up builds
- Parallel jobs: Increase
capacityfor concurrent job execution - Local images: Use
force_pull: falsefor frequently used images - Dedicated volumes: Use fast storage for workspaces and cache
Reliability
- Monitor disk space: Watch for low disk space warnings
- Set appropriate timeouts: Balance between job completion and resource usage
- Use health checks: Monitor runner process and Docker daemon
- Graceful shutdown: Configure
shutdown_timeoutfor clean termination - Log rotation: Implement log rotation to prevent disk fill
Scalability
- Ephemeral runners: Use
--ephemeralfor auto-scaling - Multiple runners: Deploy multiple runners for load distribution
- Label-based routing: Use labels to route jobs to appropriate runners
- Resource limits: Set Docker resource limits in
container.options
Maintenance
- Regular cleanup: Run periodic manual cleanup or rely on automatic cleanup
- Update images: Keep runner images and workflow images current
- Monitor logs: Check logs for warnings and errors
- Test configuration: Validate config changes in staging first
- Backup registration: Keep backup of
.runnerfile
Workflow Best Practices
- Use specific versions: Pin action versions (e.g.,
@v3, not@latest) - Minimize steps: Combine related commands
- Use artifacts wisely: Only upload necessary files
- Clean up: Remove temporary files in workflows
- Test locally: Use
gitcaddy-runner execto test workflows locally
Example Production Setup
# config.yaml
log:
level: info
runner:
capacity: 4
timeout: 2h
shutdown_timeout: 5m
fetch_interval: 2s
labels:
- "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
- "ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
cache:
enabled: true
dir: /mnt/fast-storage/cache
container:
network: gitea-actions
force_pull: false
workdir_parent: /mnt/fast-storage/workspace
valid_volumes:
- /mnt/artifacts/**
docker_host: unix:///var/run/docker.sock
host:
workdir_parent: /mnt/fast-storage/host-workspace
This configuration provides:
- 4 concurrent jobs
- 2-hour job timeout with 5-minute graceful shutdown
- Fast storage for cache and workspaces
- Restricted volume mounts for security
- Optimized image pulling