fix(deploy): /tmp 占满把部署自己卡死了 —— 收构建暂存 + 构建带 -trimpath + 判据 ⑤

起因是用户让「清理一下」那批带仓库路径的残留。照着清理策略走时撞上更大的事实:
本机 /tmp 是 9.8G 的 tmpfs,**已 100% 满、可用 0 字节**,我自己的 `go build` 当场
ENOSPC 失败 —— 而部署的第一步就是构建。

## 1 谁把 /tmp 占满的(agentmail 自己的那份)

`redeploy-gateway.sh` 把网关构建到 /tmp 再 install 过去(为了原子替换),**用完没人删**:
每次部署留一个 24MB,实测 7 份 / 162MB。加上电子打包的中间物(squashfs-root 283MB、
pkgcheck/deb 291MB)、go-build-agentmail 缓存 172MB、4 个孤儿 go-build 工作目录 50MB
—— agentmail 名下约 960MB。另有别的产品的 /tmp/gocache 4.6G(TrueAgent 的
rebuild-plugins.sh 里 `export GOCACHE=/tmp/gocache`),不是本项目的,没动。

- prune-deploy-artifacts.sh 新增一类「构建暂存」,窗口 KEEP_BUILD_STAGES=1
  (正常路径下部署脚本自己会收,留下的只可能是失败那次,正好留现场)。
  自检 +1 项、变异验证过(把删除改成永不删 → 恰好那一项红)。
- 本次实际收:删除 8 项 / 释放 164MB(另加手动清 623MB 不可再生的中间物)。
- redeploy-gateway.sh 成功分支上收掉 $STAGE;失败/回滚分支**不删**(要留现场)。

## 2 残留里还藏着两处「旧真相」

- /etc/systemd/system/zcode.service.bak-20260912-145744(+ 同一次改动的
  zcode.service.d/10-dbus.conf.bak-…)里躺着 /home/program/agentmail/deploy/
  service-failure-notify.mjs —— 就是我上一封报「/etc/systemd 引用仓库 = 0 个文件」时
  **判据自己划掉了的那一类**(walk 里 `!name.includes('.bak')`)。已删(在线单元与
  deploy/systemd/ 逐字节一致,sha256 核对过),另外 4 个是别的产品的,没动。
- 判据 ① 因此放宽到含 .bak,并补了坏样本(.bak 里引用仓库路径必须判红)。
  上一封那句「0 个文件」的边界现在写进判据里了 —— 边界不说出口,就等于报了个假的 0。

## 3 -trimpath:标准目录部署只做了一半

Go 默认把源文件绝对路径编进二进制。对照实验(同一份源码、同一个 go,只差标志):
带 -trimpath 0 处,不带 57 处 —— 而 19:05 那次部署产出的
/opt/agentmail/agentmail-gateway 里就有 57 处 /home/program/agentmail/…。
依赖确实没了,但**源仓库位置还印在产物上**。两个构建点都加上 -trimpath,
并新增判据 ⑤(已安装二进制不得含源码路径,两侧样本都验)。

判据 ⑤ 现在**是红的**,这是存量产物的实情:磁盘上那份要等下一次
redeploy-gateway.sh 才会被换掉。我没替它单独重启网关 —— 会掐断正在跑的会话。

