Post-merge / detect-type (push) Successful in 51s
Post-merge / release (push) Successful in 54s
Post-merge / validate-commit-msg (push) Successful in 1m5s
Post-merge / publish (push) Has been skipped
Post-merge / badges (push) Successful in 1m17s
Post-merge / vikunja (push) Successful in 1m26s
Post-merge / configure-repo (push) Successful in 1m12s
Post-merge / sync-wiki (push) Successful in 1m34s
243 lines
8.6 KiB
Markdown
243 lines
8.6 KiB
Markdown
# Installation
|
|
|
|
> **Before you start:** Make sure you have cloned the repo and checked out the latest stable release tag. See [Getting Started](Getting-Started) for setup instructions. Do not run from `master` — it may contain unreleased changes.
|
|
|
|
## Prerequisites
|
|
|
|
### On your local machine (where you run `grm`)
|
|
|
|
- **Python 3.12+** — GRM targets Python 3.12 and requires it for development setup. Use `pyenv` if you need to manage multiple Python versions.
|
|
- **Ansible** — Installed automatically by `make setup` (via pip). GRM delegates all remote operations to `ansible-playbook`.
|
|
- **SSH key** — A private key that grants access to the target host(s) as a user with sudo privileges.
|
|
|
|
### On the target host(s) (where runners will be installed)
|
|
|
|
- **SSH server** — The remote host must be reachable via SSH using the user specified with `--user` and the private key specified with `--key`. GRM uses Ansible under the hood, which connects to the target host over SSH to execute all installation and configuration tasks. Without valid SSH credentials, Ansible cannot establish a connection and the deployment will fail.
|
|
- **Sudo access** — GRM requires root privileges on the remote host to create system users, install packages, and configure rootless Docker. By default, you will be prompted interactively for the sudo password. For automation or uninterrupted workflows, configure passwordless sudo on the remote host and pass `--no-ask-become-pass`.
|
|
- **Gitea registration token** — You need a runner registration token from your Gitea instance. See [Getting Started](Getting-Started) for detailed instructions on obtaining tokens.
|
|
- **systemd** — Required for user services and lingering. All supported OSes ship with systemd.
|
|
- **Docker** — Installed automatically by the Ansible role (rootless mode). No pre-existing Docker installation is required.
|
|
|
|
## Supported Operating Systems
|
|
|
|
| OS | Versions | Package manager |
|
|
|----|----------|-----------------|
|
|
| Arch Linux | rolling | pacman |
|
|
| Ubuntu | 22.04, 24.04 | apt |
|
|
| Debian | 12 | apt |
|
|
|
|
All supported OSes are tested in CI via Molecule scenarios on every PR that changes Ansible files. The platform matrix is defined in `devx.molecule.platforms` as the single source of truth.
|
|
|
|
## Installation Methods
|
|
|
|
### Method 1: From source (recommended for full control)
|
|
|
|
```bash
|
|
git clone https://git.oblachno.oblachno.fyi/oblachno-oss/grm.git
|
|
cd grm
|
|
git checkout $(git describe --tags --abbrev=0) # Latest stable release
|
|
make setup
|
|
source .venv/bin/activate
|
|
```
|
|
|
|
`make setup` performs the following:
|
|
|
|
1. Verifies Python 3.12+ is installed
|
|
2. Creates a virtualenv in `.venv`
|
|
3. Installs all Python dependencies (including Ansible, Click, python-dotenv)
|
|
4. Creates `.env` from `.env.example` if not present
|
|
5. Installs development tools (actionlint, git-cliff, act_runner, checkmake)
|
|
6. Sets up pre-commit hooks
|
|
|
|
### Method 2: Via pip
|
|
|
|
GRM is published to the Gitea PyPI registry at
|
|
`https://git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple`.
|
|
The registry is publicly readable — no authentication required to install.
|
|
|
|
**Quick install (one-off):**
|
|
|
|
```bash
|
|
pip install gitea-runner-manager --index-url https://git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple
|
|
```
|
|
|
|
**Persistent configuration (recommended):**
|
|
|
|
Add the registry to `~/.pip/pip.conf`:
|
|
|
|
```ini
|
|
[global]
|
|
extra-index-url = https://git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple
|
|
```
|
|
|
|
Then install normally:
|
|
|
|
```bash
|
|
pip install gitea-runner-manager
|
|
```
|
|
|
|
This installs the `grm` CLI and its Python dependencies. The Ansible playbooks
|
|
and role are bundled with the package, so `grm install` works out of the box.
|
|
For development or access to Make targets, clone the repository (Method 1).
|
|
|
|
### Post-install configuration
|
|
|
|
After installation, create your `.env` file:
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
# Edit .env with your Gitea URL and registration token
|
|
```
|
|
|
|
Required variables:
|
|
|
|
| Variable | Description |
|
|
|----------|-------------|
|
|
| `GITEA_URL` | Your Gitea instance URL (e.g., `https://git.example.com`) |
|
|
| `GITEA_REGISTRATION_TOKEN` | Runner registration token from Gitea (starts with `GR`) |
|
|
|
|
See [Getting Started](Getting-Started) for detailed token setup instructions.
|
|
|
|
## Quick Start Install
|
|
|
|
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
|
|
```
|
|
|
|
> **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.
|
|
|
|
## Make Install
|
|
|
|
Using Make:
|
|
|
|
```bash
|
|
make install HOST=192.168.1.10 USER=ubuntu KEY=~/.ssh/id_ed25519 NAME=prod-runner
|
|
```
|
|
|
|
The Make target wraps the `grm install` CLI command. All Make install variables are optional except `HOST`:
|
|
|
|
| Variable | Description |
|
|
|----------|-------------|
|
|
| `HOST` | Remote host (IP address or hostname) — **required** |
|
|
| `USER` | SSH user |
|
|
| `KEY` | Path to SSH private key |
|
|
| `NAME` | Gitea Runner name |
|
|
| `TOKEN` | Registration token |
|
|
| `ASK_BECOME_PASS` | Set to `1` to prompt for sudo password |
|
|
|
|
## What Gets Installed on the Target Host
|
|
|
|
When you run `grm install`, the Ansible role creates the following on the remote host:
|
|
|
|
| Resource | Path | Description |
|
|
|----------|------|-------------|
|
|
| System user | `grm-<name>` | Dedicated system user with `/bin/bash` shell |
|
|
| Home directory | `/home/grm-<name>/` | User home with `.config/systemd/user/` |
|
|
| Data directory | `/var/lib/gitea-runner/<name>/` | Runner data including `.runner` registration file |
|
|
| Config directory | `/etc/gitea-runner/<name>/` | Runner configuration file (`config.yaml`) |
|
|
| Runner binary | `/usr/local/bin/gitea_runner` | The gitea_runner executable |
|
|
| Docker socket | `/run/user/<UID>/docker.sock` | Rootless Docker socket |
|
|
| Systemd service | `gitea-runner.service` | User service for the runner daemon |
|
|
| Docker prune timer | `docker-prune.timer` | Daily Docker cleanup timer |
|
|
| subuid/subgid | `/etc/subuid`, `/etc/subgid` | User namespace mapping (100000-165535) |
|
|
| Lingering | `loginctl enable-linger` | Ensures services run without active login |
|
|
|
|
## Runner Registry
|
|
|
|
After installation, GRM stores each runner's connection details (host, user, SSH key, Gitea URL, labels) in a local JSON registry at `~/.local/share/grm/runners.json`. This means you rarely need to repeat connection arguments:
|
|
|
|
```bash
|
|
# List all registered runners with live systemd status
|
|
grm list
|
|
|
|
# Manage runners by name — connection details come from the registry
|
|
grm status prod-runner
|
|
grm stop prod-runner
|
|
grm start prod-runner
|
|
```
|
|
|
|
You can override any stored value by passing the corresponding flag (`--host`, `--user`, `--key`).
|
|
|
|
### Registry file format
|
|
|
|
```json
|
|
{
|
|
"prod-runner": {
|
|
"host": "192.168.1.10",
|
|
"user": "ubuntu",
|
|
"key": "/home/user/.ssh/id_ed25519",
|
|
"gitea_url": "https://git.example.com",
|
|
"labels": "docker:docker://gitea/runner-images:ubuntu-latest",
|
|
"created_at": "2026-06-22T14:30:12.000000+00:00"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Multiple Instances on the Same Host
|
|
|
|
Each runner instance is fully isolated with its own system user, rootless Docker daemon, data directory, and systemd user service:
|
|
|
|
```bash
|
|
# Install two runners on the same host
|
|
grm install 192.168.1.10 --user ubuntu --name workflow-runner
|
|
grm install 192.168.1.10 --user ubuntu --name build-runner
|
|
|
|
# Manage them independently by name
|
|
grm stop workflow-runner
|
|
grm status build-runner
|
|
grm list
|
|
```
|
|
|
|
Each instance gets:
|
|
|
|
- **Dedicated system user**: `grm-<name>` with its own home directory
|
|
- **Rootless Docker daemon**: Isolated Docker socket at `/run/user/<UID>/docker.sock`
|
|
- **Data directory**: `/var/lib/gitea-runner/<name>/`
|
|
- **Config directory**: `/etc/gitea-runner/<name>/`
|
|
- **Systemd user service**: `gitea-runner.service` (independent start/stop/enable)
|
|
- **Docker prune timer**: Per-instance daily cleanup
|
|
|
|
Runners on the same host never interfere with each other or with the host's Docker installation.
|
|
|
|
## Updating Runners
|
|
|
|
To update the gitea_runner binary on a remote host:
|
|
|
|
```bash
|
|
grm update 192.168.1.10 --user ubuntu
|
|
```
|
|
|
|
To update to a specific version:
|
|
|
|
```bash
|
|
grm update 192.168.1.10 --user ubuntu --version 1.0.8
|
|
```
|
|
|
|
Using Make:
|
|
|
|
```bash
|
|
make update HOST=192.168.1.10 USER=ubuntu VERSION=1.0.8
|
|
```
|
|
|
|
## Removing Runners
|
|
|
|
To remove a runner completely (deregisters from Gitea, removes user, directories, and service files):
|
|
|
|
```bash
|
|
grm remove prod-runner --token <registration-token>
|
|
```
|
|
|
|
To skip remote cleanup and only remove the local registry entry (useful when the remote host is already gone):
|
|
|
|
```bash
|
|
grm remove prod-runner --force
|
|
```
|
|
|
|
Using Make:
|
|
|
|
```bash
|
|
make remove NAME=prod-runner TOKEN=<registration-token>
|
|
```
|