Incus 实战SWES · 技术记录

小鸡连不上网?两次真实排障实录

两次真实排障实录:Docker 把 FORWARD 设成 DROP 导致小鸡断网,用 DOCKER-USER 定向放行解决;apt 连不上 deb.debian.org,定位到 Fastly CDN 超时后换源+强制 IPv4。

脚本写得再漂亮,真机上总有意外。这篇记录两次真实发生的排障:一次是 Docker 把小鸡的出站网络掐了,一次是生产机 apt 连不上 Debian 官方源。两次都写出完整的排查思路链——现象 → 假设 → 验证 → 根因 → 修复 → 沉淀。

排障方法论:分层、二分、一次只动一个变量

两次排障用的是同一套方法,值得抽象出来:

  1. 分层定位:网络问题先分清是容器层、宿主机层还是公网层。容器能 ping 通网关 → 问题在宿主机之外;DNS 能解析但 TCP 不通 → 问题在传输层,不是 DNS。
  2. 二分验证:每次只验证一个假设。怀疑 DNS?getent 一测就知道,不用连带换源一起试。
  3. 一次只动一个变量:修 FORWARD 时不动 Docker 原有规则,换 apt 源时不动网络配置。这样如果修坏了,知道是谁的锅;修好了,知道是谁的功。

排障一:Docker 把 FORWARD 设成 DROP,小鸡出不了网

现象:小鸡里 apt-get update 卡死,ping 1.1.1.1 不通。但宿主机网络一切正常。

排查链:

  1. 先分层:容器里 ip route 有默认网关 → 网关 ping 得通 → 说明容器到宿主机的链路没问题,问题在宿主机往外的转发。
  2. 看宿主机转发:iptables -L FORWARD -n -v,发现 FORWARD 链默认策略是 DROP,而且链里全是 Docker 的规则——这是 Docker 启动时的标准动作:它把 FORWARD 默认策略改成 DROP,再用自己的规则精确放行容器流量。
  3. 根因:Incus 的 incusbr0 网桥走的是宿主机内核转发,不在 Docker 的放行名单里。ipv4.nat=true 配了 NAT 规则也没用,因为包在 FORWARD 链就被 DROP 了,根本到不了 POSTROUTING。

修复:不动 Docker 的任何规则——动了下次 Docker 重启又会被覆盖,还可能影响宿主机上跑的 Halo/XBoard 容器。Docker 预留了 DOCKER-USER 链,优先级在 Docker 自己的规则之前,专门给用户自定义。加两条最小放行规则:

iptables -I DOCKER-USER 1 -i incusbr0 -o "$WAN" -s "$SUBNET" -j ACCEPT
iptables -I DOCKER-USER 1 -i "$WAN" -o incusbr0 -d "$SUBNET" \
  -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

第一条放行小鸡出站,第二条只放行回包(conntrack 跟踪已建立连接),公网不能主动连进内网——最小权限。

沉淀:写成 /usr/local/sbin/incus-docker-forward-fix.sh,WAN 网卡和子网都是自动探测的(读默认路由、读 incus network get incusbr0 ipv4.address),换机器不用改。再配 systemd oneshot 服务,After=docker.service incus.service,开机自动补规则。注意:如果单独重启 Docker,规则会丢,需要手动重跑一次脚本——脚本注释里写明了,不藏着。

修复后怎么确认:iptables -L DOCKER-USER -n -v 看计数器——小鸡里跑个 ping 1.1.1.1,对应规则的 packets 数字往上涨,就证明流量确实走了这条放行规则,而不是"好像通了"。排障里"证明修好了"和"修好了"同样重要,计数器就是证据。

脚本的防御性:forward-fix 开头有三行守卫——没装 docker 直接退出、没装 iptables 直接退出、没有 DOCKER-USER 链直接退出。这意味着在没有 Docker 的机器上跑部署脚本,修复步骤静默跳过,不会报错、不会留下半截规则。一个脚本要能在"有 Docker"和"无 Docker"的机器上都跑通,靠的就是这种"环境不对就优雅退出"的守卫。

为什么不用更粗暴的办法:有人图省事直接 iptables -P FORWARD ACCEPT,把整条 FORWARD 链放开。这等于把 Docker 精心设计的隔离拆了——宿主机上还跑着 Halo、XBoard 等 Docker 容器,全暴露了。DOCKER-USER 定向放行只放 incusbr0 子网的出站和回包,影响面最小。这就是"最小权限"原则:能精确放行,就不全局放开。

