一次「cargo 突然消失」之后:聊聊 GitHub Actions + 本机 self-hosted runner 的正确打开方式
最近踩了个挺典型的坑:
前一天还能正常构建,第二天终端里 cargo --version 直接变成 command not found。更离谱的是,~/.zshrc 里 PATH 配置明明还在。
当时第一反应是 shell 配置坏了,结果查下来不是。
现象看起来像 PATH,实际上是“断链”
先看几个关键信息:
PATH里有~/.cargo/bin~/.cargo/bin/cargo存在- 但
cargo是个软链:cargo -> rustup - 真正的
~/.cargo/bin/rustup文件没了
也就是说,不是找不到 cargo,是 cargo 指向的目标没了。
这种情况很容易误判成“环境变量没生效”,其实是工具链启动器被清理了。
根因:self-hosted runner 和开发环境共用 HOME,被 CI 的缓存清理逻辑误伤
我项目是 GitHub Actions 跑在本机 self-hosted runner 上(同一个用户)。
Workflow 里用了 swatinem/rust-cache@v2,默认 cache-bin: true。
这件事在 GitHub-hosted runner 上通常没问题,因为机器是一次性的;
但在长期运行的 self-hosted 上,~/.cargo/bin 是你本机常驻环境的一部分,一旦 post-cleanup 动到它,就会出现这种“本机 cargo 消失”的事故。
一句话总结:CI 没删你代码,但删了你本机共享环境里的关键二进制。
最小改动修复
我最后没把缓存全关,而是只关了 bin 缓存:
1 | - name: Cache Rust build |
这行建议至少加在所有 self-hosted 的 Rust job 里(比如 macOS / Linux)。
这样还能继续缓存 registry/git/target,构建速度保住,同时避开 ~/.cargo/bin 被清理。
如果你现在已经中招了,可以先这么做
1 | curl https://sh.rustup.rs -sSf | sh -s -- -y |
另外建议顺手检查一下:
1 | ls -l ~/.cargo/bin/cargo |
如果 cargo -> rustup 但 rustup 不存在,就是同类问题。
这类问题的通用治理建议(不只 Rust)
这次是 Rust,换成 Node/Python/Go 也可能发生。核心原则就两条:
不要让 CI 和你的日常开发环境“共用生活空间”
最好给 runner 单独用户(甚至单独机器/容器)。缓存“构建产物”和“依赖仓库”,少碰“全局工具目录”
例如~/.cargo/bin、~/.nvm、~/.pyenv这种位置,一旦被清理就是系统性故障。
再补一个实用建议:
给 self-hosted runner 加个构建前自检脚本(比如检查 cargo/node/python 是否可用),早失败比跑完才发现要省很多时间。
写在最后
self-hosted 的优势是快、可控、省钱;
代价是你得把“本机”当“生产环境”来管理。
这次问题本身不复杂,但很有代表性:
不是代码错了,是运行边界没隔离好。
如果你也在用 GitHub Actions + self-hosted,建议现在就看一眼你的 workflow:
缓存到底是在加速构建,还是在悄悄改你的机器状态。