Files
michaelschiemer/deployment/gitea-runner/README.md

14 KiB

Gitea Actions Runner (Development Machine)

Self-hosted Gitea Actions runner for executing CI/CD workflows on the development machine.

Overview

This setup provides a Gitea Actions runner that executes CI/CD workflows triggered by repository events in Gitea. The runner runs in Docker and uses Docker-in-Docker (DinD) for isolated job execution.

Key Features:

  • Self-Hosted: Runs on development machine with full control
  • Docker-Based: Isolated execution environment for jobs
  • Docker-in-Docker: Jobs run in separate containers for security
  • Multiple Labels: Support for different workflow environments
  • Auto-Restart: Automatically restarts on failure
  • Secure: Isolated network and resource limits

Prerequisites

  • Docker and Docker Compose installed
  • Gitea instance running (Stack 2: Gitea)
  • Admin access to Gitea for runner registration
  • Network connectivity to Gitea instance

Directory Structure

gitea-runner/
├── docker-compose.yml          # Service definitions
├── .env.example               # Environment template
├── .env                       # Environment configuration (create from .env.example)
├── config.yaml                # Runner configuration
├── register.sh                # Registration script
├── unregister.sh              # Unregistration script
├── data/                      # Runner data (auto-created)
│   └── .runner               # Registration info (auto-generated)
└── README.md                  # This file

Quick Start

1. Create Environment File

cd deployment/gitea-runner
cp .env.example .env

2. Get Registration Token

  1. Go to Gitea admin panel: https://git.michaelschiemer.de/admin
  2. Navigate to: Site Administration > Actions > Runners
  3. Click "Create New Runner"
  4. Copy the registration token
  5. Add token to .env file:
nano .env
# Set GITEA_RUNNER_REGISTRATION_TOKEN=<your-token>

3. Configure Environment Variables

Edit .env and configure:

# Gitea Instance URL
GITEA_INSTANCE_URL=https://git.michaelschiemer.de

# Registration Token (from step 2)
GITEA_RUNNER_REGISTRATION_TOKEN=<your-token>

# Runner Name (appears in Gitea UI)
GITEA_RUNNER_NAME=dev-runner-01

# Runner Labels (what environments this runner supports)
GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:16-bullseye,ubuntu-22.04:docker://node:16-bullseye

4. Register Runner

Run the registration script:

./register.sh

This will:

  • Start the runner services
  • Register the runner with Gitea
  • Display runner status

5. Verify Registration

Check runner status in Gitea:

Configuration

Runner Labels

Labels define what workflow environments the runner supports. Format: label:image

Common Labels:

# Ubuntu with Node.js 16
ubuntu-latest:docker://node:16-bullseye

# Ubuntu 22.04
ubuntu-22.04:docker://node:16-bullseye

# Debian
debian-latest:docker://debian:bullseye

# Custom images from private registry
ubuntu-php:docker://registry.michaelschiemer.de/php:8.3-cli

Example Workflow Using Labels:

# .gitea/workflows/test.yml
name: Test
on: [push]

jobs:
  test:
    runs-on: ubuntu-latest  # Uses runner with this label
    steps:
      - uses: actions/checkout@v3
      - run: npm install
      - run: npm test

Runner Capacity

Control how many jobs can run concurrently:

In .env:

GITEA_RUNNER_CAPACITY=1  # Max concurrent jobs

In config.yaml:

runner:
  capacity: 1  # Max concurrent jobs
  timeout: 3h  # Job timeout

Resource Limits

Configure resource limits in config.yaml:

container:
  resources:
    memory_limit: 2147483648  # 2GB
    cpu_quota: 100000         # 1 CPU

Usage

Start Runner

# Start services
docker compose up -d

# View logs
docker compose logs -f gitea-runner

Stop Runner

docker compose down

Restart Runner

docker compose restart gitea-runner

View Logs

# Follow logs
docker compose logs -f gitea-runner

# View last 100 lines
docker compose logs --tail=100 gitea-runner

# View Docker-in-Docker logs
docker compose logs -f docker-dind

Check Runner Status

# Check container status
docker compose ps