排障二:apt 连不上 deb.debian.org,真凶是 Fastly

现象(2026-10-19,生产机):apt-get update 报 deb.debian.org 连接超时。

排查链:

  1. 先排除 DNS:getent ahostsv4 deb.debian.org 能解析出 151.101.x.x —— DNS 没问题。
  2. 测连通性:curl 直连 151.101.x.x:80 超时;ping6 显示 IPv6 unreachable。这段 IP 是 Fastly CDN,Debian 官方源的 CDN 供应商。
  3. 根因:这台机器所在的网络到 Fastly CDN 全超时(IPv4 超时、IPv6 不可达),DNS 正常。这是该网络的线路特性,不是配置问题——换什么 apt 参数都绕不过去,只能换不走 Fastly 的源。

修复(已在宿主机验证生效):

# sources.list 换成 ftp.us.debian.org
sed -i 's|deb.debian.org|ftp.us.debian.org|g' /etc/apt/sources.list
# 强制 IPv4,避开 IPv6 的坑
echo 'Acquire::ForceIPv4 "true";' > /etc/apt/apt.conf.d/99force-ipv4

ftp.us.debian.org 是 Debian 官方的 DNS 轮询源,不经过 Fastly。ForceIPv4 是因为这台机器的 IPv6 根本不通,apt 默认会先试 IPv6,白白超时。

怎么认出 151.101.x.x 是 Fastly:deb.debian.org 本身是个 CDN 入口域名,解析出来 151.101.0.0/16 段——这是 Fastly 的 ASN 段。看到 apt 卡在连接 151.101.x.x:80,而其他网站正常,第一反应就该是"CDN 线路问题"而不是"我的配置问题"。这个判断省了大量弯路。

换源后怎么确认真的好了:apt-get update 一次跑通不算,还要看后续。我的验证方法是:宿主机换源后连续跑三天日常 apt 操作无超时,才算"验证生效"写进结论。容器侧因为当时没条件逐台确认,所以文章里如实标"未确认"——验证标准不能双标,宿主机什么标准,容器就什么标准。

沉淀与边界:容器里同样中招——Debian 12 容器默认源也是 deb.debian.org。批量修复的思路是逐台 incus exec 进去做三件事:

for n in vps1 vps2 vps3; do
  incus exec "$n" -- sed -i 's|deb.debian.org|ftp.us.debian.org|g' /etc/apt/sources.list
  incus exec "$n" -- bash -c 'echo "Acquire::ForceIPv4 \"true\";" > /etc/apt/apt.conf.d/99force-ipv4'
  incus exec "$n" -- apt-get update
done

但这是建议方案,容器侧的批量修复结果当时未确认,如实标注。另外 reinstall_incus_vps_6_0_6_fixed.sh 重装脚本里,apt 步骤直接带了 -o Acquire::ForceIPv4=true 参数,把这次排障的经验写进了流程。

两次排障的共同点

  • 都是分层排查:先确定哪一层通、哪一层不通,再往下钻,而不是一上来就改配置碰运气。
  • 都沉淀进了脚本:forward-fix 服务、ForceIPv4 参数。排障的终点不是"修好了",是"下次不会再被同一个问题绊倒"。

附:这次用到的排障工具箱

两次排障翻来覆去用的就这几个命令,值得收进你的工具箱:

iptables -L FORWARD -n -v          # 看 FORWARD 链:谁在 DROP 谁在 ACCEPT
getent ahostsv4 deb.debian.org     # 只查 A 记录,确认 DNS 本身没问题
ss -lnt | grep 2201                # 宿主机端口到底在没在监听
timeout 8 bash -c 'echo >/dev/tcp/1.1.1.1/443'   # 不装 nc 也能测 TCP 通断
incus network get incusbr0 ipv4.address          # 查网桥网段,排障先看拓扑

/dev/tcp 是 bash 内建的 TCP 客户端,不用装任何包,在最小化容器里特别好用——两次排障里验证"外网通不通"全靠它。顺带一提,timeout 8 包一层是防止目标完全黑洞时 bash 一直挂起,排障命令也要有超时意识。工具箱不在多,在顺手——这五个命令解决过我 90% 的网络问题。

下一篇:小鸡开出来只是开始——端口管理、一键重装、批量监控三件套。

感谢阅读 · 保持好奇,认真记录。浏览更多文章 ↗