1
Getting-Started
Devin CI edited this page 2026-08-04 14:04:14 +00:00

Getting Started

This guide walks you through setting up GRM, configuring Gitea credentials, and installing your first runner.

Prerequisites

Before you begin, ensure you have:

  • Python 3.12+ on your local machine
  • SSH access to the target host(s) where runners will be installed
  • Sudo privileges on the target host(s) for the SSH user
  • A Gitea instance with admin access to create registration tokens
  • Git for cloning the repository

Step 1: Clone and Setup

git clone https://git.oblachno.oblachno.fyi/oblachno-oss/grm.git
cd grm
git checkout $(git describe --tags --abbrev=0)  # Checkout latest stable release
make setup
source .venv/bin/activate

Important: Always checkout the latest release tag before running make setup. The master branch may contain unreleased changes that are not yet stable. The git describe --tags --abbrev=0 command automatically selects the most recent tagged release. To see all available releases, run git tag --sort=-version:refname or check the releases page.

make setup creates a virtualenv, installs all dependencies (including Ansible), creates .env from .env.example, and sets up pre-commit hooks.

If you use pyenv for Python version management:

pyenv install 3.12
pyenv local 3.12
make setup

Step 2: Configure Gitea Credentials

GRM needs two tokens from your Gitea instance: a registration token (required) and an admin API token (optional, for post-install verification).

Get the Registration Token

The registration token tells Gitea to accept the runner when it connects.

  1. Log in to your Gitea instance as an administrator
  2. Navigate to Site Administration → Actions → Runners
  3. Click Create Registration Token
  4. Copy the token — it starts with GR

Note: There are three levels of registration tokens:

  • Instance-level (Site Administration → Actions → Runners) — registers a runner for all repositories
  • Organization-level (Organization → Settings → Actions → Runners) — registers a runner for repos in that organization
  • Repository-level (Repository → Settings → Actions → Runners) — registers a runner for a single repository

Use instance-level tokens for shared runners, and repo-level tokens for dedicated runners.

Get the Admin API Token (optional)

The admin API token enables post-install API checks that verify the runner appears in Gitea's runner list. This is purely informational — the integration test primarily verifies the runner by checking:

  1. .runner registration file exists and contains valid JSON (proves successful registration)
  2. Systemd user service is active (proves daemon is polling for jobs)

