mirror of
https://gitea.com/gitea/docs.git
synced 2026-09-17 19:55:34 +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,74 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# Job hooks
|
||||
|
||||
Job hooks are operator-provided scripts that run **inside the job environment**, before the job's first step and after its last one. They are the equivalent of GitHub's [job hooks](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/run-scripts):
|
||||
|
||||
```yaml
|
||||
runner:
|
||||
hooks:
|
||||
job_started: /hooks/started.sh
|
||||
job_completed: /hooks/completed.sh
|
||||
```
|
||||
|
||||
| Setting | Runs |
|
||||
| --- | --- |
|
||||
| `runner.hooks.job_started` | before the job's first step, before any action is downloaded |
|
||||
| `runner.hooks.job_completed` | after the job's last post step, while the job environment is still up |
|
||||
|
||||
`ACTIONS_RUNNER_HOOK_JOB_STARTED` and `ACTIONS_RUNNER_HOOK_JOB_COMPLETED` are read from the runner's environment (`runner.envs`, `runner.env_file`) when the settings are unset, so a configuration carried over from `actions/runner` keeps working. The settings take precedence. A workflow cannot point the runner at a different hook: those variables are only read from the runner's own environment, never from the job's.
|
||||
|
||||
Both hooks are **synchronous** and block the job while they run, and a non-zero exit from either one fails the job. There is no `continue-on-error` and no per-hook timeout — the job's `runner.timeout` is the only bound. Run anything long in the background from within the hook.
|
||||
|
||||
Use them for per-job setup that no workflow should have to carry: registry logins, mirror configuration, or masking runner-wide secrets with `::add-mask::`.
|
||||
|
||||
## Where they run
|
||||
|
||||
The hooks run where the job's steps run: inside the job container, or on the host in host mode. The paths are resolved *there*, so the script has to exist in the job image or on the host — a path that only exists on the runner host is not visible to a containerized job. For host-wide cleanup after the job environment is gone, use the [post-task script](post-task-script.md) instead.
|
||||
|
||||
:::note
|
||||
This is a deliberate difference from `actions/runner`, which runs its job hooks on the host, outside any container the job declares. Running them where the steps run is what lets a hook prepare the environment the steps actually see.
|
||||
:::
|
||||
|
||||
The script is run according to its extension:
|
||||
|
||||
| Extension | Command |
|
||||
| --- | --- |
|
||||
| `.sh` | `bash -e <path>` |
|
||||
| `.ps1` | `pwsh -command . '<path>'` |
|
||||
| anything else | the file itself, which needs its own shebang and executable bit |
|
||||
|
||||
As on GitHub, the shell flags applied to `run:` steps are **not** applied to a hook — set `pipefail` or anything else you want inside the script.
|
||||
|
||||
A hook path that does not exist inside the job environment fails the job with `No such file or directory`, naming the path.
|
||||
|
||||
### Docker-in-Docker and Docker-out-of-Docker
|
||||
|
||||
The hook is executed and its files are exchanged over the Docker API, addressed by container ID, so no path is translated between the runner and the daemon. Both setups work unchanged, but they differ in where the hook file has to be:
|
||||
|
||||
- **DinD** — the daemon has its own filesystem. Bake the hook into the job image; a path from the runner's filesystem is not visible to it.
|
||||
- **DooD** — the job container is created by the host's daemon, so a bind mount in `container.options` is resolved against the **host**, not against the runner container. Either bake the hook into the job image, or mount a host directory and add it to `container.valid_volumes`.
|
||||
|
||||
## Environment
|
||||
|
||||
A hook sees the job's environment: the workflow, job and `container:` `env:`, the runner's `envs`, and the `GITHUB_*` context variables, with the same masking applied to its output as to a step's. The step-specific ones (`GITHUB_ACTION`, `GITHUB_OUTPUT`, `GITHUB_STATE`) are not set — a hook is not a step, so `::save-state::` and `::set-output::` have nowhere to go.
|
||||
|
||||
Its stdout is part of the job log, inside a collapsible group, and is scanned for workflow commands: `::add-mask::` registers a value to be masked for the rest of the job, `::set-env::` and `::add-path::` apply to the steps that follow.
|
||||
|
||||
`$GITHUB_ENV` and `$GITHUB_PATH` point at files that are read back after the hook exits, so the file-command form works too:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
echo "REGISTRY_TOKEN=$(fetch-token)" >> "$GITHUB_ENV"
|
||||
echo "/opt/tooling/bin" >> "$GITHUB_PATH"
|
||||
```
|
||||
|
||||
Both files are the hook's own, separate from the per-step ones, so nothing a hook writes is truncated by the first step.
|
||||
|
||||
## Recommendations
|
||||
|
||||
- Keep hooks **fast** and return the right exit code: they are on the critical path of every job, and nothing bounds them.
|
||||
- Use **idempotent** operations, and expect `job_completed` to run after success, failure, and cancellation alike.
|
||||
- Mask anything secret the hook prints or exports with `::add-mask::`.
|
||||
@@ -0,0 +1,101 @@
|
||||
---
|
||||
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.
|
||||
- For work that has to happen inside the job environment, use [job hooks](job-hooks.md) instead.
|
||||
Reference in New Issue
Block a user