指南 08
调试指南
定位并解决本地评估栈的常见问题。
本指南收集在本机运行 Mega2 评估栈时遇到的问题,每个问题按「现象 → 确认原因 → 原因 → 解决」组织。请先用文中的命令确认原因,再修改配置。评估栈的启动方式见快速开始。
1. 从哪里开始排查
先确认哪个服务没有起来,再看它的日志:
COMPOSE=macos-orbstack-mega2-compose.yml # macOS + OrbStack
COMPOSE=linux-mega2-compose.yml # Linux Docker
docker compose -f $COMPOSE ps -a # 各服务的状态与退出码
docker compose -f $COMPOSE logs --tail 100 mega2 # mega2 最近的日志
mega2 启动时会执行数据库迁移、初始化空的 Monorepo,并把初始 Git 对象写入 RustFS。任何一步失败,进程都会以退出码 1 结束,原因写在日志最后几行。Monorepo 初始化在一个数据库事务中完成,失败时整体回滚;排除原因后重新运行 docker compose -f $COMPOSE up -d --wait 即可,不需要 down -v。
2. macOS + OrbStack:开启 Clash Verge 虚拟网卡模式后 mega2 启动失败
2.1. 现象
- 运行
docker compose -f macos-orbstack-mega2-compose.yml up -d --wait后,postgres、redis、rustfs 和 rustfs-init 都是 healthy,只有 mega2 在启动几秒后退出(Exited (1)),重复up结果相同。 - mega2 日志反复重试对象存储请求,最后因写入 Git 对象失败而退出:
INFO object_store::client::retry: Encountered transport error of kind Request, backing off for 0.14486904 seconds, retry 3 of 10: HTTP error: error sending request
...
Other error: object_storage::put_many failed for key=afff6026cbd0c96177c593ff71f92a563f354c3b namespace=git error_chain:
[0] ObjectStore { message: "Generic S3 error: Error performing PUT http://mega2-rustfs.orb.local:9000/mega2/git/af/ff/60/26cbd0c96177c593ff71f92a563f354c3b in 3.44620306s, after 10 retries, max_retries: 10, retry_timeout: 180s - HTTP error: error sending request", not_found: false }
- 宿主机运行着 Clash Verge,并开启了「虚拟网卡模式」(TUN)。
2.2. 确认原因
分别在宿主机和容器内解析 RustFS 的域名:
dscacheutil -q host -a name mega2-rustfs.orb.local # 宿主机
docker exec mega2-rustfs getent hosts mega2-rustfs.orb.local # 容器内
正常时得到的是 OrbStack 分配的地址(例如 192.168.138.5)。如果结果落在 198.18.0.0/15 网段(例如 198.18.0.16),或是代理配置的 IPv6 fake-ip 地址(例如 2001:2::5),说明这个域名被代理软件的 fake-ip DNS 接管了。可以进一步确认:
ifconfig | grep 'inet 198.18.' # Clash 的 TUN 网卡,例如 inet 198.18.0.1
dns-sd -G v4v6 mega2-rustfs.orb.local # 观察几秒后按 Ctrl-C 结束
dns-sd 会列出两组结果:IF 为 0 的一组是代理返回的 fake-ip,几乎立即出现;另一组来自 OrbStack 的网桥(IF 不为 0),晚约 100 ms 才到,这才是真实地址。用真实地址直接访问 RustFS,返回 200 就说明 RustFS 本身正常,问题只出在域名解析:
# 把 192.168.138.5 换成 dns-sd 显示的真实地址
curl -s -o /dev/null -w '%{http_code}\n' \
--resolve mega2-rustfs.orb.local:9000:192.168.138.5 \
http://mega2-rustfs.orb.local:9000/health
2.3. 原因
- macOS 版 Compose 文件(
macos-orbstack-mega2-compose.yml)让 mega2 通过http://mega2-rustfs.orb.local:9000访问 RustFS:这个名称在宿主机和容器内都能解析,artifact 预签名 URL 因此也能在宿主机上直接下载。其它服务之间使用 Compose 服务名(postgres、redis、rustfs),由 Docker 内置 DNS 直接解析,不受影响,所以只有 mega2 失败。 - macOS 上的
*.orb.local由 OrbStack 通过 mDNS 应答。Clash Verge 开启虚拟网卡模式且 DNS 为 fake-ip 模式时,会接管系统的 DNS 查询,立即为这个名称返回 fake-ip,抢在 OrbStack 的真实结果之前。容器内的 DNS 查询最终也交给宿主机解析,得到同样的 fake-ip。 - 发往 fake-ip 的连接进入代理内核,而代理无法把它送到 OrbStack 的容器,连接随即被关闭(用 curl 访问会看到
Empty reply from server)。mega2 初始化 Monorepo 时写入 RustFS 失败,重试 10 次后退出。 - Clash Verge 默认的
fake-ip-filter虽然包含*.local,但 mihomo 的域名通配符*只匹配一级:它匹配foo.local,不匹配mega2-rustfs.orb.local。
2.4. 解决
把 +.orb.local 加入 fake-ip-filter。+ 匹配任意层级的子域,Clash 不再为 *.orb.local 分配 fake-ip,系统会用上 OrbStack 返回的真实地址。
Clash Verge Rev 推荐用全局扩展脚本追加这一项:在「订阅」页面右键「全局扩展脚本」,选择「编辑文件」,写入下面的脚本后保存。扩展脚本在「DNS 覆写」之后执行,无论是否开启 DNS 覆写都会生效,并保留原有的过滤项:
function main(config, profileName) {
config.dns = config.dns || {};
const filter = config.dns["fake-ip-filter"] || [];
if (!filter.includes("+.orb.local")) filter.push("+.orb.local");
config.dns["fake-ip-filter"] = filter;
return config;
}
如果全局扩展脚本里已有 main 函数,把其中修改 config.dns 的几行合并进去即可。不要改用「全局扩展覆写配置」(YAML)写 dns.fake-ip-filter:从 v2.5.5 起,扩展配置写出的 dns 字段会整体替换原值,默认的过滤项会全部丢失,详见 Clash Verge Rev 文档。直接编辑 mihomo 配置文件时,在已有的 dns.fake-ip-filter 列表中加入同一项:
dns:
fake-ip-filter:
- '+.orb.local'
保存后清除 macOS 的 DNS 缓存,确认解析结果,再重新启动:
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
dscacheutil -q host -a name mega2-rustfs.orb.local # 只剩 OrbStack 的地址
docker exec mega2-rustfs getent hosts mega2-rustfs.orb.local # 容器内也一样
docker compose -f macos-orbstack-mega2-compose.yml up -d --wait
临时办法是关闭 Clash Verge 的虚拟网卡模式,只使用系统代理:清除 DNS 缓存后解析即可恢复,可以先把评估栈启动起来。但 mega2 运行时会持续访问 RustFS,重新开启虚拟网卡模式后,推送、LFS 等需要读写对象的操作仍会失败,长期还是应该使用上面的过滤配置。
其它基于 mihomo 的客户端(例如 Mihomo Party、FlClash)同样在 dns.fake-ip-filter 中加入 +.orb.local;Surge、sing-box 等使用 fake-ip 的工具,也需要把 *.orb.local 及其多级子域排除在 fake-ip 之外。