Files
pikasTech-unidesk/docs/reference/gc.md
T
2026-07-05 04:18:22 +00:00

324 lines
35 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Disk GC And Retention Reference
UniDesk 的磁盘治理入口是 `bun scripts/cli.ts gc ...`。该入口用于短期一次性止血和低风险防膨胀策略,所有清理动作都必须先有结构化 plan,再通过显式确认执行。GC 不是通用 `rm -rf` 或原生命令集合;当目标磁盘水位无法在保护边界内下降到阈值以下时,应停止并升级为 retention/capacity 决策,而不是扩大清理范围。
所有主 server GC 可调策略都由 `config/unidesk-cli.yaml#gc` 拥有,包括默认 include 开关、保留窗口、输出 limit、Codex session root、worktree main/root/baseRef、worktree 扫描预算、`.state` allowlist roots 和是否在 plan 阶段估算 worktree size。CLI 参数只作为一次性显式覆盖;代码只校验 YAML 字段存在、类型正确和路径可渲染,不把这些策略值写成隐藏默认。
## Command Boundary
- `gc plan`:只读生成主 server 清理候选、估算收益、风险等级、保护对象和数据库诊断摘要。
- `gc run --confirm`:只执行当前 plan 可见候选页,默认不执行分页隐藏候选;用 `--limit``--result-limit``--full|--raw` 控制披露和执行范围。
- `gc policy plan|install`:从 `config/unidesk-cli.yaml#gc.policyTimer` 渲染或安装低风险长期策略,例如 journald cap、每日 allowlisted 文件/tmp 清理 timer、VPN 诊断 pcap retention、`.state` artifact retention 和 VS Code CachedExtensionVSIXs 下载缓存 retention。
- `gc db-trace plan|run --confirm --before-date YYYY-MM-DD --vacuum-full`:显式 trace 遥测留存入口;涉及数据库重写时按维护窗口处理。
- `gc remote <providerId> plan|run --confirm|status --job-id <id>`:通过 UniDesk SSH 透传在 provider host 上执行受控 GC。远端长任务必须使用异步 job 和 `status` 短查询,不应让单次 SSH 等待完整 registry GC 或其他长清理。
- `--include-tool-caches`:本机和远端都必须是显式 opt-in,只清理固定 allowlist 的可重建 npm/npx/Bun 缓存;不得扩大成清理 `~/.npm``~/.bun``node_modules`、auth/config 或运行面依赖。
所有成功和失败输出都必须是 JSON。`plan` 必须标记 `dryRun=true``mutation=false``run` 必须要求 `--confirm` 并报告 `diskBefore``diskAfter``summary``results``protected`。远端 GC 可用 `--target-use-percent N` 显式表达目标根盘水位;`summary.target` 必须给出目标所需释放量、候选估算、预计水位、缺口和 `safeStop` 决策,避免靠人工心算判断是否应该继续扩大清理范围。
默认 `/tmp` GC 只包含 allowlisted 诊断目录和已知低风险路径。非 allowlist 的 stale `/tmp` 一级子项必须显式 `--include-stale-tmp` 才能进入候选;扫描按 `--limit` 有界枚举候选,执行时仍只允许删除 `/tmp` 直接子项,并避开 X11/ICE/font socket、systemd private、tmux、ssh、vscode 等系统/session 前缀。该入口不能递归扩大成通用 `/tmp` 清空器,也不能为了估算全量临时目录而长时间阻塞。
主 server VPN 诊断日志默认不清理。`/root/vpn-server/logs` 中由长期 `tcpdump -G` 产生的 `hy2-udp-ring-*.pcap``hy2-monitor-ring-*.pcap` 可通过显式 `--include-vpn-diagnostic-logs` 进入候选,默认只选择超过 `--vpn-diagnostic-log-keep-hours 24` 的普通 pcap 文件。执行前必须重新校验路径、文件名、非 symlink/regular file,并用 active-file 检查确认没有进程仍打开该文件。`hy2-server-evidence.jsonl`、stdout/stderr log、最新 pcap 和整个日志根目录始终作为 protected 输出,不得被这个入口删除或截断。
主 server `.state` 历史诊断和部署产物默认不进入手动 GC。需要清理时必须显式传入 `--include-state-artifacts`,保留期通过 `--state-artifact-keep-days N` 设置,默认 14 天且必须是正整数。该入口只选择以下对象:
| 范围 | 候选 |
|---|---|
| `.state/e2e` | 超过保留期的普通文件 |
| `.state/validation` | 超过保留期的普通文件 |
| `.state/jobs` | 超过保留期的普通文件 |
| `.state/codex-queue/output-archive` | 超过保留期的普通文件 |
| `.state/deploy/exports` | 超过保留期的直接子目录 |
| `.state/deploy/resolve` | 超过保留期的直接子目录 |
`gc run --confirm --include-state-artifacts` 执行前必须重新校验路径、保留期、对象类型和 symlink 状态。文件候选必须仍是 allowlist 根下的普通文件;deploy 目录候选必须仍是 `.state/deploy/exports``.state/deploy/resolve` 的直接子目录。该入口不得递归扩大成通用 `.state` 清空器,也不得选择 `.state` 根目录、allowlist 之外的目录、symlink、active worktree、runtime image 或 snapshot 状态。
`.state` scratch 清理是另一类显式入口:`--include-state-stale-scratch` 只读取 `config/unidesk-cli.yaml#gc.stateStaleScratch` 中声明的 fileRoots/dirRoots 和 keepHours。它用于历史临时验证、性能探针、Web observe、CD scratch 等可重建对象;`.state/recovery``.state/codex-queue/codex-home``.state/deploy/work``.state/baidu-netdisk`、Secret/sourceRef 和 runtime snapshot 仍作为 protected 输出,不允许通过这个入口扩大删除范围。
Codex session 清理由 `--include-codex-sessions` 显式启用,只删除 `config/unidesk-cli.yaml#gc.codexSessions.root` 下超过 YAML keepHours 的普通 session 文件。执行前必须重新校验路径仍在 YAML root 下、对象是普通文件、未被进程打开,删除后只向上清理空目录;`auth.json`、config、profile、Secret 或其他 Codex state 永远不通过该入口删除。
Worktree 清理由 `--include-merged-worktrees` 显式启用,只扫描 `config/unidesk-cli.yaml#gc.mergedWorktrees.root` 下的 worktree,主 worktree、当前执行 worktree、recent worktree、未合入 YAML baseRef 或 cherry-pick 等价未吸收的 worktree 都作为 protected 输出。plan 阶段按 YAML scanBudgetMs 有界扫描,超预算对象 protected;run 阶段删除前重新执行 full `git status --untracked-files=all`、inactive 和 merge/cherry-equivalence 校验,并通过 `git worktree remove` 删除,不用手工 `rm -rf`
主 server VS Code 下载缓存默认不清理。`/root/.vscode-server/data/CachedExtensionVSIXs` 只用于 VS Code extension VSIX 下载缓存,可通过显式 `--include-vscode-cached-vsix` 进入候选;执行时只允许删除该目录下符合 extension-version 命名的顶层普通文件,并按 `--vscode-cached-vsix-keep-days` 保留近期缓存。执行前必须重新校验路径、文件名、非 symlink/regular file,并用 active-file 检查确认没有进程仍打开该文件。该入口不得触碰 `/root/.vscode-server/extensions``/root/.vscode-server/cli/servers`、VS Code user data 或任意 session/auth state。
## Protected Data
默认 GC 不得删除或 prune 以下对象:
| 对象 | 保护原因 |
|---|---|
| PostgreSQL PGDATA | 数据库权威状态,必须走备份、留存或迁移流程 |
| Docker image/container/volume | 运行面和发布真相可能依赖旧镜像或 volume |
| `.state/recovery` | 恢复状态和人工回滚线索,不属于 artifact retention |
| `.state/codex-queue/codex-home` | Codex sessions/auth/profile 状态,不得作为队列输出归档清理 |
| `.state/deploy/work` | 部署工作目录可能包含 active rollout 上下文 |
| `.state/baidu-netdisk` | Baidu Netdisk token、任务、备份和 staging 状态需单独判定 |
| active worktree、runtime image、runtime snapshot state | 当前执行面和运行面 provenance,不通过 `.state` artifact retention 删除 |
| Codex auth/config | `~/.codex/auth.json`、profile 和 config 等凭证状态;session 文件只能通过显式 `--include-codex-sessions` 按 YAML retention 清理 |
| VPN diagnostic evidence logs | `/root/vpn-server/logs/hy2-server-evidence.jsonl` 等 active evidence 流用于网络排障,不随 pcap retention 删除 |
| VS Code installed extensions/server/user data | 已安装扩展、server 版本和用户配置不是下载缓存,只能由专门 stale-version 规则或 VS Code 自身管理 |
| D601 registry storage | artifact registry retention 需使用专门入口 |
| `/var/lib/rancher/k3s``/var/lib/rancher/k3s/storage` | k3s 控制面、containerd 状态和 local-path PVC 数据 |
| `/var/lib/kubelet``/var/lib/containerd` | kubelet/runtime 状态和可能被 workload 复用的 image cache |
| HWLAB 固定 workspaces | `/root/hwlab``/root/hwlab-v02``/root/agentrun` 是 source/runtime 约束的一部分 |
| Kubernetes workload、Secret、PVC、PV、Argo、Tekton 对象 | 必须通过对应运行面 retention 子命令或 GitOps/CI 控制入口处理 |
如果需要触碰上表对象,必须先补高层 UniDesk CLI 子命令、dry-run 计划、保护对象、验证命令和失败分类;不能把原生 `kubectl``docker prune``crictl rmi` 或手写 registry shell 作为长期流程。
`gc policy install` 的每日 timer 按 `config/unidesk-cli.yaml#gc.policyTimer` 启用 `.state` artifact retention、VPN pcap retention 和 VS Code CachedExtensionVSIXs retention,用来限制历史诊断/部署产物、tcpdump ring 文件与 VS Code 下载缓存长期增长;手动 `gc plan/run` 仍默认不清 `.state` 或 VSIX 缓存,必须显式 `--include-state-artifacts` / `--include-vscode-cached-vsix` 才会列出或执行这些候选。policy timer 仍保护上表对象,并把输出限制在 `.state/gc/last-run.json``.state/gc/last-run.stderr`
## Remote G14 Policy
`gc remote G14 ...` 必须先确认目标是 G14 原生 k3s 节点,且 preflight 中节点名包含 `ubuntu-rog-zephyrus-g14-ga401iv-ga401iv`。G14 默认候选只允许:
- systemd journal vacuum 到目标上限。
- Docker `json-file` 日志截断。
- Docker BuildKit cache prune,默认只清理超过 `--build-cache-until` 的 cache。
- apt archive clean。
- allowlisted `/tmp` 诊断目录删除。
- 受限 core dump 删除。
受限 core dump 只匹配 `/root/unidesk/core.<pid>` 普通文件。执行前必须重新校验路径 allowlist、Git 未跟踪、非 symlink、无 `fuser` 活跃引用。估算收益必须按实际分配块数计算,并可另行披露 `apparentSizeBytes`;不能把 sparse core dump 的表观大小当成可回收磁盘空间。
## Remote PK01 Policy
PK01 是腾讯云 Docker provider,不是 G14 k3s/registry 节点;长期运维边界见 `docs/reference/pk01.md``gc remote PK01 ...` 可用于通用低风险候选(allowlisted `/tmp`、Docker json-file 日志、BuildKit cache、apt cache、受限 core dump 和 journald 计划),但 pikanode 的主要增长源由 PK01 节点本地 retention 机制管理,而不是 G14 registry/PVC retention。
PK01 pikanode temp retention 只允许清理 `/home/ubuntu/pikanode/html/temp` 下超过保留窗口的直接子目录,并必须保护 `html/download/``html/upload/``files/`、证书、Git state、直接日志文件和近期 temp workspace。该策略已固化为 PK01 节点本地 systemd timer 与 logrotate;人工排障时优先查看 `systemctl status unidesk-pk01-pikanode-temp-gc.timer``/var/log/unidesk-pk01/pikanode-temp-gc.log`。如果 PK01 高水位仍无法通过 temp retention 和通用低风险 GC 降下来,必须停止并进入 pikanode 下载产物留存、Docker image retention 或容量扩容决策,不能把 `download/``files/` 或 Docker overlay 当作普通临时目录删除。
## Remote JD01 Policy
JD01 是 YAML-first k3s provider,承载 AgentRun、HWLAB v0.3、Web probe sentinel 和相关 PVC/state artifact。`gc remote JD01 ...` 的目标节点、lane、namespace 集合、state root、保护路径、扫描预算、artifact cap、retention 窗口、observer stop 策略和输出 limit 必须来自 `config/unidesk-cli.yaml#gc.remote.targets.JD01` 或等价 source of truth;CLI 参数只作为一次性覆盖,不得把 JD01 namespace、路径或阈值写成脚本隐藏默认。
JD01 远端 plan 必须适配短连接:`snapshot` 和轻量 `plan` 返回有界 JSON;涉及 k3s/PVC 实占、state root 深扫、history/trend 或大 protected path size 的长任务必须创建异步 job,并通过 `gc remote JD01 status --job-id <id>` 渐进查询。protected path size 采集必须是 budgeted/progressive:每个 protected item 披露 `sizeState`、耗时、超时或失败原因;`du` 超时后不得回退为无界递归扫描,也不得让保护对象尺寸统计阻塞 plan 返回。
JD01 PVC 归因必须按 YAML 配置的 namespace 集合读取 k8s API,不得复用 G14 专属 namespace 硬编码。报告至少包含 namespace、PVC、PV、host path、requested size、estimated actual bytes、active mount pods、owner/session/PipelineRun/runId、phase 和 reclaim policy。默认只做 plan 和归因;删除 PVC/PV、local-path host path、k3s storage、containerd snapshot/blob 或 workload 对象必须通过对应高层 retention 子命令和 GitOps/运行面 owner 判定,不能由 remote GC 扩大成 raw `kubectl delete` 或 host path 删除。
JD01/AgentRun 这类 PVC retention 确认入口必须适配短连接:确认步骤只提交经过 plan 选中的 Kubernetes 删除请求并快速返回,不能等待 local-path PV 后端同步回收完成;收敛状态通过下一次 dry-run、`gc remote JD01 status` 或专用 status 子命令查询。若一次提交在 transport 窗口内仍不稳定,应降低 YAML/CLI 批量,而不是改成手工 raw kubectl 或 host path 删除。
JD01 local-path storage 中没有 PV 引用的 orphan 目录只能通过 `gc remote JD01 plan|run --include-local-path-orphans` 进入候选。该入口必须从 YAML 读取 storage root、目录前缀 allowlist 和年龄策略,只允许删除 root 的直接子目录,且执行前重新确认无 PV 引用、无 symlink、无打开 fd/cwd;不得把它扩大成通用 `/var/lib/rancher/k3s/storage` 清空或 raw host path 删除。
JD01 host containerd 只能通过 `gc remote JD01 plan|run --include-host-containerd-cache` 进入候选。该入口必须从 YAML 读取 containerd root、socket address 和 namespace allowlist;只有 host containerd 目标 namespace 中没有 task/container 时才允许执行 `ctr images prune --all`,不得直接删除 `/var/lib/containerd` 下的 content、snapshot 或 metadata 路径。
当 host containerd 的 `ctr` 元数据中 images、containers、tasks、leases、snapshots 和 content 全为空,但 YAML allowlist 下仍残留 overlay snapshot 目录或 content blob 文件时,才能把它们分类为 orphan state。orphan state 清理仍必须通过 `--include-host-containerd-cache` 的 plan/run,执行前重新检查元数据为空、路径在 YAML root 下、名称匹配受控形态、无 symlink、无打开 fd/cwd;不得删除 metadata DB 或扩大到 containerd root。
JD01 Web observe artifact 是一等 GC 对象。state root 必须来自 YAML;候选按 run 聚合并读取 `manifest.json``heartbeat.json``pid`、report sha 和 top files。年龄判定以 manifest/heartbeat 的 started/completed/updated 字段、pid 存活和打开 fd 检查为准,不以目录 mtime 为唯一依据,因为手动 GC 或目录遍历可能刷新 mtime。active run、pid alive、open fd、未生成必要 report 的 run 均为 protected。safe 候选只覆盖超过 YAML retention 且可重建的 raw samples、browser-process、network/trace、screenshot 等大 artifact;长期保留 report summary、report json/md、最终截图或诊断摘要由 YAML cap/retention 策略控制。
JD01 Chrome 内存治理应优先管理 observer runner 生命周期,而不是孤立清理 Chrome 进程。Web probe sentinel 和 quick-verify 启动 observer 后,所有终态路径(成功、blocked、失败、timeout、异常)都必须执行 YAML 控制的 `web-probe observe stop`/force stop 流程,并验证对应 runner/Chrome process tree 退出;observe runner 自身也必须从 scenario/YAML 获得最大运行时长或 max samples 兜底,即使调用方退出也会停止采样并关闭 browser。browser freeze policy 只能作为异常保护,不替代正常任务生命周期结束后的 stop。
JD01 plan 和 status 应同时披露内存压力摘要:active observer 数、Chrome process 数、Chrome RSS、stale observer 数、state root artifact bytes、last cleanup、last stop failure 和 drill-down 命令。GC run 只能执行 plan 中明确标记 safe 的低风险动作,例如 apt/journal/tmp allowlist、dead web-observe raw artifact retention,以及通过受控 observe stop 处理 stale observer;对 PVC、k3s runtime、containerd、Docker volume、Secret 和 auth/config 状态一律保持 protected 或转交专用 retention 入口。
JD01 的 npm/npx/Bun 缓存可作为中低风险边界候选,但必须通过 `gc remote JD01 plan|run --include-tool-caches` 显式启用。该入口只允许固定 allowlist 的可重建缓存目录,并在执行前重新校验路径、非 symlink 和 allowlist;它不清理 `node_modules`、用户配置、认证状态、k3s/containerd、PVC、Docker image/container/volume 或 GitOps 运行面对象。
Web probe sentinel 的 `quick-verify`、Playwright 或浏览器验证不得作为 CI/CD 发布 gate 自动周期触发。若某个 sentinel 需要周期 quick-verify,必须在 YAML 中显式 opt-in cadence scheduler;默认发布验证只看配置的 health endpointquick-verify 只作为人工或独立 post-deploy evidence 入口。这样避免 CI/CD 周期性重启 observer/Chrome 并重新制造内存和 artifact 增长。
## HWLAB Registry Retention
G14 HWLAB registry 清理必须显式使用 `--include-hwlab-registry`,默认 `gc remote G14 plan` 不进入 registry。策略必须保守,不能只留 latest,也不能只删除 tag link 后误判已经释放空间。
默认保留规则:
| 保留项 | 规则 |
|---|---|
| 当前 workload 引用 | 保留所有当前 k3s workload 使用的 tag ref 和 digest ref |
| digest closure | 从当前 workload、保留 tag、protected/base/非业务 repo 出发,保留 manifest config/layer/manifest-list 的 digest 闭包 |
| 近期 tag | 保留 `--registry-min-age-hours` 内全部 tag,默认 48 小时,可显式设为 0 |
| 每 repo 最新 tag | 每个业务 repo 至少保留 `--registry-keep-per-repo` 个最新 tag,默认 20,最小 1 |
| cache/base/protected tag | 保留 cache repo、`latest`、基础镜像 tag 和显式 protected tag |
| 非业务 repo | 默认不删除非 `hwlab/hwlab-*` 的 commit-like tag |
删除范围包括两类:不在保留集内的 commit-like tag,以及 `hwlab/hwlab-*` / `hwlab/cache/hwlab-*` repo 内不在保留 digest closure 的 stale `_manifests/revisions/sha256/<digest>`。执行时先在 registry 在线状态下通过 API 删除 manifest,再缩容 registry pod,删除遗留 tag/revision 目录,运行官方 `registry garbage-collect`,最后恢复 registry。`--registry-gc-only` 只用于中断恢复或人工维护窗口收尾:它不删除任何 tag 或 revision,只运行官方 GC。
BuildKit cache repo 的历史 `latest` 写入会留下大量 untagged manifest revision;只删除 tag 通常只能释放少量 manifest blob,无法释放旧 cache layer。需要大幅降低 `/var/lib/hwlab/registry` 时,必须以 plan 输出的 `deleteRevisions``protectedDigestClosure` 和 official GC 后的 `diskAfterBytes` 判断是否真正生效。
Registry 执行必须以远端异步 job 完成,并具备以下维护保护:
- 先记录并暂停 G14/v0.2 branch poller CronJob;目标集群中某条 lane 暂无 CronJob 时记录为 absent,不视为失败。
- 暂停 poller 后再等待 hwlab-ci PipelineRun、TaskRun 和 Job 空闲;不能在暂停前因为 active CI 直接拒绝,否则 poller 竞态会导致 maintenance 反复失败。
- 通过 registry API 删除 manifest 时 registry 必须仍在线。
- registry 下线后只能删除通过 plan 判定的 tag/revision 目录;不得直接删除 blob 目录。
- 缩容 registry 后运行官方 `registry:2.8.3` garbage-collect pod。
- finally 阶段删除 GC pod、恢复 registry replicas、等待 rollout、恢复 CronJob suspend 状态。
- 状态查询使用 `gc remote G14 status --job-id <id>`,不使用长 SSH 会话等待。
- `gc remote` 的 stdout 是有界 JSON:当 `--full` 或大量候选导致结果过大时,完整结果会写入远端 `/tmp/unidesk-gc-remote/jobs/<job>.json`stdout 只返回摘要、`jobId``statePath``statusCommand`,再用 `gc remote G14 status --job-id <job>` 渐进查询,避免输出爆炸被误判为 JSON 失败。
## G14 CI Workspace Retention
G14 的 Tekton workspace retention 不能通过原生 `kubectl delete`、直接删除 `/var/lib/rancher/k3s/storage` 或手工清 PV host path 完成。所有完成态 PipelineRun workspace 清理都必须走对应高层 UniDesk CLI,先 dry-run 输出候选和保护对象,再 confirm 执行。
AgentRun `v0.1` 使用 `agentrun-ci` namespace
```bash
bun scripts/cli.ts agentrun control-plane cleanup-runs --min-age-minutes 30 --limit 200 --dry-run
bun scripts/cli.ts agentrun control-plane cleanup-runs --min-age-minutes 30 --limit 200 --confirm
bun scripts/cli.ts agentrun control-plane cleanup-released-pvs --limit 200 --dry-run
bun scripts/cli.ts agentrun control-plane cleanup-released-pvs --limit 200 --confirm
```
HWLAB 使用 `hwlab-ci` namespace
```bash
bun scripts/cli.ts hwlab g14 control-plane cleanup-runs --lane v02 --min-age-minutes 30 --limit 200 --dry-run
bun scripts/cli.ts hwlab g14 control-plane cleanup-runs --lane v02 --min-age-minutes 30 --limit 200 --confirm
bun scripts/cli.ts hwlab g14 control-plane cleanup-released-pvs --lane all --limit 200 --dry-run
bun scripts/cli.ts hwlab g14 control-plane cleanup-released-pvs --lane all --limit 200 --confirm
```
Retention 入口的长期合同:
- 默认只选择 `Succeeded`/`Failed` 的完成态 PipelineRun,且必须达到 `--min-age-minutes`
- 默认保护每条 lane 或前缀下最新完成的 PipelineRun,保留当前 CI/CD 状态证据;只有显式定点目标才允许清理最新证据。
- dry-run 必须披露候选 PipelineRun、owned PVC、active mount 保护、预估可回收空间或可回收对象数,以及 confirm 命令。
- confirm 首先删除 PipelineRun,让 Tekton ownerRef 释放临时 PVC;随后用 `cleanup-released-pvs` 处理 local-path 未自动删除的 `Released` PV。
- `cleanup-released-pvs` 只能选择 `local-path``Delete` reclaim policy、目标 CI namespace 的 Released PV;不得触碰业务 namespace、runtime PVC、Secret、registry storage 或 GitOps desired state。
CI workspace retention 是 registry retention 之前的低风险步骤。若它清不出足够空间,不能扩大到 raw PV/path 删除;应继续进入 registry retention plan,或进入 safe-stop 决策。
## Safe Stop Line
磁盘目标可以设为 `<70%` 或维护窗口临时目标如 `<50%`,但安全边界优先级高于目标百分比。目标必须直接传给 CLI,使输出带有可机读缺口:
```bash
bun scripts/cli.ts gc remote G14 plan --target-use-percent 50 --limit 20
bun scripts/cli.ts gc remote G14 plan --target-use-percent 50 --include-hwlab-registry --limit 20
```
`summary.target.safeStop=true``state``shortfall``safe-stop-no-meaningful-candidates` 时,应停止自动清理并提交决策表。若默认 plan 和 registry plan 都无法覆盖目标缺口,剩余空间通常位于 registry 保留集、k3s runtime、containerd image cache 或 PVC 数据中。继续下降需要显式选择以下更高风险方案之一:
| 方案 | 风险 | 需要的前置决策 |
|---|---|---|
| 降低 registry 每 repo 保留数或缩短近期 tag 窗口 | 可能影响切旧 tag 回滚 | 明确旧 tag 回滚窗口和服务 owner 接受标准 |
| containerd/k3s image cache prune | 可能触发 workload 重新拉镜像或旧镜像缺失 | registry 健康、镜像可拉取性和维护窗口 |
| PVC/runtime 数据 retention | 可能删除业务状态或 CI 证据 | 业务 owner 确认数据类别和留存期限 |
| rsyslog 文件日志压缩/截断 | 可能丢失一线故障证据 | 明确日志留存窗口,先补受控 CLI/logrotate 策略 |
| source worktree/cache TTL | 可能删除并行任务上下文或本地依赖缓存 | worktree owner、分支状态、dirty 状态和可重建性判定 |
| 扩容磁盘 | 低运行风险 | 节点容量预算和停机/在线扩容方式 |
G14 进入 50% 这类维护窗口目标时,标准顺序是:
1. `gc remote G14 plan --target-use-percent <N>` 取得默认低风险候选和缺口。
2. 运行 AgentRun/HWLAB CI workspace retention,并二次处理 Released PV。
3. 使用 `--include-hwlab-registry` 规划 registry retention;默认保守保留,维护窗口内可显式把 `--registry-keep-per-repo` 降到 1,但必须保留当前 workload refs 和 digest closure。
4. 再次运行 `gc remote G14 plan --target-use-percent <N> --include-hwlab-registry ...`
5. 若只剩 KiB 级低风险候选且 `safeStop=true`,停止自动清理,不得为了命中百分比目标手工删除受保护目录。
维护窗口目标接近整数边界时,验收必须同时报告 `df -h /``df -B1 /``summary.target` 使用字节计算,`df` 使用整数展示,二者在 49/50 这类边界可能看起来不一致;收口时以最终 `diskAfter.usePercent``df -h` 展示和字节视图共同说明,不得因为四舍五入差异绕过 protected boundary。
## G14 Space Attribution Baseline
G14 当前只有一个本机 k3s cluster;空间归因时不要把 `hwlab-dev``hwlab-prod``hwlab-v02` 理解成独立 cluster,它们是同一 k3s 上的 namespace/runtime slice。长期诊断应按三层归因:
| 层级 | 归因方式 | 判读口径 |
|---|---|---|
| Host path | `du -x``/var/lib/*``/root``/usr` 等目录统计 | 判断根盘主要压力源 |
| k3s namespace/PVC | `kubectl get pv,pvc,pod -A -o json` 结合 local-path PV host path | 把可归属数据映射到 namespace/workload |
| Registry repo/tag/revision | registry v2 repository/tag link、manifest revision 与 blob manifest 解析 | 判断镜像历史 tag、cache revision 与共享 layer 的贡献 |
G14 高水位的长期基线分布如下,后续诊断出现同类量级时优先按同一顺序处理。registry 和 CI workspace retention 后,空间压力通常从 `/var/lib/hwlab/registry` 转移到 k3s containerd snapshot/content、local-path PVC、host containerd、rsyslog 文件日志和 source worktree/cache;这些都属于受保护或需策略化处理的运行面,不能为了达到百分比目标直接删除目录。
| 类别 | 路径 | 典型量级 | 归因说明 |
|---|---|---:|---|
| HWLAB local registry | `/var/lib/hwlab/registry` | 高水位约 60GiB;强 retention 后约十几 GiB | 最大头;按 repo/tag/revision retention 管理,不能直接删 blob |
| k3s runtime | `/var/lib/rancher/k3s` | 高水位约 45-55GiB;清理后约 28-35GiB | embedded containerd、local-path PVC 和 k3s server/db |
| k3s containerd snapshots | `/var/lib/rancher/k3s/agent/containerd/.../snapshots` | 高水位约 30-40GiB;清理后约十几 GiB | workload image layer/snapshot cache,共享占用,不能直接按单 pod 删除 |
| k3s containerd blobs | `/var/lib/rancher/k3s/agent/containerd/.../blobs` | 高水位约 8-12GiB;清理后约数 GiB | k3s image content store,共享占用 |
| k3s local-path PVC | `/var/lib/rancher/k3s/storage` | 高水位约 8-10GiBCI retention 后约 6-8GiB | 可按 namespace/PVC 归因,只能通过运行面 retention 入口清理 |
| host containerd | `/var/lib/containerd` | 约 9-12GiB | k3s 外的 host/containerd cache,默认不由 remote GC prune |
| root workspaces/cache | `/root` | 约 2-8GiB | HWLAB/v0.2 worktree、npm/bun/cache 等;worktree TTL 需 owner/dirty 判定 |
| logs | `/var/log` | 约 1-3GiB | journald 可由 GC caprsyslog 文件需受控 logrotate/压缩策略,pod logs 通常较小 |
PVC 的长期判读口径:
| Namespace | 典型占用 | 主要来源 |
|---|---:|---|
| `hwlab-ci` | 约 2GiB | 完成态 Tekton TaskRun workspace PVC;单个 PVC 通常约 0.24GiB |
| `hwlab-dev` | 数百 MiB | `hwlab-code-agent-workspace` 与 dev Postgres |
| `hwlab-prod` | 数百 MiB | `hwlab-code-agent-workspace` |
| `hwlab-v02` | 数百 MiB | `hwlab-code-agent-workspace` 与 v0.2 Postgres |
Registry 的长期判读口径:
| Repo 类型 | 典型形态 | 说明 |
|---|---|---|
| `hwlab/hwlab-cloud-api` | tag 数可超过 20unique blob 数 GiB | 最大业务 repo,优先观察 tag 增长 |
| `hwlab/hwlab-agent-*``hwlab/hwlab-cloud-web``hwlab/hwlab-gateway*` | 每 repo 保留约 20 tag 时通常各占数 GiB | 多服务并行构建导致 registry 线性增长 |
| `hwlab/cache/*` | tag 少但共享 layer 多 | 不能按 expanded size 简单相加 |
| base/protected image | tag 少,占用低到中等 | 保留用于构建和运行回滚 |
Registry 报告必须区分 `uniqueBlobBytes``sharedBlobBytes`。多个 repo/tag 复用同一 layer 时,expanded tag size 会重复计算;判断可回收空间应以 official registry GC 后的根目录变化为准。
## Diagnosis Commands
G14 空间审计默认只读。需要报告时优先采集以下摘要,避免全量 dump 大 JSON:
```bash
trans G14 sh -- 'df -h / | tail -1'
trans G14 sh -- 'du -xh -d 1 / /var /var/lib /root 2>/dev/null | sort -h | tail -40'
trans G14 sh -- 'du -xh -d 2 /var/lib/rancher/k3s /var/lib/containerd /var/log 2>/dev/null | sort -h | tail -80'
trans G14:k3s kubectl get pv,pvc,pod -A -o wide
trans G14 sh -- 'find /var/lib/hwlab/registry/docker/registry/v2/repositories -path "*/_manifests/tags/*/current/link" -type f | wc -l'
```
需要深挖 registry 时,报告字段至少包括 repo、tag count、manifest revision count、latest tags、protected digest closure、unique blob bytes 和 shared blob bytes。需要深挖 k3s runtime 时,报告字段至少包括 namespace/PVC、PV host path、owner workload、PVC 实占、k3s containerd snapshots/blobs 总量。不要把 `/var/lib/kubelet/pods``/var/lib/rancher/k3s/storage` 简单相加,因为 kubelet pod 目录可能包含 PVC bind mount 或 runtime 元数据,存在重复计数风险。
需要深挖日志和 worktree 时,默认只读报告,不直接清理:
```bash
trans G14 sh -- 'du -xh -d 1 /var/log 2>/dev/null | sort -h | tail -40'
trans G14 sh -- 'du -xh -d 2 /root/hwlab-v02/.worktree 2>/dev/null | sort -h | tail -60'
```
rsyslog 文件日志不属于当前 `gc remote` 默认可变更对象。若 `/var/log/syslog*``/var/log/kern.log*` 或同类文件成为 50% 目标的最后缺口,应先新增受控 logrotate/压缩/截断 CLI,并在输出中披露保留 tail、压缩对象、释放估算和失败恢复;禁止直接 `truncate` 或删除日志文件作为长期流程。`/root/hwlab-v02/.worktree` 只能在明确 owner、branch、dirty 状态和可重建性后清理,不能按目录大小直接删除。
JD01 空间和 Chrome 压力审计同样默认只读。需要深挖时,优先通过 `gc remote JD01 snapshot|plan|status` 暴露有界摘要;必要的远端探测只用于补 CLI 证据,不作为长期手工流程。报告字段至少包括 root 水位、inode、水位目标缺口、YAML 配置引用、k8s PVC namespace 归因、web-observe run artifact topN、observer/Chrome process tree 摘要、protected sizeState 和 safe/blocked 分类。Web observe run 的 stale 判定必须说明 manifest/heartbeat/pid/open-fd 依据;不能把目录 mtime 当作唯一证据。
## Validation Checklist
G14 GC 后必须验证:
```bash
trans G14 sh -- 'df -h / | tail -1'
trans G14 sh -- 'curl -fsS http://127.0.0.1:5000/v2/ >/dev/null && echo ok'
trans G14:k3s kubectl -n hwlab-ci get deploy hwlab-registry
trans G14:k3s sh -- 'kubectl -n hwlab-ci get cronjob hwlab-g14-branch-poller -o custom-columns=NAME:.metadata.name,SUSPEND:.spec.suspend --no-headers && ! kubectl -n hwlab-ci get cronjob hwlab-v02-branch-poller >/dev/null 2>&1'
```
DEV workload 验证应检查非零副本 workload 是否 ready`0/0` 的显式停用 deployment 不应误报为事故。registry tag 数只作为辅证,不能替代 workload ref 保护和 registry API 健康。
同时必须用高层 CLI 验证受影响运行面仍对齐:
```bash
bun scripts/cli.ts agentrun control-plane status
bun scripts/cli.ts hwlab g14 control-plane status --lane v02
bun scripts/cli.ts agentrun control-plane cleanup-runs --min-age-minutes 30 --limit 200 --dry-run
bun scripts/cli.ts hwlab g14 control-plane cleanup-released-pvs --lane all --limit 200 --dry-run
```
验收结论至少包含:根盘水位、`DiskPressure=False`、registry readiness/API、AgentRun `aligned=true`、HWLAB v0.2 `state=aligned`、active PipelineRun 数,以及 remaining low-risk candidates / safe-stop 决策。若目标百分比未达到但 `safeStop=true`,必须写清剩余缺口和下一类策略选择,不得把未执行的高风险清理伪装成已完成。
JD01 GC 或 Chrome/observer 压力收口还必须补充:
```bash
trans JD01 sh -- 'df -h /; df -B1 /; free -h'
trans JD01 sh -- 'ps -eo pid,rss,comm,args | awk '\''BEGIN{IGNORECASE=1} /chrome|chromium|web-probe observe/ && !/awk/ {print}'\'' || true'
bun scripts/cli.ts web-probe sentinel control-plane status --node JD01 --lane v03 --sentinel <id>
```
若本次变更涉及关闭 cadence scheduler,还应确认 GitOps objects 不再包含 quick-verify CronJob,并确认 runtime/Argo/health endpoint 仍为 ready。
## Long-Term Anti-Bloat Plan
| 措施 | 默认策略 | 预期收益 |
|---|---|---|
| Registry conservative retention | workload refs + 48h tag + 每 repo 20 tag + official GC | 高构建频率下通常是主要收益,可释放十几到几十 GiB |
| CI tag growth cap | 每个 service 对 commit tag 增长设置上限并进入 GC plan | 防止 registry 每周持续膨胀 |
| Tekton/Pipeline retention | 完成态 PipelineRun/TaskRun/Job 按留存期清理 | 释放少量空间,降低 API 噪声 |
| Log/journal cap | journald 上限、文件日志轮转、Docker json log truncate | 稳定防止日志膨胀,收益通常为数百 MiB 到数 GiB |
| Remote tool cache opt-in | `gc remote ... --include-tool-caches` 只清理固定 allowlist 的 npm/npx/Bun 可重建缓存 | 在不触碰运行面状态的前提下释放数百 MiB 级边界空间 |
| VS Code CachedExtensionVSIXs retention | 只清理可重建 extension VSIX 下载缓存,不触碰已安装扩展/server/user data | 防止远程 VS Code 扩展升级缓存长期堆积,收益通常为数百 MiB |
| Core dump limits | 限制 dump 大小或按 allowlist 删除实际分配块 | 防止 crash dump 污染观测;sparse dump 不应被高估 |
| Containerd image audit | 定期只读报告 runtime image cache 构成 | 为维护窗口 prune 提供证据,不默认删除 |
| Worktree TTL audit | 报告 `.worktree` owner、branch、dirty 和 node_modules/cache 占用 | 为安全清理并行任务 scratch 提供证据 |
| Web observe artifact caps | 从 YAML 控制 samples/browser-process/network/screenshot raw artifact cap、summary+tail 保留和 dead run retention | 防止 Web sentinel 长期巡检把 JSONL 与截图产物线性堆满磁盘 |
| Observer lifecycle cap | quick-verify/sentinel 所有终态 stop observerrunner 按 YAML TTL/maxSamples 自停 | 防止 detached observer 与 Chrome process tree 在线性巡检中泄露内存 |
| Capacity trigger | 达到高水位时输出 safe-stop 决策表 | 避免为了百分比目标破坏运行面 |