<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>网络排障 on 寻 Mi 处</title>
        <link>https://blog.mibase.top/tags/%E7%BD%91%E7%BB%9C%E6%8E%92%E9%9A%9C/</link>
        <description>Recent content in 网络排障 on 寻 Mi 处</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh</language>
        <lastBuildDate>Tue, 24 Mar 2026 06:08:00 +0800</lastBuildDate><atom:link href="https://blog.mibase.top/tags/%E7%BD%91%E7%BB%9C%E6%8E%92%E9%9A%9C/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>一台工控机连不上外网，我用抓包找到了真正的原因</title>
            <link>https://blog.mibase.top/p/%E4%B8%80%E5%8F%B0%E5%B7%A5%E6%8E%A7%E6%9C%BA%E8%BF%9E%E4%B8%8D%E4%B8%8A%E5%A4%96%E7%BD%91%E6%88%91%E7%94%A8%E6%8A%93%E5%8C%85%E6%89%BE%E5%88%B0%E4%BA%86%E7%9C%9F%E6%AD%A3%E7%9A%84%E5%8E%9F%E5%9B%A0/</link>
            <pubDate>Tue, 24 Mar 2026 06:08:00 +0800</pubDate>
            <guid>https://blog.mibase.top/p/%E4%B8%80%E5%8F%B0%E5%B7%A5%E6%8E%A7%E6%9C%BA%E8%BF%9E%E4%B8%8D%E4%B8%8A%E5%A4%96%E7%BD%91%E6%88%91%E7%94%A8%E6%8A%93%E5%8C%85%E6%89%BE%E5%88%B0%E4%BA%86%E7%9C%9F%E6%AD%A3%E7%9A%84%E5%8E%9F%E5%9B%A0/</guid>
            <description>&lt;img src=&#34;https://blog.mibase.top/p/%E4%B8%80%E5%8F%B0%E5%B7%A5%E6%8E%A7%E6%9C%BA%E8%BF%9E%E4%B8%8D%E4%B8%8A%E5%A4%96%E7%BD%91%E6%88%91%E7%94%A8%E6%8A%93%E5%8C%85%E6%89%BE%E5%88%B0%E4%BA%86%E7%9C%9F%E6%AD%A3%E7%9A%84%E5%8E%9F%E5%9B%A0/cover.jpg&#34; alt=&#34;Featured image of post 一台工控机连不上外网，我用抓包找到了真正的原因&#34; /&gt;&lt;p&gt;机房里有一台旧工控机，装的是 Debian，跑着一个小采集程序。&lt;/p&gt;&#xA;&lt;p&gt;它需要把采集到的数据发到公网的一台服务器上。局域网内一切正常，能 ping 通网关，能访问内网的其他机器。但一访问公网就出问题。&lt;/p&gt;&#xA;&lt;p&gt;现象很奇怪。&lt;code&gt;ping 8.8.8.8&lt;/code&gt; 能通，延迟正常。但 &lt;code&gt;curl https://api.example.com&lt;/code&gt; 就卡住，一直转圈，最后超时。&lt;/p&gt;&#xA;&lt;p&gt;能 ping 通说明网络层是好的。curl 不行说明问题在更上层。这种&amp;quot;一半通一半不通&amp;quot;的情况，光看配置文件是找不出来的，得抓包。&lt;/p&gt;&#xA;&lt;h2 id=&#34;先做基本检查&#34;&gt;先做基本检查&#xA;&lt;/h2&gt;&lt;p&gt;动手抓包之前，先把能排除的排掉。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ip addr show&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ip route show&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat /etc/resolv.conf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;IP 是 &lt;code&gt;192.168.10.55/24&lt;/code&gt;，网关 &lt;code&gt;192.168.10.1&lt;/code&gt;，路由表里有默认路由指向网关。DNS 是 &lt;code&gt;223.5.5.5&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;再看 DNS 能不能解析：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dig api.example.com&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;能解析出 IP。那问题不在 DNS。&lt;/p&gt;&#xA;&lt;p&gt;试一下 TCP 能不能连：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nc -zv api.example.com &lt;span class=&#34;m&#34;&gt;443&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;卡住，最后超时。&lt;/p&gt;&#xA;&lt;p&gt;到这一步基本确定，是 TCP 握手的问题。要么是 SYN 发出去了没回来，要么是回来了但被丢了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;抓包&#34;&gt;抓包&#xA;&lt;/h2&gt;&lt;p&gt;工控机上装 tcpdump：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install tcpdump&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;开始抓：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo tcpdump -i eth0 -n -s &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; -w /tmp/capture.pcap &lt;span class=&#34;s1&#34;&gt;&amp;#39;host api.example.com&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;参数说明。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;-i eth0&lt;/code&gt; 指定网卡。用 &lt;code&gt;ip addr&lt;/code&gt; 确认是哪个。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;-n&lt;/code&gt; 不做 DNS 反解，避免抓包的时候卡在解析上。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;-s 0&lt;/code&gt; 是抓完整的包，不截断。默认只抓 262 字节，分析 TLS 的时候不够用。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;-w&lt;/code&gt; 写到文件，方便后面用 Wireshark 分析。&lt;/p&gt;&#xA;&lt;p&gt;最后那个 &lt;code&gt;&#39;host api.example.com&#39;&lt;/code&gt; 是过滤表达式。不加的话会抓到所有流量，文件很快变大。&lt;/p&gt;&#xA;&lt;p&gt;抓的同时在另一个窗口跑 &lt;code&gt;nc -zv api.example.com 443&lt;/code&gt;，然后 Ctrl+C 停掉抓包。&lt;/p&gt;&#xA;&lt;h2 id=&#34;用-wireshark-打开&#34;&gt;用 Wireshark 打开&#xA;&lt;/h2&gt;&lt;p&gt;把 pcap 文件下载到本地，用 Wireshark 打开。&lt;/p&gt;&#xA;&lt;p&gt;我一般先用这个过滤器：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tcp.flags.syn == 1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;只看 SYN 包。能看到发了几个 SYN，有没有收到 SYN-ACK。&lt;/p&gt;&#xA;&lt;p&gt;结果是这样：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;No.  Time      Source          Destination     Info&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1    0.000000  192.168.10.55   203.0.113.5     443 → 52134 [SYN] Seq=0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2    1.002341  192.168.10.55   203.0.113.5     443 → 52134 [SYN] Seq=0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3    2.004891  192.168.10.55   203.0.113.5     443 → 52134 [SYN] Seq=0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;三个 SYN，间隔一秒，没有收到任何 SYN-ACK。这是典型的&amp;quot;对面没收到&amp;quot;或者&amp;quot;对面收到了但回复回不来&amp;quot;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;换一个角度验证&#34;&gt;换一个角度验证&#xA;&lt;/h2&gt;&lt;p&gt;既然 ping 能通，说明 ICMP 是双向的。那为什么 TCP 不行。&lt;/p&gt;&#xA;&lt;p&gt;用 &lt;code&gt;traceroute&lt;/code&gt; 看看路径：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;traceroute -T -p &lt;span class=&#34;m&#34;&gt;443&lt;/span&gt; api.example.com&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-T&lt;/code&gt; 是用 TCP SYN 探测，&lt;code&gt;-p 443&lt;/code&gt; 指定端口。普通的 traceroute 用 UDP 或者 ICMP，可能和实际情况不一样。&lt;/p&gt;&#xA;&lt;p&gt;结果：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 1  192.168.10.1      0.5 ms&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 2  100.64.0.1        3.2 ms&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 3  10.0.0.1           5.8 ms&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 4  * * *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 5  * * *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;到第三跳之后就全是星号。但 ping 是通的，这就矛盾了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;想到-mtu&#34;&gt;想到 MTU&#xA;&lt;/h2&gt;&lt;p&gt;这里我突然想起一个可能性。&lt;/p&gt;&#xA;&lt;p&gt;ping 的包很小，默认 56 字节，加上头部也就 84 字节。而 TLS 握手的时候，客户端会发一个 ClientHello，这个包通常有一千多字节。&lt;/p&gt;&#xA;&lt;p&gt;如果路径上的 MTU 有问题，小包能过，大包过不去。&lt;/p&gt;&#xA;&lt;p&gt;验证一下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ping -M &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; -s &lt;span class=&#34;m&#34;&gt;1472&lt;/span&gt; 8.8.8.8&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-M do&lt;/code&gt; 是禁止分片，&lt;code&gt;-s 1472&lt;/code&gt; 是数据部分 1472 字节，加上 ICMP 头部 8 字节和 IP 头部 20 字节，正好是 1500。&lt;/p&gt;&#xA;&lt;p&gt;如果通，说明 MTU 是 1500。&lt;/p&gt;&#xA;&lt;p&gt;如果不通，报 &lt;code&gt;Frag needed and DF set&lt;/code&gt;，说明路径上的 MTU 小于 1500。&lt;/p&gt;&#xA;&lt;p&gt;我测出来是不通，一直降到了 &lt;code&gt;-s 1400&lt;/code&gt; 才通。也就是说实际的路径 MTU 在 1428 左右。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么会这样&#34;&gt;为什么会这样&#xA;&lt;/h2&gt;&lt;p&gt;工控机所在的那个网段，中间经过了一个 VPN 隧道。VPN 封装会增加额外的头部，导致实际可用的 MTU 变小。&lt;/p&gt;&#xA;&lt;p&gt;正常情况这不该有问题。TCP 有路径 MTU 发现机制（PMTUD），它会探测路径上最小的 MTU，然后按那个大小发包。&lt;/p&gt;&#xA;&lt;p&gt;但 PMTUD 依赖 ICMP 的 &amp;ldquo;Fragmentation Needed&amp;rdquo; 消息。如果中间有防火墙把这类 ICMP 消息拦了，PMTUD 就失效了。&lt;/p&gt;&#xA;&lt;p&gt;失效之后，TCP 会用默认的 MSS 发大包，包被丢弃，但发送方不知道，就一直重传，最后超时。&lt;/p&gt;&#xA;&lt;p&gt;这就能解释为什么 ping 通但 TCP 不通了。ping 的包小，不受影响。&lt;/p&gt;&#xA;&lt;h2 id=&#34;确认&#34;&gt;确认&#xA;&lt;/h2&gt;&lt;p&gt;回到 Wireshark，看抓到的包里 TCP 的 MSS 值。&lt;/p&gt;&#xA;&lt;p&gt;打开一个 SYN 包，展开 TCP 层，找 Options，里面有一项 &lt;code&gt;Maximum segment size&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;我抓到的值是 1460，这是 1500 MTU 下的标准值。&lt;/p&gt;&#xA;&lt;p&gt;但实际路径 MTU 是 1428，那么 MSS 应该是 1388。&lt;/p&gt;&#xA;&lt;p&gt;所以每次发出去的数据包都超过路径 MTU，被中间设备丢弃，而且没有 ICMP 反馈回来。&lt;/p&gt;&#xA;&lt;p&gt;再看有没有重传：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tcp.analysis.retransmission&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;这个过滤器能看到所有重传的包。果然有一堆。&lt;/p&gt;&#xA;&lt;h2 id=&#34;解决&#34;&gt;解决&#xA;&lt;/h2&gt;&lt;p&gt;有两个办法。&lt;/p&gt;&#xA;&lt;p&gt;一个是在工控机上手动把 MTU 调小：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo ip link &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; dev eth0 mtu &lt;span class=&#34;m&#34;&gt;1400&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;立刻生效，但重启会丢。要持久化得写进网络配置。&lt;/p&gt;&#xA;&lt;p&gt;Debian 12 用 systemd-networkd 或者 NetworkManager，看用的是哪个。&lt;/p&gt;&#xA;&lt;p&gt;如果是 NetworkManager：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nmcli connection modify &lt;span class=&#34;s2&#34;&gt;&amp;#34;Wired connection 1&amp;#34;&lt;/span&gt; 802-3-ethernet.mtu &lt;span class=&#34;m&#34;&gt;1400&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nmcli connection up &lt;span class=&#34;s2&#34;&gt;&amp;#34;Wired connection 1&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;如果是 systemd-networkd，在 &lt;code&gt;.network&lt;/code&gt; 文件里加：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[Link]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;MTUBytes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;1400&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;另一个办法是在防火墙上放行 ICMP 的 &lt;code&gt;fragmentation-needed&lt;/code&gt; 消息。这个是治本的，因为 PMTUD 恢复之后，系统会自己找到正确的 MSS。&lt;/p&gt;&#xA;&lt;p&gt;但很多时候你控制不了中间的防火墙。所以我两个都做了，MTU 调小是兜底。&lt;/p&gt;&#xA;&lt;h2 id=&#34;关于-mss-clamping&#34;&gt;关于 MSS clamping&#xA;&lt;/h2&gt;&lt;p&gt;还有一个更精细的做法，叫 MSS clamping。它是在路由器上改 TCP 握手时的 MSS 值，让双方按更小的包来发。&lt;/p&gt;&#xA;&lt;p&gt;Linux 上：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -j TCPMSS --clamp-mss-to-pmtu&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;&lt;code&gt;--clamp-mss-to-pmtu&lt;/code&gt; 会自动按当前路径的 MTU 算。也可以用 &lt;code&gt;--set-mss 1388&lt;/code&gt; 写死。&lt;/p&gt;&#xA;&lt;p&gt;这个一般配在路由器或者 VPN 网关上，因为它需要看到所有经过的 TCP 握手。&lt;/p&gt;&#xA;&lt;p&gt;我用的是 OpenWrt 的路由器，在防火墙的自定义规则里加了这一条。加了之后，整个局域网里所有走 VPN 的设备都不会再有这个问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;抓包的一些技巧&#34;&gt;抓包的一些技巧&#xA;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;tcpdump&lt;/code&gt; 的过滤表达式很强大，用熟了能省很多时间。&lt;/p&gt;&#xA;&lt;p&gt;只看某个端口：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tcpdump -i eth0 -n &lt;span class=&#34;s1&#34;&gt;&amp;#39;port 443&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;只看某个方向：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tcpdump -i eth0 -n &lt;span class=&#34;s1&#34;&gt;&amp;#39;src host 192.168.10.55 and dst port 443&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;看 HTTP 的内容（明文才有效）：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tcpdump -i eth0 -n -A &lt;span class=&#34;s1&#34;&gt;&amp;#39;port 80&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-A&lt;/code&gt; 是以 ASCII 显示内容。看 TLS 的话只能看到加密后的乱码，但能看到握手的结构。&lt;/p&gt;&#xA;&lt;p&gt;抓包的时候加 &lt;code&gt;-c&lt;/code&gt; 限制数量，避免文件太大：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tcpdump -i eth0 -n -c &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt; -w /tmp/capture.pcap&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;还有 &lt;code&gt;-tttt&lt;/code&gt; 让时间戳带上日期，方便对照日志。&lt;/p&gt;&#xA;&lt;h2 id=&#34;wireshark-的几个好用功能&#34;&gt;Wireshark 的几个好用功能&#xA;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Statistics -&amp;gt; Flow Graph&lt;/code&gt; 能把整个 TCP 会话画成时序图，一眼就能看出谁先发了什么、哪里断了。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;Statistics -&amp;gt; Conversations&lt;/code&gt; 能看到每个会话的流量统计，找出谁在占带宽。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;Analyze -&amp;gt; Expert Information&lt;/code&gt; 会把所有异常标出来，包括重传、乱序、窗口满、连接重置。这个功能新手特别友好，不用自己一条条看。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;Follow -&amp;gt; TCP Stream&lt;/code&gt; 能把一个会话的完整内容拼出来。分析 HTTP 的时候很有用。&lt;/p&gt;&#xA;&lt;h2 id=&#34;后来&#34;&gt;后来&#xA;&lt;/h2&gt;&lt;p&gt;MTU 调成 1400 之后，curl 立刻通了。&lt;/p&gt;&#xA;&lt;p&gt;但这件事让我意识到，那台工控机所在的网段一直有这个隐患，只是之前跑的服务都是小包交互，没暴露出来。&lt;/p&gt;&#xA;&lt;p&gt;后来我在路由器上加了 MSS clamping，又把整个局域网的 MTU 统一调到了 1400。虽然理论上 1500 更好，但实际用起来，1400 能避免很多莫名其妙的问题。&lt;/p&gt;&#xA;&lt;p&gt;这个经验在后来配 Tailscale 的时候又用上了。Tailscale 的默认 MTU 是 1280，就是因为它知道自己会被封装在各种网络里，留了足够的余量。&lt;/p&gt;&#xA;&lt;h2 id=&#34;一点感受&#34;&gt;一点感受&#xA;&lt;/h2&gt;&lt;p&gt;网络问题最麻烦的地方是，它不报错。&lt;/p&gt;&#xA;&lt;p&gt;CPU 满了会有告警，磁盘满了会有告警，内存泄漏能看到曲线。但一个包被悄悄丢掉，什么都不会说。你只能看到&amp;quot;连不上&amp;quot;，然后自己去猜。&lt;/p&gt;&#xA;&lt;p&gt;抓包是唯一能让你看到真相的手段。它不依赖任何日志，不依赖任何配置，就是实实在在地记录网卡上流过了什么。&lt;/p&gt;&#xA;&lt;p&gt;学会用 tcpdump 和 Wireshark，是我这几年在运维上最值的一件事。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>两个容器明明在同一个宿主机上，就是互相连不上</title>
            <link>https://blog.mibase.top/p/%E4%B8%A4%E4%B8%AA%E5%AE%B9%E5%99%A8%E6%98%8E%E6%98%8E%E5%9C%A8%E5%90%8C%E4%B8%80%E4%B8%AA%E5%AE%BF%E4%B8%BB%E6%9C%BA%E4%B8%8A%E5%B0%B1%E6%98%AF%E4%BA%92%E7%9B%B8%E8%BF%9E%E4%B8%8D%E4%B8%8A/</link>
            <pubDate>Mon, 29 Jul 2024 02:54:00 +0800</pubDate>
            <guid>https://blog.mibase.top/p/%E4%B8%A4%E4%B8%AA%E5%AE%B9%E5%99%A8%E6%98%8E%E6%98%8E%E5%9C%A8%E5%90%8C%E4%B8%80%E4%B8%AA%E5%AE%BF%E4%B8%BB%E6%9C%BA%E4%B8%8A%E5%B0%B1%E6%98%AF%E4%BA%92%E7%9B%B8%E8%BF%9E%E4%B8%8D%E4%B8%8A/</guid>
            <description>&lt;img src=&#34;https://blog.mibase.top/p/%E4%B8%A4%E4%B8%AA%E5%AE%B9%E5%99%A8%E6%98%8E%E6%98%8E%E5%9C%A8%E5%90%8C%E4%B8%80%E4%B8%AA%E5%AE%BF%E4%B8%BB%E6%9C%BA%E4%B8%8A%E5%B0%B1%E6%98%AF%E4%BA%92%E7%9B%B8%E8%BF%9E%E4%B8%8D%E4%B8%8A/cover.jpg&#34; alt=&#34;Featured image of post 两个容器明明在同一个宿主机上，就是互相连不上&#34; /&gt;&lt;p&gt;有段时间我在搭一个小的内部工具，前端是一个 PHP 的容器，后端是一个 Redis 容器。两个都在同一台机器上，端口也都正常开着。&lt;/p&gt;&#xA;&lt;p&gt;但 PHP 那边一连 Redis 就报错，&lt;code&gt;Connection refused&lt;/code&gt;，或者更奇怪一点，&lt;code&gt;php_network_getaddresses: getaddrinfo failed&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;我当时的第一反应是，两个容器不是都在 &lt;code&gt;172.17.0.x&lt;/code&gt; 这个网段吗，怎么可能连不上。&lt;/p&gt;&#xA;&lt;p&gt;这个想法本身就是错的。花了小半个晚上才想明白问题出在哪，记一下。&lt;/p&gt;&#xA;&lt;h2 id=&#34;先看清楚默认的-bridge-网络&#34;&gt;先看清楚默认的 bridge 网络&#xA;&lt;/h2&gt;&lt;p&gt;我当时的启动命令大概是这样的：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker run -d --name redis redis:7&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker run -d --name web -p 8080:80 php:8.2-apache&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;两条命令都没指定 &lt;code&gt;--network&lt;/code&gt;，所以它们都跑在默认的 &lt;code&gt;bridge&lt;/code&gt; 网络上。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;docker network inspect bridge&lt;/code&gt; 看一眼：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker network inspect bridge --format &lt;span class=&#34;s1&#34;&gt;&amp;#39;{{json .Containers}}&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;两个容器确实都在里面，IP 分别是 &lt;code&gt;172.17.0.2&lt;/code&gt; 和 &lt;code&gt;172.17.0.3&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;那我先进 web 容器里试一下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; -it web bash&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ping 172.17.0.3&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;通。说明二层是通的，两个容器确实能互相访问。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ping redis&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ping: bad address &#39;redis&#39;&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;到这里问题就很清楚了。IP 能通，名字解析不了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;默认-bridge-没有内置-dns&#34;&gt;默认 bridge 没有内置 DNS&#xA;&lt;/h2&gt;&lt;p&gt;这是 Docker 里一个非常容易踩的点。&lt;/p&gt;&#xA;&lt;p&gt;在默认的 &lt;code&gt;bridge&lt;/code&gt; 网络上，Docker 是不提供自动服务发现的。容器之间只能通过 IP 通信，不能通过容器名。你想让 &lt;code&gt;redis&lt;/code&gt; 这个名字能解析，得自己用 &lt;code&gt;--link&lt;/code&gt;，而这个参数早就被标记成废弃了，官方文档里明确说不建议用。&lt;/p&gt;&#xA;&lt;p&gt;那为什么我印象里&amp;quot;容器名可以互相访问&amp;quot;呢。&lt;/p&gt;&#xA;&lt;p&gt;因为自定义网络可以。&lt;/p&gt;&#xA;&lt;p&gt;只要你自己建一个 bridge 网络，Docker 就会给它启用一个内置的 DNS 服务器，所有接入这个网络的容器都会自动注册自己的名字。之后容器之间直接 &lt;code&gt;ping 服务名&lt;/code&gt; 就能通。&lt;/p&gt;&#xA;&lt;p&gt;这就是关键区别。默认 bridge 是个历史包袱，为了兼容早期的行为，它没开这个功能。&lt;/p&gt;&#xA;&lt;h2 id=&#34;改成自定义网络&#34;&gt;改成自定义网络&#xA;&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker network create appnet&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker run -d --name redis --network appnet redis:7&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker run -d --name web --network appnet -p 8080:80 php:8.2-apache&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;再进 web 容器：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; -it web bash -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;getent hosts redis&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;这次输出 &lt;code&gt;172.18.0.2  redis&lt;/code&gt;，解析成功了。&lt;/p&gt;&#xA;&lt;p&gt;不过这里还有个细节。&lt;code&gt;ping&lt;/code&gt; 在 &lt;code&gt;php:8.2-apache&lt;/code&gt; 这个镜像里可能没装，&lt;code&gt;getent hosts&lt;/code&gt; 更通用一些。&lt;code&gt;curl&lt;/code&gt;、&lt;code&gt;nc&lt;/code&gt; 这些也未必有，排查的时候先确认工具在不在。&lt;/p&gt;&#xA;&lt;h2 id=&#34;内置-dns-是怎么回事&#34;&gt;内置 DNS 是怎么回事&#xA;&lt;/h2&gt;&lt;p&gt;Docker 在每个自定义网络的容器里塞了一个 &lt;code&gt;127.0.0.11&lt;/code&gt; 的 DNS 服务器。你可以看一下容器里的 &lt;code&gt;/etc/resolv.conf&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; web cat /etc/resolv.conf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;输出大概是：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nameserver 127.0.0.11&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;options ndots:0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;这个 &lt;code&gt;127.0.0.11&lt;/code&gt; 是 Docker 的 embedded DNS。它拦截容器内的所有 DNS 查询，先查自己维护的一张表，也就是同一网络里其他容器的名字。查不到再转发给宿主机的 DNS 或者你在 &lt;code&gt;daemon.json&lt;/code&gt; 里配的上游。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;ndots:0&lt;/code&gt; 这个选项也有讲究。它决定了域名里有多少个点才被当成绝对域名。设成 0 意味着任何带点的名字都先当绝对域名查，不做 search domain 的拼接。这个值能减少很多无谓的查询延迟。&lt;/p&gt;&#xA;&lt;h2 id=&#34;那我当初为什么连-ip-也失败过&#34;&gt;那我当初为什么连 IP 也失败过&#xA;&lt;/h2&gt;&lt;p&gt;前面说 IP 能 ping 通，但那是后来验证的。我最初遇到的报错是 &lt;code&gt;Connection refused&lt;/code&gt;，这个和 DNS 没关系，是另一个问题。&lt;/p&gt;&#xA;&lt;p&gt;Redis 的镜像默认只监听 &lt;code&gt;127.0.0.1&lt;/code&gt;。这是从 Redis 3.2 开始的默认行为，官方镜像也继承了这个配置。也就是说，就算你从外面连得上这个容器的 IP，Redis 本身也只接受本机回环的连接。&lt;/p&gt;&#xA;&lt;p&gt;解决办法是启动的时候覆盖掉：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker run -d --name redis --network appnet redis:7 redis-server --bind 0.0.0.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;或者用配置文件：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker run -d --name redis --network appnet &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -v ./redis.conf:/usr/local/etc/redis/redis.conf &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  redis:7 redis-server /usr/local/etc/redis/redis.conf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;配置文件里写 &lt;code&gt;bind 0.0.0.0&lt;/code&gt;，再配一个 &lt;code&gt;requirepass&lt;/code&gt;，因为一旦绑到 &lt;code&gt;0.0.0.0&lt;/code&gt;，同网络里任何容器都能连，得有个密码。&lt;/p&gt;&#xA;&lt;p&gt;这里顺便说一句，&lt;code&gt;bind 0.0.0.0&lt;/code&gt; 不等于把 Redis 暴露到公网。只要你没做端口映射，外面还是进不来，只有同一 Docker 网络里的容器能访问。这个边界很容易搞混。&lt;/p&gt;&#xA;&lt;h2 id=&#34;名字里的下划线和连字符&#34;&gt;名字里的下划线和连字符&#xA;&lt;/h2&gt;&lt;p&gt;还有一次，我在 Compose 里把服务名写成了 &lt;code&gt;my_redis&lt;/code&gt;，然后在应用配置里写 &lt;code&gt;my_redis&lt;/code&gt;，死活解析不了。&lt;/p&gt;&#xA;&lt;p&gt;查了半天，是 Docker 的 DNS 对下划线的处理有点特殊。容器名里带下划线的时候，有些客户端库在做解析的时候会失败，因为下划线在主机名规范里本来就不是合法字符。&lt;/p&gt;&#xA;&lt;p&gt;把服务名改成 &lt;code&gt;my-redis&lt;/code&gt;，问题立刻消失。&lt;/p&gt;&#xA;&lt;p&gt;所以我的建议是，容器名和服务名只用小写字母、数字和连字符。别用下划线，也别用大写。这个约定能省掉很多莫名其妙的解析失败。&lt;/p&gt;&#xA;&lt;h2 id=&#34;compose-里的网络行为&#34;&gt;Compose 里的网络行为&#xA;&lt;/h2&gt;&lt;p&gt;Compose 比裸 &lt;code&gt;docker run&lt;/code&gt; 好一些，它会自动为每个项目建一个网络，项目内的服务默认都接进去，名字自动能解析。&lt;/p&gt;&#xA;&lt;p&gt;但有几个地方还是会踩。&lt;/p&gt;&#xA;&lt;p&gt;一个是跨项目。项目 A 的容器想连项目 B 的容器，默认是连不上的，因为它们在两个不同的网络里。得建一个外部网络，两边都声明 &lt;code&gt;external: true&lt;/code&gt; 接进去。&lt;/p&gt;&#xA;&lt;p&gt;另一个是 &lt;code&gt;container_name&lt;/code&gt; 和 &lt;code&gt;services&lt;/code&gt; 键的区别。如果你设了 &lt;code&gt;container_name: redis&lt;/code&gt;，那这个容器在网络里的别名就是 &lt;code&gt;redis&lt;/code&gt;。如果你没设，Compose 生成的容器名是 &lt;code&gt;项目名-redis-1&lt;/code&gt;，但它在网络里的别名同时包含 &lt;code&gt;redis&lt;/code&gt; 和 &lt;code&gt;项目名-redis-1&lt;/code&gt;。所以在同一个 Compose 项目里，写服务名总是能通的。&lt;/p&gt;&#xA;&lt;p&gt;这个行为在扩容的时候会变。&lt;code&gt;docker compose up --scale web=3&lt;/code&gt; 之后，三个 web 容器会共享 &lt;code&gt;web&lt;/code&gt; 这个别名，DNS 返回的是一组 IP，客户端连到哪个不确定。这时候做负载均衡是它自带的，不需要额外配置。&lt;/p&gt;&#xA;&lt;h2 id=&#34;一个特别隐蔽的坑网络别名冲突&#34;&gt;一个特别隐蔽的坑：网络别名冲突&#xA;&lt;/h2&gt;&lt;p&gt;我有一次把两个不同的项目都接到了同一个外部网络里，然后两边都有一个叫 &lt;code&gt;db&lt;/code&gt; 的服务。&lt;/p&gt;&#xA;&lt;p&gt;结果就是 DNS 返回两个 IP，客户端随机连，有时候连到 A 的数据库，有时候连到 B 的。数据错乱了一整天才发现。&lt;/p&gt;&#xA;&lt;p&gt;解决办法是给服务加显式的网络别名：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;shared&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;aliases&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;projectA-db&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;然后应用里就写 &lt;code&gt;projectA-db&lt;/code&gt;。这样不会撞。&lt;/p&gt;&#xA;&lt;p&gt;或者干脆别共用网络，用不同的网络隔离。这个我后来更倾向，隔离得越清楚，出问题的概率越小。&lt;/p&gt;&#xA;&lt;h2 id=&#34;排查顺序&#34;&gt;排查顺序&#xA;&lt;/h2&gt;&lt;p&gt;踩过这几次之后，我形成了一个固定的检查顺序。&lt;/p&gt;&#xA;&lt;p&gt;先看容器在不在同一个网络：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker inspect web --format &lt;span class=&#34;s1&#34;&gt;&amp;#39;{{range $k, $v := .NetworkSettings.Networks}}{{$k}} {{end}}&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker inspect redis --format &lt;span class=&#34;s1&#34;&gt;&amp;#39;{{range $k, $v := .NetworkSettings.Networks}}{{$k}} {{end}}&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;两个输出里得有至少一个共同的网络名。&lt;/p&gt;&#xA;&lt;p&gt;再看容器里的 DNS 配置：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; web cat /etc/resolv.conf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;得看到 &lt;code&gt;127.0.0.11&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;再试解析：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; web getent hosts redis&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;能解析出 IP 说明名字这块没问题了。&lt;/p&gt;&#xA;&lt;p&gt;最后测连通性：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; web nc -zv redis &lt;span class=&#34;m&#34;&gt;6379&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;到这一步还不行，那就是服务本身没监听对地址，或者有防火墙规则。&lt;/p&gt;&#xA;&lt;p&gt;这套顺序跑一遍，基本五分钟内能定位。&lt;/p&gt;&#xA;&lt;h2 id=&#34;现在的习惯&#34;&gt;现在的习惯&#xA;&lt;/h2&gt;&lt;p&gt;我现在新起一个服务，一律先建自定义网络，绝不往默认 bridge 里塞东西。&lt;/p&gt;&#xA;&lt;p&gt;Compose 的话，我习惯显式写一个 &lt;code&gt;networks&lt;/code&gt; 段，哪怕只是默认的那个。写出来心里有数，不用去猜它自动生成了什么名字。&lt;/p&gt;&#xA;&lt;p&gt;还有个小习惯，我在容器里排查的时候，如果发现 &lt;code&gt;ping&lt;/code&gt;、&lt;code&gt;curl&lt;/code&gt;、&lt;code&gt;nc&lt;/code&gt; 都没有，会临时起一个 &lt;code&gt;nicolaka/netshoot&lt;/code&gt; 容器接到同一个网络上：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker run -it --rm --network appnet nicolaka/netshoot&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;这个镜像里工具很全，&lt;code&gt;dig&lt;/code&gt;、&lt;code&gt;tcpdump&lt;/code&gt;、&lt;code&gt;curl&lt;/code&gt;、&lt;code&gt;nc&lt;/code&gt; 什么都有。比自己往业务镜像里装工具干净得多。&lt;/p&gt;&#xA;&lt;p&gt;这类网络问题，说穿了就是&amp;quot;默认配置不是你以为的那个&amp;quot;。默认 bridge 没有 DNS，Redis 默认只听回环，容器名别带下划线，这三件事记住了，能省掉一大半的排查时间。&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
