feat: scoped runner cleanup with ownership leases and disk admission

Extend stopped-container protection to an explicit lease contract
(org.oblachno.lease-until / org.oblachno.owner) honored by every cleanup
path. Consolidate the duplicated inline prune logic from docker-prune
and the healthcheck into a single tiered runner-cleanup.sh; remove the
unfiltered `system prune -af --volumes` / `volume prune` paths that could
wipe a job's volumes mid-run, and keep warm base images under pressure.

At critical disk usage the healthcheck now stops admitting new work
(stops gitea-runner.service once no CI job is in flight) and resumes it
automatically after recovery. The runner config declares capacity, and
the role refuses to install on production-marked hosts.
This commit is contained in:
Emil Simeonov
2026-09-22 18:34:12 +02:00
parent 49646c38db
commit 3c0696f3f2
10 changed files with 385 additions and 106 deletions
+19
View File
@@ -1,4 +1,23 @@
---
# Implements: REQ-6 (GRM-173) — a CI runner must never be installed on a
# production host (production workloads must not share hardware with
# arbitrary CI jobs, and runner cleanup logic assumes a dedicated host).
- name: Check for production-host marker
ansible.builtin.stat:
path: "{{ gitea_runner_production_marker_path }}"
register: gitea_runner_production_marker
- name: Fail on production hosts
ansible.builtin.fail:
msg: >-
Refusing to install a CI runner on a production host
(marker: {{ gitea_runner_production_marker_path }} present or
gitea_runner_on_production_host=true). Set
gitea_runner_allow_production_host=true to override.
when:
- not gitea_runner_allow_production_host
- gitea_runner_on_production_host or gitea_runner_production_marker.stat.exists
- name: Include systemd availability check
ansible.builtin.include_tasks: systemd_check.yml
@@ -1,4 +1,14 @@
---
# Implements: REQ-2 (GRM-173) — shared scoped cleanup script used by both
# the prune timer and the healthcheck disk-pressure tiers.
- name: Create runner cleanup script
ansible.builtin.template:
src: runner-cleanup.sh.j2
dest: "{{ gitea_runner_cleanup_script_path }}"
owner: "{{ gitea_runner_service_user }}"
group: "{{ gitea_runner_service_user }}"
mode: "0755"
- name: Create docker-prune user service file
ansible.builtin.template:
src: docker-prune.service.j2