# View runner info
docker compose exec gitea-runner cat /data/.runner

Unregister Runner

./unregister.sh

This will:

  • Stop the runner services
  • Remove registration file
  • Optionally remove runner data

Note: You may need to manually delete the runner from Gitea UI:

Workflow Examples

Basic Node.js Test Workflow

Create .gitea/workflows/test.yml in your repository:

name: Test
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Install dependencies
        run: npm install

      - name: Run tests
        run: npm test

PHP Test Workflow

name: PHP Tests
on: [push]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Install PHP dependencies
        run: |
          apt-get update
          apt-get install -y php8.3-cli php8.3-mbstring
          php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
          php composer-setup.php --install-dir=/usr/local/bin --filename=composer
          composer install

      - name: Run tests
        run: ./vendor/bin/pest

Build and Deploy Workflow

name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Build Docker image
        run: |
          docker build -t registry.michaelschiemer.de/app:latest .

      - name: Push to registry
        run: |
          echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.michaelschiemer.de -u admin --password-stdin
          docker push registry.michaelschiemer.de/app:latest

      - name: Deploy via SSH
        run: |
          # Add SSH deployment commands here

Troubleshooting

Runner Not Appearing in Gitea

Check registration:

# Verify registration file exists
ls -la data/.runner

# Check runner logs
docker compose logs gitea-runner

Re-register:

./unregister.sh
./register.sh

Jobs Not Starting

Check runner status:

# View logs
docker compose logs -f gitea-runner

# Check if runner is idle
# In Gitea: Admin > Actions > Runners

Common Issues:

  • Runner is offline: Restart runner (docker compose restart gitea-runner)
  • No matching labels: Verify workflow runs-on matches runner labels
  • Capacity reached: Increase GITEA_RUNNER_CAPACITY or wait for jobs to finish

Docker-in-Docker Issues

Check DinD container:

# View DinD logs
docker compose logs docker-dind

# Check DinD is running
docker compose ps docker-dind

Restart DinD:

docker compose restart docker-dind

Job Timeout

Jobs timing out after 3 hours? Increase timeout in config.yaml:

runner:
  timeout: 6h  # Increase to 6 hours

Network Issues

Cannot reach Gitea:

# Test connectivity from runner
docker compose exec gitea-runner wget -O- https://git.michaelschiemer.de

# Check DNS resolution
docker compose exec gitea-runner nslookup git.michaelschiemer.de

Disk Space Issues

Clean up old job data:

