# 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 ```bash 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](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases). `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: ```bash 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 ```bash cp .env.example .env ``` Edit `.env` with your tokens: ```bash # 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): ```bash 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: ```bash 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`: ```bash 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 ```bash grm status prod-runner ``` This connects to the remote host and checks the systemd user service status. ### List all runners ```bash 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): ```bash 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](CLI-Commands) for the full command reference. ## View Logs ### GRM application logs (on your local machine) ```bash # 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: ```bash ls ~/.local/state/grm/logs/ansible-*.log cat ~/.local/state/grm/logs/ansible-20260622-143012.log ``` ### Runner logs (on the remote host) ```bash # 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-.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 - **Install more runners** on the same or different hosts — see [Installation](Installation) - **Learn all CLI commands** — see [CLI Commands](CLI-Commands) - **Troubleshoot issues** — see [Troubleshooting](Troubleshooting) - **Understand the architecture** — see [Architecture](Architecture)