(工作区是多会话共用的,本次只 add 了上面这 4 个 deploy/ 文件。)
This commit is contained in:
2026-09-14 20:06:19 +08:00
parent 6b1cca0fe4
commit 2d936893f5
4 changed files with 100 additions and 14 deletions

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
# 清理部署残留:旧网关二进制、旧插件快照、旧数据库/附件备份、/tmp 里的部署前备份。
# 清理部署残留:旧网关二进制、旧插件快照、旧数据库/附件备份、/tmp 里的构建暂存与部署前备份。
#
# # 为什么要脚本而不是手敲 rm
#
@ -25,7 +25,7 @@
# bash deploy/prune-deploy-artifacts.sh # 干跑,只报告
# bash deploy/prune-deploy-artifacts.sh --apply # 真删
# bash deploy/prune-deploy-artifacts.sh --self-check # 自检:坏样本必须红、干净样本必须绿
# KEEP_GATEWAY=2 KEEP_SNAPSHOTS=2 bash ... --apply # 调保留窗口
# KEEP_GATEWAY=2 KEEP_SNAPSHOTS=2 KEEP_BUILD_STAGES=0 bash ... --apply # 调保留窗口
set -uo pipefail
ROOT="${AGENTMAIL_ROOT:-/opt/agentmail}"
@ -33,6 +33,7 @@ KEEP_GATEWAY="${KEEP_GATEWAY:-3}"
KEEP_SNAPSHOTS="${KEEP_SNAPSHOTS:-3}"
KEEP_DB_BACKUPS="${KEEP_DB_BACKUPS:-1}"
KEEP_TMP_DB="${KEEP_TMP_DB:-2}"
KEEP_BUILD_STAGES="${KEEP_BUILD_STAGES:-1}"
TMPD="${PRUNE_TMP_DIR:-/tmp}"
APPLY=0
[ "${1:-}" = "--apply" ] && APPLY=1
@ -117,6 +118,8 @@ if [ "${1:-}" = "--self-check" ]; then
for i in 1 2 3; do
: > "$t/tmp/agentmail-pre-deploy-2026010$i-000000.db"
touch -d "2026-01-0$i 00:00:00" "$t/tmp/agentmail-pre-deploy-2026010$i-000000.db"
: > "$t/tmp/agentmail-gateway-build-2026010$i-000000"
touch -d "2026-01-0$i 00:00:00" "$t/tmp/agentmail-gateway-build-2026010$i-000000"
done
echo "$t"
}
@ -131,7 +134,7 @@ if [ "${1:-}" = "--self-check" ]; then
"$TMPD"/am-prune-selftest-*) ;;
*) echo " [FATAL] 自检根目录不在临时区:$t —— 拒跑" >&2; exit 1;;
esac
AGENTMAIL_ROOT="$t" PRUNE_TMP_DIR="$t/tmp" KEEP_GATEWAY=2 KEEP_SNAPSHOTS=2 KEEP_DB_BACKUPS=1 KEEP_TMP_DB=1 \
AGENTMAIL_ROOT="$t" PRUNE_TMP_DIR="$t/tmp" KEEP_GATEWAY=2 KEEP_SNAPSHOTS=2 KEEP_DB_BACKUPS=1 KEEP_TMP_DB=1 KEEP_BUILD_STAGES=1 \
bash "$0" $mode
}
@ -168,6 +171,8 @@ if [ "${1:-}" = "--self-check" ]; then
"$([ ! -e "$T/backups/agentmail-20251201-000000.db" ] && [ ! -e "$T/backups/attachments-20251201-000000.tar.gz" ] && [ -e "$T/data/agentmail.db.bak-20260105-000000" ] && echo 1 || echo 0)"
ck "干净样本:/tmp 备份只留窗口内那 1 份" \
"$([ -e "$T/tmp/agentmail-pre-deploy-20260103-000000.db" ] && [ ! -e "$T/tmp/agentmail-pre-deploy-20260101-000000.db" ] && echo 1 || echo 0)"
ck "干净样本:/tmp 构建暂存只留窗口内那 1 份" \
"$([ -e "$T/tmp/agentmail-gateway-build-20260103-000000" ] && [ ! -e "$T/tmp/agentmail-gateway-build-20260101-000000" ] && echo 1 || echo 0)"
# 坏样本:超窗口的那个备份是指向在线库的符号链接 —— 必须**拒跑**,而不是"删了才发现"
B="$(mktree)"; rm -f "$B/backups/agentmail-20251201-000000.db"
@ -261,6 +266,22 @@ else
done
fi
# 构建暂存:`redeploy-gateway.sh` 先把网关构建到 `$TMPD` 再 `install` 过去(为了原子
# 替换),**用完没有任何人删过它** —— 每次部署留下一个 24MB。2026-09-14 实测 7 份
# / 162MB。这不是"几百 MB 而已":本机 `$TMPD` 是 9.8G 的 tmpfs,当时已被占满
# (可用 0 字节),连 `go build` 都进不去 —— 而部署的第一步就是构建。
#
# 窗口留 1 份而不是 0:正常路径下部署脚本自己会收(见 redeploy-gateway.sh 末尾),
# 留下的只可能是**失败**的那次;失败时那一份正好用来事后查,删了就没现场了。
echo "==> $TMPD 的构建暂存(保留最新 $KEEP_BUILD_STAGES 份)"
mapfile -t stages < <(ls -1t "$TMPD"/agentmail-gateway-build-* 2>/dev/null)
for i in "${!stages[@]}"; do
[ "$i" -lt "$KEEP_BUILD_STAGES" ] && { report " 保留" "${stages[$i]}"; continue; }
# 二进制可能正被某个部署进程 install 到一半 —— 与快照同理,用过的路径一律先问一句。
if in_use "${stages[$i]}"; then report " ★跳过(正在被使用)" "${stages[$i]}"; skipped=$((skipped+1)); continue; fi
del "${stages[$i]}"
done
echo "==> $TMPD 的部署前数据库备份(保留最新 $KEEP_TMP_DB 份)"
mapfile -t dbs < <(ls -1t "$TMPD"/agentmail-pre-deploy-*.db 2>/dev/null)
for i in "${!dbs[@]}"; do