mirror of
https://gitea.com/gitea/docs.git
synced 2026-09-18 03:58:52 +00:00
Add runner 2 and 3 documentations (#488)
Reviewed-on: https://gitea.com/gitea/docs/pulls/488 Reviewed-by: silverwind <[email protected]>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# Caching
|
||||
|
||||
Every runner starts its own cache server, so `actions/cache` works without any configuration. Cache entries are local to that runner: two runners do not share a cache unless you make them.
|
||||
|
||||
Only the cache service v1 API is served in this version, so `actions/cache` has to be pinned to a version that still speaks it (up to `v4.1`), and artifacts need the `gitea-upload-artifact` / `gitea-download-artifact` forks. Runner `3.0` adds cache service v2, which the stock actions use.
|
||||
|
||||
## Where cache blobs are stored
|
||||
|
||||
```yaml
|
||||
cache:
|
||||
enabled: true
|
||||
dir: /var/lib/gitea-runner/cache # default: $HOME/.cache/actcache
|
||||
```
|
||||
|
||||
The directory grows with use; entries are evicted as they expire, so give it a filesystem with room to spare and monitor it like any other build cache.
|
||||
|
||||
## Dockerized runners
|
||||
|
||||
When the runner itself runs in a container and creates a network per job, the address it detects for its own cache server is often unreachable from the job containers. `actions/cache` then fails with:
|
||||
|
||||
```text
|
||||
Failed to restore: getCacheEntry failed: connect ETIMEDOUT IP:PORT
|
||||
```
|
||||
|
||||
Pin the address and the port the job containers should use, and make that endpoint reachable:
|
||||
|
||||
1. take an address of the host that job containers can reach, and a free port on it;
|
||||
2. configure them:
|
||||
|
||||
```yaml
|
||||
cache:
|
||||
enabled: true
|
||||
dir: ""
|
||||
host: "192.168.8.17"
|
||||
port: 8088
|
||||
```
|
||||
|
||||
3. publish the port when starting the runner container:
|
||||
|
||||
```bash
|
||||
docker run -d --name gitea-runner -p 8088:8088 ... docker.io/gitea/runner:2
|
||||
```
|
||||
|
||||
Putting the runner and the job containers on one shared `container.network` instead works too, and then the auto-detected address is reachable.
|
||||
|
||||
## Sharing a cache between runners
|
||||
|
||||
Run one dedicated cache server that every runner points at.
|
||||
|
||||
1. Config for the cache server host:
|
||||
|
||||
```yaml
|
||||
cache:
|
||||
dir: /data/actcache
|
||||
port: 8088
|
||||
external_secret: "replace-with-a-strong-random-secret"
|
||||
# external_secret_file: /run/secrets/cache-secret # or keep it out of this file
|
||||
```
|
||||
|
||||
2. Start it:
|
||||
|
||||
```bash
|
||||
gitea-runner -c cache-server-config.yaml cache-server
|
||||
```
|
||||
|
||||
3. On every runner:
|
||||
|
||||
```yaml
|
||||
cache:
|
||||
external_server: "http://cache-host:8088/"
|
||||
external_secret: "replace-with-a-strong-random-secret" # must match the server
|
||||
```
|
||||
|
||||
The secret authenticates runners against the shared server and must be identical on all of them; generate one with `openssl rand -hex 32`. Setting both `external_secret` and `external_secret_file` is an error.
|
||||
|
||||
`cache-server` accepts `--dir`, `--host` and `--port`, which override the corresponding `cache.*` keys. Every other setting, `external_secret` included, has to come from the config file.
|
||||
|
||||
### Alternatives
|
||||
|
||||
- **Shared filesystem** — mount the same NFS/CIFS share on every runner and point `cache.dir` at it. Simpler, but repositories are less isolated from each other than behind a cache server.
|
||||
- **Object storage** — mount S3 or MinIO as a FUSE filesystem, e.g. with [s3fs](https://github.com/s3fs-fuse/s3fs-fuse) or [goofys](https://github.com/kahing/goofys), and set `cache.dir` to the mount point.
|
||||
|
||||
## Action repository cache
|
||||
|
||||
Actions pulled by `uses:` are cached too, and by default refreshed on every job so a moved tag is picked up. To pin them to what has already been fetched:
|
||||
|
||||
```yaml
|
||||
cache:
|
||||
offline_mode: true
|
||||
```
|
||||
|
||||
A re-tagged `v6` or an updated branch then stays at the cached commit until its entry expires or is removed. Combined with `runner.action_shallow_clone` (on by default, fetching only the requested ref at depth 1), this keeps job startup fast on runners with limited bandwidth.
|
||||
@@ -0,0 +1,137 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Configuration
|
||||
|
||||
The runner is configured with a single YAML file. It is optional: without one, the built-in defaults apply, which are the same as an empty YAML document and safe to run with.
|
||||
|
||||
```bash
|
||||
gitea-runner generate-config > config.yaml
|
||||
gitea-runner -c config.yaml register
|
||||
gitea-runner -c config.yaml daemon
|
||||
```
|
||||
|
||||
`-c` / `--config` is a global flag and is accepted by every command that loads configuration (`register`, `daemon`, `cache-server`). The generated file is fully commented and is reproduced in [Example configuration](reference/config-example.md).
|
||||
|
||||
:::warning No environment variable overrides
|
||||
The runner process is configured only through the YAML file. Earlier releases let a few variables (`GITEA_DEBUG`, `GITEA_TRACE`, `GITEA_RUNNER_CAPACITY`, `GITEA_RUNNER_FILE`, `GITEA_RUNNER_ENVIRON`, `GITEA_RUNNER_ENV_FILE`) override parts of the config; those overrides have been removed.
|
||||
|
||||
The variables understood by the Docker images belong to their [entrypoint](installation/docker.md#entrypoint-environment-variables), not to the runner, and `GITEA_RUNNER_LABELS` / `GITEA_RUNNER_REGISTRATION_TOKEN` are read by the corresponding CLI flags only.
|
||||
:::
|
||||
|
||||
Values with a duration type accept Go duration strings such as `30s`, `10m`, `3h`.
|
||||
|
||||
## `log`
|
||||
|
||||
Controls the runner's own log, not how step output is streamed to the UI.
|
||||
|
||||
| Option | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `log.level` | `info` | `trace`, `debug`, `info`, `warn`, `error`, `fatal` or `panic`. `trace` and `debug` add the caller's `file:line`. |
|
||||
|
||||
## `runner`
|
||||
|
||||
| Option | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `file` | `.runner` | path of the registration file. Each runner process needs its own. |
|
||||
| `capacity` | `1` | jobs executed concurrently. With an empty `container.network`, every concurrent docker job takes a subnet from the daemon's address pool, so a high capacity can exhaust it (see `default-address-pools` in the daemon config). |
|
||||
| `envs` | – | extra environment variables given to every job. |
|
||||
| `env_file` | `.env` | same, read from a file; ignored when empty or missing. |
|
||||
| `timeout` | `3h` | maximum job duration. Gitea has its own timeout (3h by default) and may stop the job earlier. |
|
||||
| `shutdown_timeout` | `0s` | how long a shutdown waits for running jobs before cancelling them. |
|
||||
| `insecure` | `false` | skip TLS verification of the Gitea instance. |
|
||||
| `fetch_timeout` | `5s` | timeout of a single job fetch. |
|
||||
| `fetch_interval` | `2s` | base polling interval. |
|
||||
| `fetch_interval_max` | `5s` | upper bound of the exponential backoff applied while idle. `0`, or the same value as `fetch_interval`, disables the backoff. |
|
||||
| `labels` | see [Labels](labels.md) | labels used at registration, and by `daemon` when the flag is absent. |
|
||||
| `github_mirror` | – | replaces `https://github.com` when actions are pulled and the instance's `DEFAULT_ACTIONS_URL` points at GitHub. |
|
||||
| `action_shallow_clone` | `true` | fetch only the requested ref of an action repository at depth 1 instead of its full history. |
|
||||
| `set_act_env` | `true` | inject `ACT=true` into jobs. Set to `false` so workflows gated on `if: ${{ !env.ACT }}` behave as they do on GitHub. |
|
||||
| `allocate_pty` | `false` | allocate a pseudo-TTY per step. Enable only when a job needs an interactive terminal; tools like `docker build` then write redrawing progress frames into the log. |
|
||||
| `workdir_cleanup_age` | `24h` | age at which stale task workspaces and orphaned host-mode scratch directories are removed while idle. |
|
||||
| `idle_cleanup_interval` | `10m` | cadence of the idle cleanup pass. Setting either this or `workdir_cleanup_age` to `0` disables all idle cleanup. |
|
||||
| `post_task_script` | – | host script run after each task's cleanup, see [Post-task script](hooks/post-task-script.md). |
|
||||
| `post_task_script_timeout` | `5m` | hard limit for that script. |
|
||||
|
||||
Log and state reporting can be tuned when the UI updates too slowly or the instance sees too many requests:
|
||||
|
||||
| Option | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `log_report_interval` | `5s` | base interval of the periodic log flush. |
|
||||
| `log_report_max_latency` | `3s` | maximum time a single log row waits. Only has an effect below `log_report_interval`. |
|
||||
| `log_report_batch_size` | `100` | flush immediately once this many rows are buffered, so bursty output arrives promptly. |
|
||||
| `state_report_interval` | `5s` | interval of task state reports. State is also sent on every step transition. |
|
||||
| `report_close_timeout` | `10s` | per-attempt deadline for the final log and state flush of a finished job. |
|
||||
|
||||
### Idle cleanup
|
||||
|
||||
While no job is running, the runner cleans up after earlier ones:
|
||||
|
||||
- stale task workspaces older than `workdir_cleanup_age` are removed when `container.bind_workdir` is enabled. Only purely numeric subdirectories of `container.workdir_parent` are treated as workspaces, and the path is assumed not to be shared with another runner;
|
||||
- orphaned host-mode scratch directories are removed on the same schedule.
|
||||
|
||||
Per-job docker networks of jobs the runner did not live to tear down are *not* cleaned up in this version, and each of them keeps holding a subnet of the daemon's address pool until it is removed manually. Runner `3.0` removes them as part of the idle pass.
|
||||
|
||||
## `cache`
|
||||
|
||||
See [Caching](cache.md) for the full picture, including shared cache servers.
|
||||
|
||||
| Option | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `enabled` | `true` | run the built-in cache server used by `actions/cache` and friends. |
|
||||
| `dir` | `$HOME/.cache/actcache` | where cache blobs are stored. Ignored with `external_server`. |
|
||||
| `host` | – | address job containers use to reach this runner's cache server. Empty means auto-detect; `0.0.0.0` is not valid. |
|
||||
| `port` | `0` | port of the built-in server, `0` picks a free one. |
|
||||
| `external_server` | – | URL of a shared `cache-server` to use instead of a local one. It has to end with `/`. |
|
||||
| `external_secret` | – | shared secret, required with `external_server`; must be identical everywhere. Generate with `openssl rand -hex 32`. |
|
||||
| `external_secret_file` | – | read that secret from a file instead. Setting both is an error. |
|
||||
| `offline_mode` | `false` | reuse a cached action instead of fetching it on every job. A moved tag or updated branch then stays at the cached commit until the entry expires or is removed. |
|
||||
|
||||
## `container`
|
||||
|
||||
Applies to jobs that run in containers.
|
||||
|
||||
| Option | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `network` | – | network the job container joins: `host`, `bridge`, or a custom network name. Empty means the runner creates one per job. `network_mode` is still accepted for old configs. |
|
||||
| `network_create_options.enable_ipv4` / `enable_ipv6` | Docker defaults | only apply to auto-created networks. IPv6 additionally requires `dockerd --ipv6`. |
|
||||
| `privileged` | `false` | run job containers privileged; required for Docker-in-Docker inside jobs. |
|
||||
| `options` | – | extra `docker run` options, e.g. `--add-host=my.gitea.url:host-gateway`, `--platform` or `--pull`. |
|
||||
| `workdir_parent` | `/workspace` | parent directory of a job's working directory inside the container. A leading `/` is trimmed and re-added. |
|
||||
| `valid_volumes` | `[]` | volumes and bind mounts a job may mount, as [glob](https://github.com/gobwas/glob) patterns. `[]` forbids all, `['**']` allows all. |
|
||||
| `docker_host` | – | override the docker host. Empty auto-detects it, `-` auto-detects it but does not mount the socket into job containers. |
|
||||
| `force_pull` | `false` | pull images even when present. |
|
||||
| `force_rebuild` | `false` | rebuild local action images even when present. |
|
||||
| `require_docker` | `false` | always require a reachable daemon, even for host-only labels. |
|
||||
| `docker_timeout` | `0s` | how long to wait for the daemon to become reachable. |
|
||||
| `bind_workdir` | `false` | bind-mount the workspace from the host instead of using a docker volume. Needed for jobs that use `docker compose` with bind mounts under Docker-in-Docker. The parent directory must then be mounted into the runner container and listed in `valid_volumes`. |
|
||||
|
||||
:::warning Workflow container options are not filtered
|
||||
A workflow's own `jobs.<job_id>.container.options` are merged into the container configuration as they are, apart from `--privileged` itself. A workflow can therefore reach the host through options such as `--pid=host` or `--cap-add=ALL`. Runner `3.0` strips those options while `container.privileged` is disabled; until then, only grant this runner to repositories you trust.
|
||||
:::
|
||||
|
||||
## `host`
|
||||
|
||||
| Option | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `host.workdir_parent` | `$HOME/.cache/act/` | parent directory of a job's working directory for host-mode jobs. |
|
||||
|
||||
## `health_check` and `metrics`
|
||||
|
||||
Both are covered in [Monitoring](monitoring.md).
|
||||
|
||||
| Option | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `health_check.enabled` | `false` | pause fetching new tasks while the machine looks unhealthy. |
|
||||
| `health_check.min_free_disk_space_mb` | `1024` | minimum free space on the filesystem holding the workspaces. |
|
||||
| `health_check.script` | – | extra executable; a non-zero exit, a timeout or a start failure marks the runner unavailable. |
|
||||
| `health_check.interval` | `30s` | how long a result is cached. |
|
||||
| `health_check.timeout` | `10s` | maximum script runtime. |
|
||||
| `metrics.enabled` | `false` | serve `/metrics`, `/healthz` and `/readyz`. |
|
||||
| `metrics.addr` | `127.0.0.1:9101` | listen address. There is no authentication, so only expose it behind a firewall. |
|
||||
| `metrics.readiness_grace` | `30s` | how long consecutive polling failures may last before `/readyz` returns 503. |
|
||||
|
||||
## Reloading
|
||||
|
||||
The runner reads its configuration at startup only. Restart the process after a change — with `shutdown_timeout` set, running jobs are given that much time to finish first.
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Post-task script
|
||||
|
||||
The post-task script is an optional host hook that runs **once after every task**, after the runner has finished its normal per-task cleanup. Typical uses are pruning Docker images, vacuuming ephemeral disks, or resetting VM state between jobs.
|
||||
|
||||
```yaml
|
||||
runner:
|
||||
# Path to an executable on the host. Empty or omitted disables the hook.
|
||||
post_task_script: /usr/local/bin/gitea-post-task.sh
|
||||
# Hard limit on script runtime. Default when post_task_script is set: 5m.
|
||||
post_task_script_timeout: 2m
|
||||
```
|
||||
|
||||
| Option | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `runner.post_task_script` | disabled | host path to the script or binary. Relative paths are resolved from the runner's working directory. |
|
||||
| `runner.post_task_script_timeout` | `5m` when a script is set | maximum runtime before the runner kills the script and moves on. |
|
||||
|
||||
## When it runs
|
||||
|
||||
For each task, the order is:
|
||||
|
||||
1. the workflow runs (steps, actions, containers);
|
||||
2. in-job cleanup (action `post:` steps, container stop and removal);
|
||||
3. job outputs are reported to Gitea;
|
||||
4. the bind-workdir workspace is removed, when `container.bind_workdir` is enabled;
|
||||
5. **the post-task script**;
|
||||
6. the final task acknowledgement to Gitea.
|
||||
|
||||
The script is **additive**: it does not replace any built-in cleanup. With `container.bind_workdir` enabled, the workspace directory has usually already been deleted before the script starts, but `GITEA_WORKSPACE` still names the path the job used.
|
||||
|
||||
## The runner stays offline until the script finishes
|
||||
|
||||
This is the most important operational detail. When the script starts, the runner **stops sending task heartbeats**, so from Gitea's perspective it is not available for new work until the script exits and the final task flush has been sent.
|
||||
|
||||
While the script runs:
|
||||
|
||||
- Gitea does not assign another task to this runner for the current job slot;
|
||||
- the capacity slot stays occupied locally — with `capacity: 1`, no other task starts;
|
||||
- a shutdown counts this phase as part of the in-flight task, so a slow script delays graceful shutdown.
|
||||
|
||||
If the script never exits, the runner stays in this state until `runner.post_task_script_timeout` elapses (default **5 minutes**), then kills it and proceeds. Set that timeout to what your housekeeping is allowed to take, and keep the script short and bounded.
|
||||
|
||||
## Environment variables
|
||||
|
||||
The script receives `runner.envs` / `runner.env_file` values plus:
|
||||
|
||||
| Variable | Description |
|
||||
| --- | --- |
|
||||
| `GITEA_TASK_ID` | numeric task ID |
|
||||
| `GITEA_RUN_ID` | workflow run ID, when the server provides it |
|
||||
| `GITEA_REPOSITORY` | repository slug (`owner/name`) |
|
||||
| `GITEA_WORKSPACE` | workspace path the job used, which may already be deleted |
|
||||
| `GITEA_JOB_RESULT` | `success`, `failure`, `cancelled`, `skipped` or `unknown` |
|
||||
|
||||
The environment is **not** a copy of the job container's. Even `PATH` is only present if `runner.envs` or `runner.env_file` defines it.
|
||||
|
||||
## Output and errors
|
||||
|
||||
- stdout and stderr go to the **runner process log**, prefixed with `post-task script stdout:` / `post-task script stderr:` — not to the job log;
|
||||
- a non-zero exit is logged as a warning and does not change the job result already reported to Gitea;
|
||||
- timeouts and start failures are warnings too; the runner still acknowledges the task.
|
||||
|
||||
## Interaction with other timeouts
|
||||
|
||||
| Timeout | Effect on the post-task script |
|
||||
| --- | --- |
|
||||
| `runner.post_task_script_timeout` | kills the script if it runs too long. The **only** timeout that bounds it. |
|
||||
| `runner.timeout` | caps the task **up to** the script. The script detaches from the task deadline, so a job that nearly hit the runner timeout does not cut it short. |
|
||||
| `runner.shutdown_timeout` | bounds how long a shutdown waits for the **task**. The script detaches from cancellation and may extend shutdown until its own timeout elapses. |
|
||||
|
||||
## Examples
|
||||
|
||||
Prune dangling Docker resources on Linux:
|
||||
|
||||
```sh
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
docker image prune -f
|
||||
docker builder prune -f --filter 'until=24h'
|
||||
```
|
||||
|
||||
On Windows, use a `.exe`, `.bat` or `.cmd` path; `.ps1` is not supported as the configured path, so wrap PowerShell in a batch file:
|
||||
|
||||
```bat
|
||||
@echo off
|
||||
powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "%~dp0post-task.ps1"
|
||||
```
|
||||
|
||||
`.sh` files on Windows need a Unix shell on `PATH`, unless `post_task_script` points at the interpreter itself.
|
||||
|
||||
## Notes
|
||||
|
||||
- `gitea-runner exec` does not load the runner YAML and never runs this hook.
|
||||
- Use idempotent operations: the script runs after success, failure and cancellation alike.
|
||||
- Watch the runner log when testing failure modes — a hung script, a non-zero exit, a missing executable.
|
||||
- Bind-workdir idle cleanup (`runner.workdir_cleanup_age`) is separate from this hook and only runs while the runner is idle.
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
slug: /
|
||||
---
|
||||
|
||||
# Gitea Runner
|
||||
|
||||
The [Gitea Runner](https://gitea.com/gitea/runner) executes the jobs of [Gitea Actions](/usage/actions/overview).
|
||||
It polls a Gitea instance for queued jobs, runs their steps in a container or directly on the machine it is installed on, and streams the logs and the result back.
|
||||
|
||||
:::info
|
||||
These pages describe the runner `2.x` series. Pick another release, or the development version, in the **Runner Version** dropdown.
|
||||
:::
|
||||
|
||||
## Requirements
|
||||
|
||||
A runner needs a Gitea instance with Actions enabled, a [registration token](registration.md), and, for containerized jobs, a Docker daemon. Actions are enabled by default since Gitea 1.21; on older instances they have to be turned on:
|
||||
|
||||
```ini
|
||||
[actions]
|
||||
ENABLED=true
|
||||
```
|
||||
|
||||
Other OCI engines that implement the Docker API may work, but are untested. Podman is not a supported configuration.
|
||||
|
||||
## Execution modes
|
||||
|
||||
A runner can run jobs in three different ways. The mode is not a global setting: it follows from the [labels](labels.md) the runner is registered with, so a single runner can offer both container and host labels.
|
||||
|
||||
| Mode | How jobs run | Docker daemon | Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| Docker (recommended) | in a container created from the label's image | external, e.g. the host's `/var/run/docker.sock` | jobs are isolated from each other, but share the daemon |
|
||||
| Docker-in-Docker | in a container created by a daemon that lives next to the runner | bundled in the `dind` / `dind-rootless` images | strongest isolation, more setup, needs `--privileged` |
|
||||
| Host | directly on the machine, with the tools installed there | only needed for `docker://` actions and service containers | no isolation between jobs |
|
||||
|
||||
## Getting started
|
||||
|
||||
1. [Install the runner](installation/binary.md) as a binary, [in Docker](installation/docker.md), or [on Kubernetes](installation/kubernetes.md).
|
||||
2. [Register it](registration.md) against your instance with a registration token.
|
||||
3. [Configure it](configuration.md), and pick the [labels](labels.md) that decide which jobs it accepts.
|
||||
4. Optionally set up a [shared cache](cache.md), a [post-task script](hooks/post-task-script.md), or [metrics and health checks](monitoring.md).
|
||||
|
||||
Every command and flag is listed in the [command line reference](reference/cli.md).
|
||||
|
||||
## Versioning and compatibility
|
||||
|
||||
The runner is released independently of Gitea and its version numbers are unrelated to the instance's. Gitea 1.21 or later is expected — older instances cannot accept the runner's label declaration — and individual features need a newer instance still, which is called out where they apply.
|
||||
|
||||
When moving between major runner versions, read [Upgrading](upgrade.md) first: `2.0.0` contains breaking changes.
|
||||
@@ -0,0 +1,151 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# Install from a binary
|
||||
|
||||
The runner is a single static binary called `gitea-runner`. It has no dependencies apart from a Docker daemon for containerized jobs.
|
||||
|
||||
## Download
|
||||
|
||||
- released builds: [dl.gitea.com/gitea-runner](https://dl.gitea.com/gitea-runner/) or the [release page](https://gitea.com/gitea/runner/releases)
|
||||
- development builds of the `main` branch: [dl.gitea.com/gitea-runner/nightly](https://dl.gitea.com/gitea-runner/nightly/)
|
||||
|
||||
Each file is published next to a `.sha256` checksum and an `.xz` compressed variant:
|
||||
|
||||
```bash
|
||||
VERSION=2.3.0 # any 2.x release, see the release page
|
||||
curl -sSLO "https://dl.gitea.com/gitea-runner/$VERSION/gitea-runner-$VERSION-linux-amd64"
|
||||
curl -sSLO "https://dl.gitea.com/gitea-runner/$VERSION/gitea-runner-$VERSION-linux-amd64.sha256"
|
||||
sha256sum -c "gitea-runner-$VERSION-linux-amd64.sha256"
|
||||
install -m 0755 "gitea-runner-$VERSION-linux-amd64" /usr/local/bin/gitea-runner
|
||||
```
|
||||
|
||||
Check that the binary matches your platform:
|
||||
|
||||
```bash
|
||||
gitea-runner --version
|
||||
```
|
||||
|
||||
## Build from source
|
||||
|
||||
Building requires the Go version declared in the repository's `go.mod`:
|
||||
|
||||
```bash
|
||||
git clone https://gitea.com/gitea/runner.git
|
||||
cd runner
|
||||
make build
|
||||
```
|
||||
|
||||
## First run
|
||||
|
||||
```bash
|
||||
gitea-runner generate-config > config.yaml # optional, defaults are safe
|
||||
gitea-runner -c config.yaml register # see "Registering a runner"
|
||||
gitea-runner -c config.yaml daemon
|
||||
```
|
||||
|
||||
The `daemon` command runs in the foreground. It reads the registration file (`runner.file`, `.runner` by default) relative to its working directory, so keep the working directory stable across restarts.
|
||||
|
||||
## Run as a systemd service
|
||||
|
||||
Create an unprivileged user, install the binary, and register the runner as that user so the `.runner` file ends up in the service's working directory:
|
||||
|
||||
```bash
|
||||
sudo useradd --system --home-dir /var/lib/gitea-runner --create-home gitea-runner
|
||||
sudo install -d /etc/gitea-runner
|
||||
sudo -u gitea-runner gitea-runner generate-config | sudo tee /etc/gitea-runner/config.yaml >/dev/null
|
||||
cd /var/lib/gitea-runner
|
||||
sudo -u gitea-runner gitea-runner register -c /etc/gitea-runner/config.yaml
|
||||
```
|
||||
|
||||
Then install the unit as `/etc/systemd/system/gitea-runner.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Gitea Actions runner
|
||||
Documentation=https://gitea.com/gitea/runner
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
# Uncomment when jobs use the local Docker daemon:
|
||||
# After=docker.service
|
||||
# Requires=docker.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/gitea-runner daemon --config /etc/gitea-runner/config.yaml
|
||||
WorkingDirectory=/var/lib/gitea-runner
|
||||
User=gitea-runner
|
||||
Group=gitea-runner
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
# Allow running jobs to finish before the runner is stopped. Keep this in sync
|
||||
# with runner.shutdown_timeout in the config.
|
||||
TimeoutStopSec=3h
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now gitea-runner
|
||||
```
|
||||
|
||||
If jobs use the host's Docker daemon, the `gitea-runner` user also needs access to the daemon socket. Adding it to the `docker` group grants that access and is [equivalent to root on the host](https://docs.docker.com/engine/security/#docker-daemon-attack-surface).
|
||||
|
||||
## Run as a launchd daemon (macOS)
|
||||
|
||||
macOS uses `launchd` instead of systemd. Daemons run as `root` by default; an unprivileged `_gitea-runner` user can be created with `dscl`. Install the following as `/Library/LaunchDaemons/com.gitea.runner.plist` and adjust the paths to your installation:
|
||||
|
||||
```xml
|
||||
<?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.gitea.runner</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/gitea-runner</string>
|
||||
<string>daemon</string>
|
||||
<string>--config</string>
|
||||
<string>/etc/gitea-runner/config.yaml</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/var/lib/gitea-runner</string>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/var/lib/gitea-runner/runner.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/var/lib/gitea-runner/runner.err</string>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
||||
<key>HOME</key>
|
||||
<string>/var/lib/gitea-runner</string>
|
||||
</dict>
|
||||
<key>UserName</key>
|
||||
<string>_gitea-runner</string>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo launchctl load /Library/LaunchDaemons/com.gitea.runner.plist
|
||||
```
|
||||
|
||||
On macOS and Windows hosts, jobs usually run with [host labels](../labels.md) and the tools installed on the machine.
|
||||
|
||||
## Windows
|
||||
|
||||
Install the `windows-amd64` binary and register it as a service with any service wrapper (for example `sc.exe` plus a wrapper such as [WinSW](https://github.com/winsw/winsw), or a scheduled task at boot). The runner itself has no service-installer subcommand.
|
||||
|
||||
Keep in mind for Windows hosts:
|
||||
|
||||
- `runner.post_task_script` accepts `.exe`, `.bat` and `.cmd` paths; `.ps1` is not supported as the configured path.
|
||||
- host-mode jobs are terminated as a process tree, so tools that daemonize are not left behind.
|
||||
@@ -0,0 +1,147 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Install with Docker
|
||||
|
||||
The official images are published on [Docker Hub](https://hub.docker.com/r/gitea/runner/tags) as `docker.io/gitea/runner`.
|
||||
Every release is tagged with its version, and the `2` tag follows the newest `2.x` release. `latest` points at the newest release of *any* series, so pin `2` (or an exact version) to stay on this one.
|
||||
|
||||
In the container the registration and the daemon are combined: the entrypoint registers the runner on first start (when no registration file exists yet) and then execs `gitea-runner daemon`.
|
||||
|
||||
## Image flavours
|
||||
|
||||
All flavours contain the same `gitea-runner` binary and differ only in how a Docker daemon is made available to jobs.
|
||||
|
||||
| Tag | Base image | Docker daemon | Supervisor | Runs as |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `2`, `2.3`, `<version>` | `alpine` | none, you provide one | `tini` | `root` |
|
||||
| `2-dind`, `2.3-dind` | `docker:dind` | bundled, needs `--privileged` | `s6` | `root` |
|
||||
| `2-dind-rootless`, `2.3-dind-rootless` | `docker:dind-rootless` | bundled, rootless | `s6` | `rootless` (UID 1000) |
|
||||
|
||||
The rootless flavour's UID is fixed at 1000 by the upstream base image, and its daemon always listens on `/run/user/1000/docker.sock`, so `--user 1001` does not work. To talk to a *host* rootless daemon under another UID, use the basic flavour and bind-mount that daemon's socket instead.
|
||||
|
||||
## Basic flavour
|
||||
|
||||
The default image ships no daemon of its own, so jobs that use `docker://` images need one from outside the container — usually the host's socket:
|
||||
|
||||
```bash
|
||||
docker run -d --name my_runner \
|
||||
-e GITEA_INSTANCE_URL=<instance_url> \
|
||||
-e GITEA_RUNNER_REGISTRATION_TOKEN=<registration_token> \
|
||||
-e GITEA_RUNNER_NAME=<runner_name> \
|
||||
-v $PWD/data:/data \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
docker.io/gitea/runner:2
|
||||
```
|
||||
|
||||
This flavour does not need `--privileged`. The trade-off is that jobs share the host's daemon and can therefore see its other containers and images. A job that can reach the socket can also read the reusable `GITEA_RUNNER_REGISTRATION_TOKEN` from the runner container's `docker inspect` output.
|
||||
|
||||
## Docker-in-Docker
|
||||
|
||||
The `dind` flavour bundles its own daemon, so no socket has to be mounted:
|
||||
|
||||
```bash
|
||||
docker run -d --name my_runner --privileged \
|
||||
-e GITEA_INSTANCE_URL=<instance_url> \
|
||||
-e GITEA_RUNNER_REGISTRATION_TOKEN=<registration_token> \
|
||||
-v $PWD/data:/data \
|
||||
docker.io/gitea/runner:2-dind
|
||||
```
|
||||
|
||||
`s6` starts `dockerd` first and the runner service waits for it before registering. Use `2-dind-rootless` to run both the daemon and the runner as an unprivileged user; rootless Docker's usual limitations around networking, cgroups and storage drivers apply.
|
||||
|
||||
## Volumes
|
||||
|
||||
Two different pieces of state are worth persisting, and neither implies the other:
|
||||
|
||||
- `/data` is the runner's working directory. It holds the `.runner` registration file and, optionally, the config file. Without it, a recreated container registers itself again as a new runner, leaving a stale entry in Gitea, and fails outright if the token has been reset in the meantime.
|
||||
- the Docker daemon's data root holds the images pulled for jobs. It is **not** under `/data`: for `dind` it is `/var/lib/docker` inside the container, for `dind-rootless` it is `/home/rootless/.local/share/docker`. Give it its own volume, or every new container re-pulls the job images.
|
||||
|
||||
## Entrypoint environment variables
|
||||
|
||||
The entrypoint ([`scripts/run.sh`](https://gitea.com/gitea/runner/src/branch/main/scripts/run.sh)) understands:
|
||||
|
||||
| Variable | Meaning |
|
||||
| --- | --- |
|
||||
| `GITEA_INSTANCE_URL` | instance to register against, e.g. `https://gitea.example.com/` |
|
||||
| `GITEA_RUNNER_REGISTRATION_TOKEN` | registration token; unset before the daemon starts |
|
||||
| `GITEA_RUNNER_REGISTRATION_TOKEN_FILE` | file to read the token from, for Docker/Kubernetes secrets |
|
||||
| `GITEA_RUNNER_NAME` | runner name, defaults to the container hostname |
|
||||
| `GITEA_RUNNER_LABELS` | labels, passed to both `register` and `daemon` |
|
||||
| `GITEA_RUNNER_EPHEMERAL` | any non-empty value registers the runner as [ephemeral](../registration.md#ephemeral-runners) |
|
||||
| `GITEA_RUNNER_ONCE` | any non-empty value runs a single job, then exits |
|
||||
| `GITEA_MAX_REG_ATTEMPTS` | registration attempts before giving up, default `10` |
|
||||
| `RUNNER_STATE_FILE` | registration file name inside `/data`, default `.runner` |
|
||||
| `CONFIG_FILE` | config file inside the container, passed as `--config` |
|
||||
|
||||
These are entrypoint variables, not runner settings: the runner process itself is configured only through the [config file](../configuration.md).
|
||||
|
||||
Mount the config file when you need one:
|
||||
|
||||
```bash
|
||||
docker run -v $PWD/config.yaml:/config.yaml -e CONFIG_FILE=/config.yaml ...
|
||||
```
|
||||
|
||||
A config file can be generated with the image itself:
|
||||
|
||||
```bash
|
||||
docker run --rm --entrypoint="" docker.io/gitea/runner:2 gitea-runner generate-config > config.yaml
|
||||
```
|
||||
|
||||
## docker compose
|
||||
|
||||
```yaml
|
||||
services:
|
||||
runner:
|
||||
image: docker.io/gitea/runner:2
|
||||
restart: always
|
||||
environment:
|
||||
CONFIG_FILE: /config.yaml
|
||||
GITEA_INSTANCE_URL: "${INSTANCE_URL}"
|
||||
GITEA_RUNNER_REGISTRATION_TOKEN: "${REGISTRATION_TOKEN}"
|
||||
GITEA_RUNNER_NAME: "${RUNNER_NAME}"
|
||||
GITEA_RUNNER_LABELS: "${RUNNER_LABELS}"
|
||||
volumes:
|
||||
- ./config.yaml:/config.yaml
|
||||
- ./data:/data
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
```
|
||||
|
||||
When Gitea runs in the same compose project, depend on its health check so the runner does not try to register before the instance answers:
|
||||
|
||||
```yaml
|
||||
depends_on:
|
||||
gitea:
|
||||
condition: service_healthy
|
||||
restart: true
|
||||
```
|
||||
|
||||
The rootless Docker-in-Docker variant needs a few extra options:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
runner:
|
||||
image: docker.io/gitea/runner:2-dind-rootless
|
||||
restart: always
|
||||
privileged: true
|
||||
security_opt:
|
||||
# for hosts running AppArmor (Ubuntu, Debian), whose default profile blocks
|
||||
# the user namespace changes the bundled daemon needs
|
||||
- apparmor=rootlesskit
|
||||
volumes:
|
||||
- ./data/runner:/data
|
||||
environment:
|
||||
- GITEA_INSTANCE_URL=<instance_url>
|
||||
- GITEA_RUNNER_REGISTRATION_TOKEN=<registration_token>
|
||||
- DOCKER_HOST=unix:///var/run/user/1000/docker.sock
|
||||
# slirp4netns gives significantly better network throughput than vpnkit
|
||||
- DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns
|
||||
- DOCKERD_ROOTLESS_ROOTLESSKIT_MTU=65520
|
||||
```
|
||||
|
||||
## Cache from a dockerized runner
|
||||
|
||||
A runner in a container creates a separate network per job by default, so the address it detects for its own cache server is often unreachable from job containers and `actions/cache` fails with a connection timeout. Set `cache.host` and `cache.port` explicitly and publish that port, or put the job containers on a shared network — see [Caching](../cache.md#dockerized-runners).
|
||||
|
||||
More deployment examples live in the [`examples`](https://gitea.com/gitea/runner/src/branch/main/examples) directory of the runner repository.
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Install on Kubernetes
|
||||
|
||||
Ready-to-adapt manifests live in [`examples/kubernetes`](https://gitea.com/gitea/runner/src/branch/main/examples/kubernetes) of the runner repository, and a Helm chart is maintained at [gitea/helm-actions](https://gitea.com/gitea/helm-actions).
|
||||
|
||||
## Choosing a manifest
|
||||
|
||||
| Example | Shape | Docker daemon |
|
||||
| --- | --- | --- |
|
||||
| `dind-docker.yaml` | `Deployment` with a native sidecar (`initContainer` with `restartPolicy: Always`, needs Kubernetes 1.29+) | privileged `docker:dind` sidecar, socket shared through an `emptyDir` |
|
||||
| `statefulset-dind.yaml` | `StatefulSet` with `volumeClaimTemplates` | same as above |
|
||||
| `rootless-docker.yaml` | `Deployment` with a single container | bundled rootless daemon of the `dind-rootless` image, reached over `tcp://localhost:2376` with TLS |
|
||||
|
||||
Prefer the `StatefulSet` variant when you scale past one replica: each pod then gets a stable identity and its own volume, so it keeps its `.runner` registration across restarts and reschedules instead of registering itself again as a new runner.
|
||||
|
||||
## Two volumes, two purposes
|
||||
|
||||
- `/data` — the runner's working directory, holding the `.runner` registration file and optionally the config file.
|
||||
- the daemon's data root — `/var/lib/docker` for the `dind` sidecar, `/home/rootless/.local/share/docker` for `dind-rootless`. It holds the images pulled for jobs and is *not* under `/data`. Dropping it still works, but every recreated pod re-pulls all job images.
|
||||
|
||||
With the rootless image, both volumes must be writable by UID/GID 1000, which is what `securityContext.fsGroup: 1000` in the example is for.
|
||||
|
||||
## Registration token
|
||||
|
||||
The examples read the token from a `Secret`:
|
||||
|
||||
```yaml
|
||||
env:
|
||||
- name: GITEA_INSTANCE_URL
|
||||
value: http://gitea-http.gitea.svc.cluster.local:3000
|
||||
- name: GITEA_RUNNER_REGISTRATION_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: runner-secret
|
||||
key: token
|
||||
```
|
||||
|
||||
The token stays valid for further registrations until it is reset, but each registration creates another runner entry. For pods that are recreated without their volume, use the instance-wide token configured on the Gitea side, and expect stale runner entries — or start an [ephemeral runner](../registration.md#ephemeral-runners) per job.
|
||||
|
||||
## Privileges
|
||||
|
||||
Docker-in-Docker needs `securityContext.privileged: true`, which lets a malicious job break out of the container. Weigh that against the alternatives:
|
||||
|
||||
- the rootless flavour, which reduces but does not remove the exposure;
|
||||
- pointing the basic flavour at a daemon outside the cluster;
|
||||
- keeping such runners on a dedicated node pool and only granting them to trusted repositories.
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# Labels
|
||||
|
||||
Labels decide **which jobs a runner accepts** and **how it runs them**. A job's `runs-on` value is matched against the runner's label names; the first match wins and selects the execution environment for that job.
|
||||
|
||||
A label is written as:
|
||||
|
||||
```text
|
||||
<name>[:<schema>[:<args>]]
|
||||
```
|
||||
|
||||
| Part | Meaning |
|
||||
| --- | --- |
|
||||
| `name` | the name a workflow refers to in `runs-on`, e.g. `ubuntu-latest` |
|
||||
| `schema` | either `docker` or `host`, defaulting to `host` when omitted |
|
||||
| `args` | only used by the `docker` schema: the image the job runs in |
|
||||
|
||||
Two schemas are supported:
|
||||
|
||||
- `docker://<image>` — the job runs in a container created from `<image>`:
|
||||
|
||||
```text
|
||||
ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest
|
||||
```
|
||||
|
||||
- `host` — the job's steps run directly on the machine, with the tools installed there:
|
||||
|
||||
```text
|
||||
macos:host
|
||||
```
|
||||
|
||||
So a runner registered with
|
||||
|
||||
```text
|
||||
ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest,macos:host
|
||||
```
|
||||
|
||||
runs `runs-on: ubuntu-latest` jobs in the `runner-images:ubuntu-latest` container and `runs-on: macos` jobs directly on the host.
|
||||
|
||||
Names may themselves contain a colon, for example `pool:e57e18d4-10d4-406f-93bf-60f127221bdd`; only `host` and `docker` are treated as schemas.
|
||||
|
||||
If a job's `runs-on` matches none of the runner's labels, the job still runs, in the default `docker.gitea.com/runner-images:ubuntu-latest` image. Images maintained for this purpose are listed at [gitea/runner-images](https://gitea.com/gitea/runner-images); community images such as the [act images](https://github.com/nektos/act/blob/master/IMAGES.md) work too.
|
||||
|
||||
:::note
|
||||
A runner that only exposes `host` labels still needs access to a Docker daemon whenever a job uses a `docker://` action or a service container. `host` labels only change where the job's own steps run.
|
||||
:::
|
||||
|
||||
## Registration versus config labels
|
||||
|
||||
Labels are chosen at registration time (`--labels`, or the interactive prompt) and stored in the registration file. Afterwards they can be changed without re-registering, and the most explicit source wins:
|
||||
|
||||
```text
|
||||
--labels / GITEA_RUNNER_LABELS > runner.labels in the config file > labels in the .runner file
|
||||
```
|
||||
|
||||
- during `register`, `runner.labels` from the config file takes precedence and the `--labels` flag is ignored;
|
||||
- `daemon --labels` (which defaults to `GITEA_RUNNER_LABELS`) overrides the labels of an already registered runner;
|
||||
- whenever the resulting labels differ from those in the registration file, they are written back to it and re-declared to the instance on startup;
|
||||
- labels that fail to parse are skipped with a warning instead of stopping the runner.
|
||||
|
||||
Labels can also be edited in the Gitea UI under the runner's settings.
|
||||
|
||||
## Choosing images
|
||||
|
||||
- Pick an image that already contains the tools your workflows expect. The default images are small; a job that installs a toolchain on every run is usually better served by a purpose-built image.
|
||||
- Pin images by tag or digest for reproducible jobs. An image pinned by digest is never re-pulled, even with `container.force_pull` enabled.
|
||||
- Use distinct names such as `linux_amd64:host` or `windows:host` for host labels, so a workflow written for GitHub's `ubuntu-latest` does not accidentally run unsandboxed on your machine.
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
sidebar_position: 7
|
||||
---
|
||||
|
||||
# Monitoring and health
|
||||
|
||||
## Prometheus metrics
|
||||
|
||||
```yaml
|
||||
metrics:
|
||||
enabled: true
|
||||
addr: "127.0.0.1:9101"
|
||||
readiness_grace: 30s
|
||||
```
|
||||
|
||||
With `metrics.enabled`, the runner serves three endpoints on `metrics.addr`:
|
||||
|
||||
| Endpoint | Purpose |
|
||||
| --- | --- |
|
||||
| `/metrics` | Prometheus exposition of the runner's own metrics |
|
||||
| `/healthz` | liveness: the process is up |
|
||||
| `/readyz` | task admission: `503` while a [health check](#local-health-checks) reports the machine as unavailable, once polling has been failing for longer than `readiness_grace`, or after the runner has been deleted on the instance |
|
||||
|
||||
There is **no authentication** on this listener. The default address binds to localhost only; expose it more widely (`":9101"`) only behind a firewall or a scrape-only network.
|
||||
|
||||
All series are prefixed with `gitea_runner_`, among them:
|
||||
|
||||
| Metric | Meaning |
|
||||
| --- | --- |
|
||||
| `gitea_runner_info` | always `1`, with the version and runner name as labels |
|
||||
| `gitea_runner_uptime_seconds` | seconds since the daemon started |
|
||||
| `gitea_runner_capacity` / `gitea_runner_job_running` / `gitea_runner_job_capacity_utilization_ratio` | configured capacity, jobs in flight, and their ratio |
|
||||
| `gitea_runner_job_total` | jobs by result (`success`, `failure`, `cancelled`, `skipped`, `unknown`) |
|
||||
| `gitea_runner_job_duration_seconds` | job duration histogram |
|
||||
| `gitea_runner_poll_fetch_total` / `gitea_runner_poll_fetch_duration_seconds` | task fetches by result (`task`, `empty`, `error`) and their latency |
|
||||
| `gitea_runner_poll_backoff_seconds` | last polling backoff interval |
|
||||
| `gitea_runner_report_log_total` / `gitea_runner_report_state_total` | log and state reports by result |
|
||||
| `gitea_runner_report_log_buffer_rows` | log rows buffered but not yet sent |
|
||||
| `gitea_runner_client_errors_total` | RPC errors by method |
|
||||
|
||||
Useful things to alert on: `gitea_runner_poll_fetch_total{result="error"}` rising (the instance is unreachable or the runner was deleted), a `capacity_utilization_ratio` pinned at `1` (the pool is too small), and a growing `report_log_buffer_rows` (log delivery is falling behind).
|
||||
|
||||
## Local health checks
|
||||
|
||||
Health checks let a runner take itself out of rotation when the machine it runs on is not fit for work — most commonly when the disk is full.
|
||||
|
||||
```yaml
|
||||
health_check:
|
||||
enabled: false
|
||||
min_free_disk_space_mb: 1024
|
||||
script: ''
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
```
|
||||
|
||||
- while a check fails, the runner stops fetching **new** tasks; jobs already running are unaffected and finish normally;
|
||||
- no check runs while a job is active — the last result is reused until the runner is idle again;
|
||||
- `min_free_disk_space_mb` is measured on the filesystem holding the runner's workspaces, and defaults to 1024 MiB when omitted or zero;
|
||||
- `script` is any executable. A non-zero exit, a timeout, or a failure to start marks the runner unavailable. Its result is cached for `interval` and it is killed after `timeout`;
|
||||
- recovery is automatic and logged (`runner local health recovered, resuming task polling`), and the state is reflected by `/readyz`.
|
||||
|
||||
## Logs
|
||||
|
||||
The runner logs to stderr; `log.level` controls the verbosity, with `debug` and `trace` adding `file:line` to each line. Under systemd the log ends up in the journal (`journalctl -u gitea-runner`), in Docker in `docker logs`.
|
||||
|
||||
The runner log is not the job log: step output is streamed to Gitea and is tuned with the `runner.log_report_*` settings, while things like [post-task script](hooks/post-task-script.md) output only ever appear in the runner log.
|
||||
|
||||
## Reporting a problem
|
||||
|
||||
`gitea-runner bug-report` prints the version, Go version, OS/architecture and CPU count — paste its output into an issue at [gitea/runner](https://gitea.com/gitea/runner/issues):
|
||||
|
||||
```bash
|
||||
gitea-runner bug-report
|
||||
```
|
||||
|
||||
```text
|
||||
Runner version: 2.3.0
|
||||
Go version: go1.26.5
|
||||
OS/Arch: linux/amd64
|
||||
NumCPU: 8
|
||||
```
|
||||
|
||||
To reproduce a workflow locally, without a Gitea instance and without touching the runner's registration, use `gitea-runner exec` — see the [command line reference](reference/cli.md#exec).
|
||||
@@ -0,0 +1,185 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
description: Every gitea-runner command and flag, generated from the runner sources.
|
||||
---
|
||||
|
||||
# Command line reference
|
||||
|
||||
{/* Generated by update_runner_docs.sh from the gitea/runner sources, do not edit. */}
|
||||
|
||||
`gitea-runner` is a single binary with one subcommand per task. `--config` / `-c` is
|
||||
global: every command that reads configuration accepts it, and commands that do not
|
||||
read any ignore it.
|
||||
|
||||
## gitea-runner
|
||||
|
||||
```text
|
||||
Gitea Runner
|
||||
|
||||
Usage:
|
||||
gitea-runner [command]
|
||||
|
||||
Available Commands:
|
||||
bug-report Print information useful when filing a bug report
|
||||
cache-server Start a cache server for the cache action
|
||||
daemon Run as a runner daemon
|
||||
exec Run workflow locally.
|
||||
generate-config Generate an example config file
|
||||
help Help about any command
|
||||
register Register a runner to the server
|
||||
|
||||
Flags:
|
||||
-c, --config string Config file path
|
||||
-h, --help help for gitea-runner
|
||||
-v, --version version for gitea-runner
|
||||
|
||||
Use "gitea-runner [command] --help" for more information about a command.
|
||||
```
|
||||
|
||||
## register
|
||||
|
||||
Registers the runner against a Gitea instance and writes the registration file. Interactive unless `--no-interactive` is given; the token can also come from `--token-file` or the `GITEA_RUNNER_REGISTRATION_TOKEN` environment variable. See [Registering a runner](../registration.md).
|
||||
|
||||
```text
|
||||
Register a runner to the server
|
||||
|
||||
Usage:
|
||||
gitea-runner register [flags]
|
||||
|
||||
Flags:
|
||||
--ephemeral Configure the runner to be ephemeral and only ever be able to pick a single job (stricter than --once)
|
||||
-h, --help help for register
|
||||
--instance string Gitea instance address
|
||||
--labels string Runner tags, comma separated
|
||||
--name string Runner name
|
||||
--no-interactive Disable interactive mode
|
||||
--token string Runner token (or set the GITEA_RUNNER_REGISTRATION_TOKEN envvar)
|
||||
--token-file string Path to a file containing the runner token
|
||||
|
||||
Global Flags:
|
||||
-c, --config string Config file path
|
||||
```
|
||||
|
||||
## daemon
|
||||
|
||||
Runs the runner: it polls the instance for jobs and executes them until it is stopped. `--labels` (default: `GITEA_RUNNER_LABELS`) overrides the labels of an already registered runner, and `--once` exits after a single job.
|
||||
|
||||
```text
|
||||
Run as a runner daemon
|
||||
|
||||
Usage:
|
||||
gitea-runner daemon [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for daemon
|
||||
--labels string Runner labels, comma separated. Overrides the labels of an already registered runner
|
||||
--once Run one job then exit
|
||||
|
||||
Global Flags:
|
||||
-c, --config string Config file path
|
||||
```
|
||||
|
||||
## exec
|
||||
|
||||
Runs a workflow from the current repository locally, without a Gitea instance and without the runner configuration file. Useful for debugging a workflow before pushing it. Runner YAML is not loaded, so hooks and cache settings do not apply.
|
||||
|
||||
```text
|
||||
Run workflow locally.
|
||||
|
||||
Usage:
|
||||
gitea-runner exec [flags]
|
||||
|
||||
Flags:
|
||||
--artifact-server-addr string Defines the address where the artifact server listens
|
||||
--artifact-server-path string Defines the path where the artifact server stores uploads and retrieves downloads from. If not specified the artifact server will not start. (default ".")
|
||||
--artifact-server-port string Defines the port where the artifact server listens (will only bind to localhost). (default "34567")
|
||||
--container-architecture string Architecture which should be used to run containers, e.g.: linux/amd64. If not specified, will use host default architecture. Requires Docker server API Version 1.41+. Ignored on earlier Docker server platforms.
|
||||
--container-cap-add stringArray kernel capabilities to add to the workflow containers (e.g. --container-cap-add SYS_PTRACE)
|
||||
--container-cap-drop stringArray kernel capabilities to remove from the workflow containers (e.g. --container-cap-drop SYS_PTRACE)
|
||||
--container-daemon-socket string Path to Docker daemon socket which will be mounted to containers (default "/var/run/docker.sock")
|
||||
--container-opts string container options
|
||||
-d, --debug enable debug log
|
||||
--default-actions-url string Defines the default url of action instance. (default "https://github.com")
|
||||
--detect-event Use first event type from workflow as event that triggered the workflow
|
||||
-C, --directory string working directory (default ".")
|
||||
-n, --dryrun dryrun mode
|
||||
--env stringArray env to make available to actions with optional value (e.g. --env myenv=foo or --env myenv)
|
||||
--env-file string environment file to read and use as env in the containers (default ".env")
|
||||
-E, --event string run a event name
|
||||
-e, --eventpath string path to a JSON event payload file exposed as the event that triggered the workflow
|
||||
--gitea-instance string Gitea instance to use.
|
||||
-h, --help help for exec
|
||||
-i, --image string Docker image to use. Use "-self-hosted" to run directly on the host. (default "docker.gitea.com/runner-images:ubuntu-latest")
|
||||
--insecure-secrets NOT RECOMMENDED! Doesn't hide secrets while printing logs.
|
||||
-j, --job string run a specific job ID; when several workflow files define that job, also pass --workflows/-W to select the file
|
||||
--json Output logs in json format
|
||||
-l, --list list workflows
|
||||
--network string Specify the network to which the container will connect
|
||||
--no-recurse Flag to disable running workflows from subdirectories of specified path in '--workflows'/'-W' flag
|
||||
--no-skip-checkout Do not skip actions/checkout
|
||||
--privileged use privileged mode
|
||||
-p, --pull pull docker image(s) even if already present
|
||||
--rebuild rebuild local action docker image(s) even if already present
|
||||
-s, --secret stringArray secret to make available to actions with optional value (e.g. -s mysecret=foo or -s mysecret)
|
||||
--use-gitignore Controls whether paths specified in .gitignore should be copied into container (default true)
|
||||
--userns string user namespace to use
|
||||
--var stringArray variable to make available to actions with optional value (e.g. --var myvar=foo or --var myvar)
|
||||
-W, --workflows string path to workflow file(s) (default "./.gitea/workflows/")
|
||||
|
||||
Global Flags:
|
||||
-c, --config string Config file path
|
||||
```
|
||||
|
||||
## cache-server
|
||||
|
||||
Runs only the cache server, so several runners can share one cache. `--dir`, `--host` and `--port` override the matching `cache.*` keys; every other setting, `cache.external_secret` included, has to come from the config file. See [Caching](../cache.md#sharing-a-cache-between-runners).
|
||||
|
||||
```text
|
||||
Start a cache server for the cache action
|
||||
|
||||
Usage:
|
||||
gitea-runner cache-server [flags]
|
||||
|
||||
Flags:
|
||||
-d, --dir string Cache directory
|
||||
-h, --help help for cache-server
|
||||
-s, --host string Host of the cache server
|
||||
-p, --port uint16 Port of the cache server
|
||||
|
||||
Global Flags:
|
||||
-c, --config string Config file path
|
||||
```
|
||||
|
||||
## generate-config
|
||||
|
||||
Prints the commented example configuration on stdout, which is the starting point for a config file: `gitea-runner generate-config > config.yaml`.
|
||||
|
||||
```text
|
||||
Generate an example config file
|
||||
|
||||
Usage:
|
||||
gitea-runner generate-config [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for generate-config
|
||||
|
||||
Global Flags:
|
||||
-c, --config string Config file path
|
||||
```
|
||||
|
||||
## bug-report
|
||||
|
||||
Prints the runner version, Go version, OS/architecture and CPU count, for pasting into an issue.
|
||||
|
||||
```text
|
||||
Print information useful when filing a bug report
|
||||
|
||||
Usage:
|
||||
gitea-runner bug-report [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for bug-report
|
||||
|
||||
Global Flags:
|
||||
-c, --config string Config file path
|
||||
```
|
||||
@@ -0,0 +1,248 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
description: The commented example configuration of the runner, generated from the runner sources.
|
||||
---
|
||||
|
||||
# Example configuration
|
||||
|
||||
{/* Generated by update_runner_docs.sh from the gitea/runner sources, do not edit. */}
|
||||
|
||||
This is the output of `gitea-runner generate-config`. It is safe to use unmodified,
|
||||
and it is the authoritative list of every option the runner understands. See
|
||||
[Configuration](../configuration.md) for what the options mean and how the file is
|
||||
loaded.
|
||||
|
||||
```yaml
|
||||
# Example configuration file, it's safe to copy this as the default config file without any modification.
|
||||
|
||||
# You don't have to copy this file to your instance,
|
||||
# just run `./gitea-runner generate-config > config.yaml` to generate a config file.
|
||||
|
||||
# Logging for the runner process itself (messages printed to stderr).
|
||||
# This does not control how workflow step output is streamed to the Gitea UI;
|
||||
# tune that with runner.log_report_* below.
|
||||
log:
|
||||
# logrus severity: trace, debug, info, warn, error, fatal, panic.
|
||||
# trace and debug turn on caller/file:line in log lines. Default if omitted: info.
|
||||
level: info
|
||||
|
||||
runner:
|
||||
# Where to store the registration result.
|
||||
file: .runner
|
||||
# Execute how many tasks concurrently at the same time.
|
||||
capacity: 1
|
||||
# Extra environment variables to run jobs.
|
||||
envs:
|
||||
A_TEST_ENV_NAME_1: a_test_env_value_1
|
||||
A_TEST_ENV_NAME_2: a_test_env_value_2
|
||||
# Extra environment variables to run jobs from a file.
|
||||
# It will be ignored if it's empty or the file doesn't exist.
|
||||
env_file: .env
|
||||
# The timeout for a job to be finished.
|
||||
# Please note that the Gitea instance also has a timeout (3h by default) for the job.
|
||||
# So the job could be stopped by the Gitea instance if its timeout is shorter than this.
|
||||
timeout: 3h
|
||||
# The timeout for the runner to wait for running jobs to finish when shutting down.
|
||||
# Any running jobs that haven't finished after this timeout will be cancelled.
|
||||
shutdown_timeout: 0s
|
||||
# Whether skip verifying the TLS certificate of the Gitea instance.
|
||||
insecure: false
|
||||
# The timeout for fetching the job from the Gitea instance.
|
||||
fetch_timeout: 5s
|
||||
# The interval for fetching the job from the Gitea instance.
|
||||
fetch_interval: 2s
|
||||
# The maximum interval for fetching the job from the Gitea instance.
|
||||
# The runner uses exponential backoff when idle, increasing the interval up to this maximum.
|
||||
# Set to 0 or same as fetch_interval to disable backoff.
|
||||
fetch_interval_max: 5s
|
||||
# While idle, remove stale bind-workdir task directories and orphaned host-mode
|
||||
# scratch directories (left behind when a host cleanup delete stalls) older than
|
||||
# this duration. Setting either workdir_cleanup_age or idle_cleanup_interval to 0
|
||||
# (or any non-positive value) disables stale-directory cleanup entirely.
|
||||
workdir_cleanup_age: 24h
|
||||
# Cadence for the idle stale-directory cleanup pass.
|
||||
idle_cleanup_interval: 10m
|
||||
# The base interval for periodic log flush to the Gitea instance.
|
||||
# Logs may be sent earlier if the buffer reaches log_report_batch_size
|
||||
# or if log_report_max_latency expires after the first buffered row.
|
||||
log_report_interval: 5s
|
||||
# The maximum time a log row can wait before being sent.
|
||||
# This ensures even a single log line appears on the frontend within this duration.
|
||||
# Must be less than log_report_interval to have any effect.
|
||||
log_report_max_latency: 3s
|
||||
# Flush logs immediately when the buffer reaches this many rows.
|
||||
# This ensures bursty output (e.g., npm install) is delivered promptly.
|
||||
log_report_batch_size: 100
|
||||
# The interval for reporting task state (step status, timing) to the Gitea instance.
|
||||
# State is also reported immediately on step transitions (start/stop).
|
||||
state_report_interval: 5s
|
||||
# Per-attempt deadline for flushing the final logs and task state when a job
|
||||
# finishes, on a detached context so a server cancel can't block the acknowledgement.
|
||||
report_close_timeout: 10s
|
||||
# The github_mirror of a runner is used to specify the mirror address of the github that pulls the action repository.
|
||||
# It works when something like `uses: actions/checkout@v4` is used and DEFAULT_ACTIONS_URL is set to github,
|
||||
# and github_mirror is not empty. In this case,
|
||||
# it replaces https://github.com with the value here, which is useful for some special network environments.
|
||||
github_mirror: ''
|
||||
# When true (the default), fetch only the requested ref of an action repository (e.g. actions/checkout@v4) at depth 1 instead of cloning every branch's full history.
|
||||
# Set to false to clone the full history.
|
||||
action_shallow_clone: true
|
||||
# When true (the default), inject the ACT=true environment variable into jobs.
|
||||
# Set to false so workflows gated on `if: ${{ !env.ACT }}` behave like they do on GitHub.
|
||||
set_act_env: true
|
||||
# The labels of a runner are used to determine which jobs the runner can run, and how to run them.
|
||||
# Like: "macos-arm64:host" or "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
|
||||
# Find more images provided by Gitea at https://gitea.com/gitea/runner-images .
|
||||
# If it's empty when registering, it will ask for inputting labels.
|
||||
# If it's empty when execute `daemon`, will use labels in `.runner` file.
|
||||
labels:
|
||||
- "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
|
||||
- "ubuntu-24.04:docker://docker.gitea.com/runner-images:ubuntu-24.04"
|
||||
- "ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
|
||||
# Allocate a pseudo-TTY for each step's process. Applies to both host and docker backends.
|
||||
# Default false matches GitHub actions/runner. Enable only for jobs that need an interactive
|
||||
# terminal; tools like `docker build` emit redrawing progress frames into the captured log
|
||||
# when a TTY is present.
|
||||
allocate_pty: false
|
||||
# Optional executable on the host, run once after each task's built-in cleanup
|
||||
# (post-steps, container teardown, bind-workdir removal). Additive only.
|
||||
#
|
||||
# IMPORTANT: While this script runs the runner stops task heartbeats and stays
|
||||
# offline from Gitea's perspective until the script exits. A script that never
|
||||
# returns blocks new work until post_task_script_timeout kills it (default 5m).
|
||||
# Keep scripts short; set post_task_script_timeout to a safe upper bound.
|
||||
#
|
||||
# Output -> runner process log (not the job log). Non-zero exit -> warning only.
|
||||
# Windows: use .exe, .bat, or .cmd. PowerShell (.ps1) is not supported yet as
|
||||
# the configured path; wrap PowerShell commands in a .cmd file instead.
|
||||
# Full guide: docs/post-task-script.md
|
||||
post_task_script: ''
|
||||
# Hard limit on post_task_script runtime. Default if omitted: 5m.
|
||||
post_task_script_timeout: 5m
|
||||
|
||||
cache:
|
||||
# Enable the built-in cache server (used by actions/cache and similar actions).
|
||||
enabled: true
|
||||
# Directory where cache blobs are stored on disk. Default: $HOME/.cache/actcache
|
||||
# Ignored when external_server is set.
|
||||
dir: ""
|
||||
# Outbound IP or hostname that job containers use to reach this runner's cache server.
|
||||
# Leave empty to detect automatically. 0.0.0.0 is not valid here.
|
||||
# If the runner itself runs in Docker, automatic detection can choose an
|
||||
# address on the runner container's network that job containers cannot reach
|
||||
# when the runner creates a separate per-job network. In that case, set this
|
||||
# to a hostname/IP reachable from job containers, and set port to a fixed
|
||||
# published port or put the job containers on a shared Docker network.
|
||||
# Ignored when external_server is set.
|
||||
host: ""
|
||||
# Port for the built-in cache server. 0 picks a random free port.
|
||||
# Ignored when external_server is set.
|
||||
port: 0
|
||||
# URL of a shared `gitea-runner cache-server` to use instead of starting a local one.
|
||||
# Set on every runner that should share a cache pool. Must end with "/".
|
||||
# Example: "http://cache-host:8088/"
|
||||
# Requires external_secret (below) to match the value on the cache-server.
|
||||
external_server: ""
|
||||
# Shared secret between this runner and the external cache-server.
|
||||
# Required when external_server is set. Must be identical on every runner and the cache-server.
|
||||
# Generate with: openssl rand -hex 32
|
||||
external_secret: ""
|
||||
# Path to a file containing the shared secret, as an alternative to external_secret.
|
||||
# Use this to keep the secret out of this file.
|
||||
# Surrounding whitespace is trimmed, so a trailing newline in the file is fine.
|
||||
# Setting both external_secret and external_secret_file is an error.
|
||||
external_secret_file: ""
|
||||
# When true, reuse a cached action instead of fetching from the remote on every job.
|
||||
# A moved tag (e.g. a re-tagged "v6") or an updated branch stays at the cached commit
|
||||
# until its cache entry expires or is manually removed.
|
||||
offline_mode: false
|
||||
|
||||
container:
|
||||
# Specifies the network to which the container will connect.
|
||||
# Could be host, bridge or the name of a custom network.
|
||||
# If it's empty, runner will create a network automatically.
|
||||
# For dockerized runners using the built-in cache server, a custom shared
|
||||
# network can be required so job containers can reach cache.host/cache.port.
|
||||
# Deprecated: `network_mode` is still accepted for old configs; use `network` instead.
|
||||
network: ""
|
||||
# network_create_options only apply when `network` is left empty and the runner
|
||||
# auto-creates a per-job network that does not already exist. They have no effect
|
||||
# when a custom `network` name is set, because that network is used as-is and never
|
||||
# created by the runner. Omit the entire block to use Docker's defaults.
|
||||
network_create_options:
|
||||
enable_ipv4: true # Omit to use Docker's default (IPv4 enabled). Set false to disable IPv4.
|
||||
enable_ipv6: false # Omit to use Docker's default (IPv6 disabled). Enabling it requires dockerd started with --ipv6.
|
||||
# Whether to use privileged mode or not when launching task containers (privileged mode is required for Docker-in-Docker).
|
||||
privileged: false
|
||||
# Any other options to be used when the container is started (e.g., --add-host=my.gitea.url:host-gateway).
|
||||
options:
|
||||
# The parent directory of a job's working directory.
|
||||
# NOTE: There is no need to add the first '/' of the path as runner will add it automatically.
|
||||
# If the path starts with '/', the '/' will be trimmed.
|
||||
# For example, if the parent directory is /path/to/my/dir, workdir_parent should be path/to/my/dir
|
||||
# If it's empty, /workspace will be used.
|
||||
# Purely numeric subdirectories under this path are reserved for task workspaces and may be removed by idle cleanup.
|
||||
workdir_parent:
|
||||
# Volumes (including bind mounts) can be mounted to containers. Glob syntax is supported, see https://github.com/gobwas/glob
|
||||
# You can specify multiple volumes. If the sequence is empty, no volumes can be mounted.
|
||||
# For example, if you only allow containers to mount the `data` volume and all the json files in `/src`, you should change the config to:
|
||||
# valid_volumes:
|
||||
# - data
|
||||
# - /src/*.json
|
||||
# If you want to allow any volume, please use the following configuration:
|
||||
# valid_volumes:
|
||||
# - '**'
|
||||
valid_volumes: []
|
||||
# Overrides the docker client host with the specified one.
|
||||
# If it's empty, runner will find an available docker host automatically.
|
||||
# If it's "-", runner will find an available docker host automatically, but the docker host won't be mounted to the job containers and service containers.
|
||||
# If it's not empty or "-", the specified docker host will be used. An error will be returned if it doesn't work.
|
||||
docker_host: ""
|
||||
# Pull docker image(s) even if already present.
|
||||
# Defaults to false when the key is omitted.
|
||||
force_pull: false
|
||||
# Rebuild docker image(s) even if already present
|
||||
force_rebuild: false
|
||||
# Always require a reachable docker daemon, even if not required by runner
|
||||
require_docker: false
|
||||
# Timeout to wait for the docker daemon to be reachable, if docker is required by require_docker or runner
|
||||
docker_timeout: 0s
|
||||
# Bind the workspace to the host filesystem instead of using Docker volumes.
|
||||
# This is required for Docker-in-Docker (DinD) setups when jobs use docker compose
|
||||
# with bind mounts (e.g., ".:/app"), as volume-based workspaces are not accessible
|
||||
# from the DinD daemon's filesystem. When enabled, ensure the workspace parent
|
||||
# directory is also mounted into the runner container and listed in valid_volumes.
|
||||
bind_workdir: false
|
||||
|
||||
host:
|
||||
# The parent directory of a job's working directory.
|
||||
# If it's empty, $HOME/.cache/act/ will be used.
|
||||
workdir_parent:
|
||||
|
||||
# Optional local task-admission checks. Disabled by default. When enabled, low
|
||||
# disk space or a failing script pauses new task fetching; existing jobs continue.
|
||||
# No health checks run while any job is active; the last result is reused until idle.
|
||||
health_check:
|
||||
enabled: false
|
||||
# Minimum free space required on the filesystem holding runner workspaces.
|
||||
# Defaults to 1024 MiB when omitted or set to zero.
|
||||
min_free_disk_space_mb: 1024
|
||||
# Optional additional executable. A non-zero exit, timeout, or startup failure
|
||||
# marks the runner unavailable.
|
||||
script: ''
|
||||
# How long a script result is cached and its maximum execution time.
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
|
||||
metrics:
|
||||
# Enable the Prometheus metrics endpoint.
|
||||
# When enabled, metrics are served at /metrics, liveness at /healthz, and
|
||||
# task-admission readiness at /readyz.
|
||||
enabled: false
|
||||
# The address for the metrics HTTP server to listen on.
|
||||
# Defaults to localhost only. Set to ":9101" to allow external access,
|
||||
# but ensure the port is firewall-protected as there is no authentication.
|
||||
addr: "127.0.0.1:9101"
|
||||
# Consecutive polling failures may last this long before /readyz returns 503.
|
||||
readiness_grace: 30s
|
||||
```
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Registering a runner
|
||||
|
||||
A runner has to be registered before it can pick up jobs: registration is what tells the runner where to fetch jobs from, and what gives the Gitea instance a stable identity for the runner.
|
||||
|
||||
## Obtain a registration token
|
||||
|
||||
Registration tokens are issued by the Gitea instance and can be scoped to the whole instance, an organization/user, or a single repository. See [Actions runners](/usage/actions/runner) for where to find them in the UI and via the API.
|
||||
|
||||
One token can register any number of runners and stays valid until it is reset in the UI or through the API. Instance administrators can also hand Gitea a fixed token with `GITEA_RUNNER_REGISTRATION_TOKEN` / `GITEA_RUNNER_REGISTRATION_TOKEN_FILE` at startup, which is what makes disposable runners practical.
|
||||
|
||||
## Interactive registration
|
||||
|
||||
```bash
|
||||
gitea-runner register
|
||||
# or with a config file
|
||||
gitea-runner -c config.yaml register
|
||||
```
|
||||
|
||||
The runner asks for:
|
||||
|
||||
- the instance URL, e.g. `https://gitea.com/` or `http://192.168.8.8:3000/` — use the instance's `ROOT_URL`, not `localhost`, when Gitea and the runner are in different containers or hosts;
|
||||
- the registration token;
|
||||
- the runner name, defaulting to the hostname;
|
||||
- the [labels](labels.md), defaulting to the built-in list, or to `runner.labels` when the config file sets it.
|
||||
|
||||
## Non-interactive registration
|
||||
|
||||
```bash
|
||||
gitea-runner register --no-interactive \
|
||||
--instance <instance_url> \
|
||||
--token <registration_token> \
|
||||
--name <runner_name> \
|
||||
--labels <runner_labels>
|
||||
```
|
||||
|
||||
The token can be kept off the command line, where it would show up in the process list and in shell history:
|
||||
|
||||
- `--token-file <path>` reads it from a file, e.g. a Docker or Kubernetes secret;
|
||||
- the `GITEA_RUNNER_REGISTRATION_TOKEN` environment variable is used when neither flag is given.
|
||||
|
||||
## The registration file
|
||||
|
||||
A successful registration writes a `.runner` file (`runner.file` in the config) into the current working directory. It holds the runner's identity and its API credentials, so:
|
||||
|
||||
- do not edit it by hand, and do not copy it to a second machine;
|
||||
- back it up or put it on a persistent volume, otherwise a recreated runner registers as a *new* runner and leaves a stale entry behind — and fails outright if the token has been reset in the meantime;
|
||||
- if it is lost or corrupted, delete it and register again.
|
||||
|
||||
Each runner process needs its own registration file. Two processes sharing one file are indistinguishable to Gitea and cancel each other's jobs; this version does not detect that, so give every runner its own `runner.file` or its own working directory. Runner `3.0` refuses to start in that situation.
|
||||
|
||||
## Ephemeral runners
|
||||
|
||||
An ephemeral runner accepts exactly one job and then exits. Once a job has been assigned, its credentials are revoked, so it cannot poll for more work before the job's untrusted code runs; it can still report progress until the job finishes.
|
||||
|
||||
This is how organization-wide or instance-wide runners can be offered without trusting every repository that may use them, provided each runner is a fresh VM or container.
|
||||
|
||||
```bash
|
||||
gitea-runner register --ephemeral
|
||||
gitea-runner register --no-interactive --ephemeral --instance <instance_url> --token <registration_token>
|
||||
```
|
||||
|
||||
With the Docker images, set `GITEA_RUNNER_EPHEMERAL=1` instead; no `/data` volume is needed, since the credentials are single-use:
|
||||
|
||||
```bash
|
||||
docker run -d --name my_runner \
|
||||
-e GITEA_INSTANCE_URL=<instance_url> \
|
||||
-e GITEA_RUNNER_REGISTRATION_TOKEN=<registration_token> \
|
||||
-e GITEA_RUNNER_EPHEMERAL=1 \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
docker.io/gitea/runner:2
|
||||
```
|
||||
|
||||
Because a fresh registration is required for every job, ephemeral runners are usually started on demand from the `workflow_job` webhook, which fires when a job is queued.
|
||||
|
||||
`--ephemeral` is stricter than `daemon --once`: `--once` also stops after one job, but its credentials stay valid for as long as the runner is registered.
|
||||
|
||||
## Re-registering and unregistering
|
||||
|
||||
Running `register` again in a directory that already has a registration file asks whether to overwrite it. To retire a runner, delete it in the Gitea UI (or via the API) and remove its registration file; the daemon shuts itself down once the server no longer knows it.
|
||||
|
||||
Changing labels does not require re-registration — see [Labels](labels.md#registration-versus-config-labels).
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
sidebar_position: 8
|
||||
---
|
||||
|
||||
# Upgrading
|
||||
|
||||
A runner upgrade is a binary or image replacement: stop the daemon, swap it, start it again. The registration file stays valid across versions, so a runner keeps its identity and does not have to be registered again.
|
||||
|
||||
```bash
|
||||
sudo systemctl stop gitea-runner
|
||||
sudo install -m 0755 gitea-runner-<version>-linux-amd64 /usr/local/bin/gitea-runner
|
||||
sudo systemctl start gitea-runner
|
||||
```
|
||||
|
||||
With `runner.shutdown_timeout` set, `stop` lets the jobs in flight finish first; without it, they are cancelled and Gitea reschedules them.
|
||||
|
||||
Config files are read leniently: keys the running version does not know are reported as a warning and ignored, so one file can be shared by runners of different versions. Compare your file with `gitea-runner generate-config` after an upgrade to pick up new options.
|
||||
|
||||
## 2.0
|
||||
|
||||
### Breaking
|
||||
|
||||
- **`DOCKER_USERNAME` / `DOCKER_PASSWORD` are no longer implicit pull credentials.** They used to be attached to every image pull, which sent private-registry credentials to Docker Hub for public images. They are ordinary secrets now. Migrate to:
|
||||
- `container.credentials` (and service `credentials`) in the workflow for private images;
|
||||
- a `docker login` performed on the runner host, for private `uses: docker://...` actions.
|
||||
- **`container.force_pull` now defaults to `false`** in the generated example config, so images already present are reused unless you ask for a pull.
|
||||
- **No environment variable overrides for the config.** `GITEA_DEBUG`, `GITEA_TRACE`, `GITEA_RUNNER_CAPACITY`, `GITEA_RUNNER_FILE`, `GITEA_RUNNER_ENVIRON` and `GITEA_RUNNER_ENV_FILE` are ignored; use a config file. The Docker images' [entrypoint variables](installation/docker.md#entrypoint-environment-variables) are unaffected.
|
||||
|
||||
### Also new
|
||||
|
||||
- [Post-task script](hooks/post-task-script.md) (`runner.post_task_script`) for host housekeeping between jobs.
|
||||
- [Health checks](monitoring.md#local-health-checks) (`health_check.*`) that pause task admission on low disk space or a failing script.
|
||||
- `register --token-file`, and `GITEA_RUNNER_LABELS` honoured by `daemon`, so labels can change without re-registering.
|
||||
- `jobs.<job_id>.timeout-minutes` and `jobs.<job_id>.continue-on-error` support, job summaries, shallow action clones (`runner.action_shallow_clone`), `ssh://` action URLs, IPv4/IPv6 options for auto-created networks, `--platform` and `--pull` in `container.options`, `cache.external_secret_file`, a GitHub-style "Set up job" log section, and pre/post entrypoints of Docker actions.
|
||||
|
||||
## Moving to 3.0
|
||||
|
||||
`3.0` filters host-escaping options out of a workflow's `container.options` while privileged mode is off, refuses to start a second process on the same registration file, and serves cache service v2 by default. See the [3.0 documentation](/runner/upgrade) before upgrading.
|
||||
|
||||
## Downgrading
|
||||
|
||||
Downgrading a runner is possible — the registration file format has not changed — but a config file written for a newer version may carry keys the older one ignores, and features such as cache service v2 stop being served, so jobs that came to rely on them fail. Test a downgrade with a spare runner before doing it on a busy pool.
|
||||
Reference in New Issue
Block a user