To get an admin API token:

  1. Go to Settings → Applications → Generate New Token
  2. Give it a name (e.g., "GRM Install Verification")
  3. Select the admin scope (or at minimum: read:user, read:repository, read:admin)
  4. Click Generate Token and copy it immediately (it won't be shown again)

Create the .env File

cp .env.example .env

Edit .env with your tokens:

# Your Gitea instance URL
GITEA_URL=https://git.example.com

# Registration token from Step 1
GITEA_REGISTRATION_TOKEN=GRxxxxxxxxxxxxxxxxxx

# Admin API token from Step 2 (optional)
CI_GITEA_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Environment Variables Reference

Variable Required Default Description
GITEA_URL Yes Gitea instance URL (e.g., https://git.example.com)
GITEA_REGISTRATION_TOKEN Yes Runner registration token from Gitea admin panel
CI_GITEA_TOKEN No Admin API token for post-install verification
GITEA_INTEGRATION_RETRIES No 3 API check retries (default: 3)
GITEA_RUNNER_USER No current login Default SSH user (overrides --user)
GITEA_RUNNER_KEY No Default SSH key path (overrides --key)
GITEA_RUNNER_LABELS No Default runner labels (overrides --labels)
GRM_LANG No en UI language: en, bg, de, ru, zh, pl
GRM_LOG_LEVEL No INFO Console log level: DEBUG, INFO, WARNING, ERROR, CRITICAL

Step 3: Install Your First Runner

Using the CLI (you will be prompted for the sudo password by default):

grm install 192.168.1.10 --user ubuntu --key ~/.ssh/id_ed25519 --name prod-runner

This command:

  1. Connects to 192.168.1.10 via SSH as user ubuntu using the specified key
  2. Creates a dedicated system user grm-prod-runner with lingering enabled
  3. Installs Docker in rootless mode under the grm-prod-runner user
  4. Downloads and installs the gitea_runner binary
  5. Creates the runner configuration file at /etc/gitea-runner/prod-runner/config.yaml
  6. Registers the runner with your Gitea instance
  7. Creates and starts a systemd user service (gitea-runner.service)
  8. Sets up a Docker prune timer (daily cleanup)
  9. Runs an integration test to verify the installation
  10. Saves the runner to the local registry at ~/.local/share/grm/runners.json

Automation tip: Configure passwordless sudo on the remote host and pass --no-ask-become-pass to skip the password prompt. This is recommended for CI/CD pipelines.

Using Make:

make install HOST=192.168.1.10 USER=ubuntu KEY=~/.ssh/id_ed25519 NAME=prod-runner

Runner labels

By default, runners are registered with the label docker,ubuntu-latest:docker://runner-images:ubuntu-22.04. You can override this with --labels:

grm install 192.168.1.10 --user ubuntu --name prod-runner \
  --labels "docker:docker://gitea/runner-images:ubuntu-latest"

Note: Use an official Gitea runner image with Node.js, Python, and Docker CLI. Avoid bare OS images like alpine:latest because actions/checkout@v4 needs Node.js.

Step 4: Verify the Installation

The installer performs an automated integration test that verifies:

  1. .runner file exists with valid JSON containing id, uuid, token, address — this proves successful registration with Gitea
  2. Systemd user service is active — this proves the daemon is polling for jobs

You can also check the Gitea UI under Actions → Runners to confirm the runner appears as Online.

Optional: If CI_GITEA_TOKEN is set, the installer will also query the Gitea API and report whether the runner appears in the admin or repo runners list. This is purely informational.

Check runner status via CLI

grm status prod-runner

This connects to the remote host and checks the systemd user service status.

List all runners

grm list

This displays a table with columns: NAME, HOST, USER, LABELS, STATUS for all runners in the local registry. The status is checked live via an Ansible ad-hoc command.

Step 5: Manage the Runner Lifecycle

Once installed, you can manage the runner by name (connection details are stored in the local registry):

grm stop prod-runner       # Stop the runner service
grm start prod-runner      # Start the runner service
grm enable prod-runner     # Enable the runner to start on boot
grm status prod-runner     # Check the runner status
grm update 192.168.1.10 --user ubuntu  # Update the runner binary
grm disable prod-runner    # Disable and deregister the runner
grm remove prod-runner     # Remove the runner completely

See CLI Commands for the full command reference.

View Logs

GRM application logs (on your local machine)

# Application log file (all messages including DEBUG)
cat ~/.local/state/grm/logs/grm.log

# Enable debug logging in the current session
GRM_LOG_LEVEL=DEBUG grm install 192.168.1.10 --user ubuntu --name prod-runner

Ansible execution logs

Each grm command that invokes Ansible creates a timestamped log file:

ls ~/.local/state/grm/logs/ansible-*.log
cat ~/.local/state/grm/logs/ansible-20260622-143012.log

Runner logs (on the remote host)

# Runner logs (via systemd user service)
sudo -u grm-prod-runner journalctl --user -u gitea-runner -f

# Rootless Docker daemon logs
sudo -u grm-prod-runner journalctl --user -u docker -f

Logging destinations

The GRM application writes to three destinations:

Destination Level Content
Console (stdout) GRM_LOG_LEVEL (default: INFO) Colorised user-facing messages and operation reports
~/.local/state/grm/logs/grm.log DEBUG All messages with timestamps and severity
~/.local/state/grm/logs/ansible-<timestamp>.log Full Ansible playbook output per execution

Set GRM_LOG_LEVEL to one of DEBUG, INFO, WARNING, ERROR, or CRITICAL to control console verbosity. The log file always captures everything at DEBUG level regardless of the console setting.

Console output is automatically colorised via click.style: operation headers in bright cyan, completed steps in green, failures in red, and status updates in yellow.

Next Steps