文档调试指南
本页目录

指南 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 之外。