# Remove old workspace data
docker compose exec gitea-runner rm -rf /tmp/gitea-runner/*

# Clean up Docker images
docker image prune -a -f

Security Considerations

1. Runner Security

  • Runner runs with access to Docker socket (required for jobs)
  • Jobs execute in isolated containers via Docker-in-Docker
  • Network is isolated from other Docker networks
  • Resource limits prevent resource exhaustion

2. Registration Token

  • Registration token has admin privileges
  • Store token securely (in .env file, not in git)
  • Token is only used during registration
  • After registration, runner uses generated credentials

3. Job Isolation

  • Each job runs in a separate container
  • Containers are destroyed after job completion
  • Docker-in-Docker provides additional isolation layer
  • Valid volume mounts are restricted in config.yaml

4. Secrets Management

In Gitea:

  • Store secrets in repository settings: Settings > Secrets
  • Access in workflows via ${{ secrets.SECRET_NAME }}
  • Secrets are masked in logs

Example:

steps:
  - name: Deploy
    run: |
      echo "${{ secrets.DEPLOY_KEY }}" > deploy_key
      chmod 600 deploy_key
      ssh -i deploy_key user@server "deploy.sh"

5. Network Security

  • Runner network is isolated
  • Only runner and DinD containers share network
  • No external access to runner management

Maintenance

Daily Tasks

  • Monitor runner logs for errors
  • Check disk space usage
  • Verify runner appears as "Idle" in Gitea when not running jobs

Weekly Tasks

  • Review completed jobs in Gitea
  • Clean up old Docker images: docker image prune -a
  • Check runner resource usage

Monthly Tasks

  • Update runner image: docker compose pull && docker compose up -d
  • Review and update runner labels
  • Audit workflow performance

Update Runner

# Pull latest image
docker compose pull

# Restart with new image
docker compose up -d

# Verify update
docker compose logs -f gitea-runner

Performance Optimization

Reduce Job Startup Time

Cache dependencies in workflows:

- name: Cache dependencies
  uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}

Optimize Docker Builds

Use Docker layer caching:

- name: Build with cache
  run: |
    docker build \
      --cache-from registry.michaelschiemer.de/app:cache \
      --tag registry.michaelschiemer.de/app:latest \
      .

Increase Runner Capacity

For more concurrent jobs:

# In .env
GITEA_RUNNER_CAPACITY=2  # Allow 2 concurrent jobs

Note: Ensure development machine has sufficient resources (CPU, RAM, disk).

Integration with Deployment Stacks

Stack 2: Gitea Integration

  • Runner connects to Gitea for job fetching
  • Uses Gitea API for workflow definitions
  • Reports job status back to Gitea

Stack 3: Docker Registry Integration

  • Push built images to private registry
  • Pull base images from registry for jobs
  • Use registry for caching layers

Stack 4: Application Deployment

  • Build and test application code
  • Deploy to application stack via SSH
  • Trigger stack updates via Ansible

Stack 5: Database Migrations

  • Run database migrations in workflows
  • Test database changes before deployment
  • Backup database before migrations

Stack 6: Monitoring Integration

  • Monitor runner resource usage via cAdvisor
  • Track job execution metrics in Prometheus
  • Alert on runner failures via Grafana

Advanced Configuration

Custom Docker Registry for Jobs

Use private registry for job images:

# In .env
DOCKER_REGISTRY_MIRROR=https://registry.michaelschiemer.de

In workflows:

jobs:
  test:
    runs-on: ubuntu-latest
    container:
      image: registry.michaelschiemer.de/php:8.3-cli
      credentials:
        username: admin
        password: ${{ secrets.REGISTRY_PASSWORD }}

Multiple Runners

Run multiple runners for different purposes:

# Production runner
cd deployment/gitea-runner-prod
cp ../gitea-runner/.env.example .env
# Set GITEA_RUNNER_NAME=prod-runner
# Set different labels
./register.sh

# Staging runner
cd deployment/gitea-runner-staging
cp ../gitea-runner/.env.example .env
# Set GITEA_RUNNER_NAME=staging-runner
./register.sh

Custom Job Container Options

In config.yaml:

container:
  # Custom Docker options
  options: "--dns 8.8.8.8 --add-host git.michaelschiemer.de:94.16.110.151"

  # Custom network mode
  network: host

  # Enable privileged mode (use cautiously)
  privileged: false

Monitoring and Logging

View Runner Metrics

# Container resource usage
docker stats gitea-runner

# Detailed metrics
docker compose exec gitea-runner cat /data/metrics

Centralized Logging

Send logs to monitoring stack:

# In docker-compose.yml
services:
  gitea-runner:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

Health Checks

# Check runner health
docker compose exec gitea-runner ps aux | grep act_runner

# Check job queue
# In Gitea: Actions > Jobs

Backup and Recovery

Backup Runner Configuration

# Backup registration and config
tar czf gitea-runner-backup-$(date +%Y%m%d).tar.gz \
  .env config.yaml data/.runner

Restore Runner

# Extract backup
tar xzf gitea-runner-backup-YYYYMMDD.tar.gz

# Restart runner
docker compose up -d

Note: If registration token changed, re-register:

./unregister.sh
./register.sh

Support

Documentation

Logs

# Runner logs
docker compose logs -f gitea-runner

# All logs
docker compose logs -f

# Export logs
docker compose logs > runner-logs-$(date +%Y%m%d).log

Health Check

# Check all components
docker compose ps

# Test runner connection to Gitea
docker compose exec gitea-runner wget -O- https://git.michaelschiemer.de/api/v1/version

Setup Status: Ready for registration

Next Steps:

  1. Copy .env.example to .env
  2. Get registration token from Gitea
  3. Run ./register.sh
  4. Verify runner appears in Gitea UI
  5. Create a test workflow to verify functionality