一次网络问题排查
内容提要
文章讲述了在搭建Jenkins时遇到的问题,通过收集信息和抓包分析发现是由于MTU太大导致的丢包问题。解决办法是通过iptables修改TCP握手包中的MSS值,从而解决了在Docker容器中访问HTTPS服务的问题。
延伸解读
MTU不匹配为何导致HTTPS超时
文章指出,宿主机MTU为1450,而Docker容器内默认MTU为1500,导致容器发出的数据包可能超过底层网络实际支持的1500字节上限。HTTP响应通常较小,不易触发问题;而HTTPS在TLS握手阶段需要交换证书等较大数据,容易产生超限包。这些超限包在中间设备被丢弃,且发送方无法收到ICMP通知,表现为443端口无响应,最终引发SocketTimeoutException。
MSS Clamping:一种有效的临时解决方案
作者通过iptables的TCPMSS目标,在FORWARD链上修改TCP握手包中的MSS值为1410(即1450减去40字节的IP和TCP头),使容器协商出更小的报文段,避免超过路径MTU。这种方法无需修改Docker或宿主机的MTU配置,即可解决因MTU不一致导致的HTTPS访问超时。但需注意,该规则仅对经过FORWARD链的流量生效,且可能影响其他连接。
排查思路:从现象到根因的推理
文章展示了系统的排查过程:先通过tcpdump定位到访问443端口卡住,再抓取DNS包找到域名,然后对比容器与宿主机的网络行为,发现HTTP正常而HTTPS超时。结合MTU差异,推断出大包被丢弃。这种从现象出发,逐步排除网络层、传输层问题,最终聚焦到MTU/MSS的推理方法,对类似网络问题有借鉴意义。
Q&A
Jenkins 在 Docker 中报 java.net.SocketTimeoutException: Read timed out 错误,可能是什么原因?
可能是由于 Docker 容器内 MTU 设置过大(默认 1500),而宿主机 MTU 为 1450,导致 TCP 握手时 MSS 协商不当,使得 HTTPS 数据包超过路径 MTU 被丢弃,从而引发超时。
如何诊断 Docker 容器内 HTTPS 访问超时的问题?
可以使用 tcpdump 抓包分析:先抓 DNS 包找到目标域名,再抓 TCP 包观察连接建立后数据交换是否卡住。同时对比容器和宿主机的网络配置,检查 MTU 差异。
为什么容器内可以访问 HTTP 但 HTTPS 会超时?
因为 HTTPS 在 TLS 握手过程中需要交换证书等大量信息,数据包较大,容易超过 MTU 导致丢包;而 HTTP 响应通常较小,不易触发 MTU 问题。
Docker 容器内 MTU 和宿主机 MTU 不一致会导致什么问题?
如果容器内 MTU 大于宿主机 MTU,容器发出的数据包可能超过路径 MTU,导致中间设备丢弃,表现为连接超时或传输缓慢。
如何通过 iptables 修改 MSS 值来解决 Docker 容器 HTTPS 访问问题?
可以使用命令:iptables -I FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1410,将 TCP 握手包中的 MSS 强制改为 1410,从而避免 MTU 过大导致的丢包。
什么是 MSS clamping,它如何解决 MTU 问题?
MSS clamping 是通过 iptables 修改 TCP 握手包中的 MSS 值,使其小于路径 MTU,从而确保数据包不会因过大而被丢弃,解决因 MTU 不匹配导致的连接问题。