揭开 `172.17.0.1` 的神秘面纱
前言
哈喽,大家好,我是你们的小小~ 👋
最近在社区里,有很多同学问了我一个看似非常基础、却又暗藏玄机的问题:“小小学姐,我的原始笔记里只记下了一个神秘的 IP 地址 —— 172.17.0.1。当时我发现在 Docker 容器里,只要访问 172.17.0.1:3000,竟然就能神奇地穿透容器,直接访问到我宿主机上的 3000 端口!这到底是怎么做到的?”
很多初学 Docker 的同学,可能都把 172.17.0.1 当作一个“魔法咒语”来背诵。遇到容器需要连宿主机的数据库(比如 MySQL、Redis),直接写上这个 IP 就能跑通,于是大呼“Docker 真香”,却很少有人真正停下来问一句:为什么?
作为一名技术人,“知其然,更要知其所以然”。比喻只是我们理解框架的拐杖,真正的目的地永远是底层那精密咬合的运行原理。如果仅仅停留在“会用”的层面,当有一天你换了 Mac 系统、或者公司网络网段冲突、又或者宿主机服务报错 Connection refused 时,你就会陷入深深的绝望。
今天,小小就带你进行一场 “硬核但不枯燥” 的深度技术探秘。我们将从这区区 10 个字符的 172.17.0.1 出发,像剥洋葱一样,一层一层地撕开 Docker 网络架构的面纱。
无论你是刚接触 Docker 的小白,还是想要彻底吃透底层机制、提升技术壁垒的资深大牛,这篇文章都将为你构建一个完整、严密的 Docker 容器网络知识闭环。
准备好了吗?泡杯咖啡,我们发车!🚀
🔥 揭开 172.17.0.1 的神秘面纱:万字长文吃透 Docker 容器与宿主机通信底层原理
🧭 导览 (Table of Contents)
- 🌟 现象与谜题:为什么
172.17.0.1成了“穿墙术”? - 🧱 筑基篇:Docker 网络的“三大法宝”
- 法宝一:Network Namespace(网络命名空间)—— 平行宇宙的结界
- 法宝二:Linux Bridge(虚拟网桥
docker0)—— 连接宇宙的星际空间站 - 法宝三:veth pair(虚拟以太网对)—— 跨越结界的隐形网线
- 🗺️ 核心探秘:揭秘
172.17.0.1的真实身份 - 🛣️ 动态追踪:一个数据包的“奇幻漂流” (附详细流转图)
- ⚠️ 致命踩坑指南:为什么 IP 对了,却还是
Connection refused?- 深入理解
0.0.0.0vs127.0.0.1Socket 绑定机制
- 深入理解
- 🧠 大牛进阶:剥开
iptables与内核路由的硬核外衣- 内核路由表的秘密
- Docker 是如何悄悄修改
iptablesNAT 表的?
- 💣 跨平台噩梦:Mac 和 Windows 玩家的专属“深坑”
- 为什么
172.17.0.1在 Mac/Windows 下突然失效了? - 终极解决方案:
host.docker.internal解析
- 为什么
- 💡 小小的最佳实践与架构建议
- 🙋 高频 Q&A (疑难杂症专诊)
- 🎓 总结
1. 🌟 现象与谜题:为什么 172.17.0.1 成了“穿墙术”?
在讲枯燥的原理前,我们先还原一个最经典的真实开发场景。
假设你在自己的电脑(宿主机)上跑了一个 Node.js Web 服务或者 MySQL 数据库,监听在 3000 端口。
接着,你启动了一个 Docker 容器(比如一个 Nginx 容器),你想在这个容器里面,把请求转发或者连接到宿主机的 3000 端口。
❌ 新手的直觉错误:
你会想当然地在容器配置里写:localhost:3000 或 127.0.0.1:3000。
结果: 报错!连接失败。因为在容器的“平行宇宙”里,它的 127.0.0.1 指的是容器自己,而不是宿主机。容器自己并没有监听 3000 端口。
✅ 老鸟的魔法代码:
你向公司的资深大佬求助,大佬轻描淡写地丢来一句:“把 127.0.0.1 换成 172.17.0.1 试试。”
你半信半疑地改掉,重启容器——结果: 竟然奇迹般地通了!
为什么这串数字有这种魔力?它究竟指向哪里?要回答这个问题,我们必须下沉到 Linux 的网络底层。
2. 🧱 筑基篇:Docker 网络的“三大法宝”
Docker 并不是什么魔法,它的本质是对 Linux 内核特性的高级封装。要弄懂 172.17.0.1,必须先掌握构建 Docker 网络世界的三个底层基石。
🛡️ 法宝一:Network Namespace(网络命名空间)—— 平行宇宙的结界
Linux 提供了一种名为 Namespace(命名空间) 的内核隔离机制。其中 Network Namespace 专门用于隔离网络资源。
- 概念白话: 想象宿主机的网络是一个繁华的“主宇宙”,拥有网卡(eth0)、IP、路由表和端口空间。当 Docker 启动一个容器时,它会利用 Network Namespace 为这个容器创造一个绝对隔离的“平行宇宙”。
- 特性: 在这个平行宇宙里,容器拥有自己独立的虚拟网卡、独立的 IP 地址、独立的路由表,甚至 独立的 端口号空间(这就是为什么你在不同容器里都可以监听 80 端口而不冲突的原因)。
🛸 法宝二:Linux Bridge(虚拟网桥 docker0)—— 连接宇宙的星际空间站
平行宇宙之间是无法直接通信的,容器既不能上网,也不能跟宿主机说话。这显然不行。于是,Docker 在宿主机的“主宇宙”中,建造了一个“星际空间站”——虚拟网桥(Linux Bridge)。
当你安装并启动 Docker 服务时,Docker 会自动在宿主机上创建一个名为 docker0 的虚拟网桥。
- 本质: 网桥(Bridge)在网络协议栈中工作在数据链路层(L2),你可以把它通俗地理解为一台虚拟交换机(Virtual Switch)。
- 神仙操作: Docker 不仅建了这台交换机,还给这台交换机分配了一个 IP 地址!默认情况下,这个 IP 就是
172.17.0.1。
📌 划重点:docker0 网桥是存在于宿主机网络空间中的。因此,172.17.0.1 这个 IP,实质上是宿主机自己网络栈上的一个 IP 地址!
🧵 法宝三:veth pair(虚拟以太网对)—— 跨越结界的隐形网线
现在我们有了孤立的容器,有了宿主机上的 docker0 交换机。怎么把它们连起来呢?Linux 内核提供了第三个法宝:veth pair(Virtual Ethernet Pair)。
- 特性:
veth pair永远是成对出现的,它们就像是一根无形的网线。从这一头发送的数据包,会原封不动地从另一头出来。 - Docker 的连接魔法:
- Docker 把这根“网线”的一头插在容器的“平行宇宙”里,命名为
eth0(容器内的虚拟网卡),并给它分配一个同网段的 IP(比如172.17.0.2)。 - Docker 把这根“网线”的另一头穿透结界,插在宿主机的
docker0虚拟交换机上(通常命名为vethXXXX这样的随机乱码网卡)。
- Docker 把这根“网线”的一头插在容器的“平行宇宙”里,命名为
💡 小结图景: 现在,所有容器都通过自己的“网线”插在了 docker0 这台交换机上。而这台交换机本身的 IP,就是 172.17.0.1。
3. 🗺️ 核心探秘:揭秘 172.17.0.1 的真实身份
经过前面的筑基,我们现在可以正式给 172.17.0.1 下个定义了。
在默认的 bridge 网络模式下,172.17.0.1 拥有双重身份:
- 对于宿主机而言: 它是宿主机上一张名为
docker0的虚拟网卡的 IP 地址。只要宿主机网络不瘫痪,宿主机始终认领这个 IP。 - 对于容器而言: 它是容器通向外部世界的 默认网关(Default Gateway)!
我们可以通过进入容器内部,查看路由表来验证这一点:
# 进入一个正在运行的容器(假设为 Nginx 容器)
$ docker exec -it my_nginx /bin/sh
# 在容器内查看路由表
$ ip route
容器内的输出结果:
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 scope link src 172.17.0.2
🧠 原理解密:
第一行 default via 172.17.0.1 dev eth0 明确宣告了:“对于我不认识的 IP(除了 172.17.x.x 同网段的局域网),通通把数据包从 eth0 网卡丢出去,交给网关 172.17.0.1 处理!”
因为 172.17.0.1 实实在在是绑定在宿主机的内核中的,所以,容器向 172.17.0.1 发送网络请求,实际上就是直接把请求发送给了宿主机本身! 这就是为什么它能“指向宿主机端口”的根本原因。
4. 🛣️ 动态追踪:一个数据包的“奇幻漂流”
为了让初学者建立直观的、极具画面感的理解,我们用 Mermaid 图表来展示当容器执行 curl 172.17.0.1:3000 时,数据包经历了怎样的一生。
sequenceDiagram
participant Container as 容器 (IP: 172.17.0.2)
participant Veth as veth pair (隐形网线)
participant Docker0 as 宿主机 docker0 (IP: 172.17.0.1)
participant HostOS as 宿主机操作系统网络栈
participant HostApp as 宿主机 Node 服务 (Port: 3000)
Note over Container: 执行 curl 172.17.0.1:3000
Container->>Container: 1. 查路由表:目标IP不是本地<br>将数据发往默认网关 172.17.0.1
Container->>Veth: 2. 数据包通过容器内 eth0 发出
Veth->>Docker0: 3. 数据包瞬间到达宿主机的另一端
Docker0->>HostOS: 4. 宿主机内核收到以 172.17.0.1 为目标的包
HostOS->>HostOS: 5. 发现目标 IP 是自己管理的 docker0 接口!
HostOS->>HostApp: 6. 查找是否有进程监听 3000 端口,发现 Node 服务并转交
Note over HostApp: 7. Node 服务处理请求并原路返回响应
详细文字拆解:
- 寻路: 容器内程序试图访问
172.17.0.1,查自己的路由表,发现该发往网关。 - 出舱: 数据包从容器内的
eth0虚拟网卡发出。 - 穿隧: 经过
veth pair隧道,数据包立刻到达宿主机侧的docker0网桥。 - 宿主机接管: 宿主机的 Linux 内核网络协议栈拦截到这个数据包。内核检查数据包的目标 IP,发现
172.17.0.1刚好是自己身上的一个网卡 IP(docker0),于是内核拍板:“哦,这包是发给我的!” - 端口匹配: 内核剥离 IP 层,查看 TCP/UDP 传输层,发现目标端口是
3000。于是内核向系统内广播:“谁监听了 3000 端口?” - 建立连接: 你跑在宿主机上的服务站出来接管了这个连接,通信成功!
5. ⚠️ 致命踩坑指南:为什么 IP 对了,却还是 Connection refused?
很多同学看到这里,觉得已经天下无敌了。转身去公司服务器上试:容器内 curl 172.17.0.1:3000。
结果现实给你泼了一盆冷水:
curl: (7) Failed to connect to 172.17.0.1 port 3000: Connection refused
“小小骗人!原理解释得天花乱坠,为什么我连不上?被拒绝了!”
别急,这也是 90% 的新手必定会踩的惊天巨坑!这个锅 Docker 不背,要怪就怪宿主机服务的“绑定地址(Bind Address)”。
🕵️ 深入理解 Socket 绑定机制(0.0.0.0 vs 127.0.0.1)
任何一个后端服务(如 Node.js, Spring Boot, MySQL, Redis)在启动监听端口时,都需要提供两个要素:端口号 和 绑定的 IP 地址。
很多现代开发框架和数据库(出于安全考虑),默认绑定的 IP 地址都是 127.0.0.1 或 localhost。
-
如果宿主机服务监听在
127.0.0.1:3000:
这意味着该服务非常傲娇,它告诉宿主机的操作系统:“我只接客从本地回环网卡(lo 网卡,即 127.0.0.1)进来的请求!外部网络,包括其他网卡进来的,一律给我拒之门外!”
还记得刚才的《奇幻漂流》吗?容器发来的请求,是从docker0网卡 进来的,目标 IP 是172.17.0.1。
所以,哪怕请求成功到达了宿主机内核,内核一核对:服务只认127.0.0.1,但你的包是冲着172.17.0.1来的,不匹配,直接拒绝连接 (Connection refused)! -
如果宿主机服务监听在
0.0.0.0:3000:
0.0.0.0在网络中代表一个特殊含义:“绑定本机所有可用的 IP 地址”。
也就是告诉内核:“不管是物理网卡(192.168.x.x)、回环网卡(127.0.0.1)还是虚拟网卡docker0(172.17.0.1)进来的 3000 端口请求,老子全包了!”
这样,容器通过172.17.0.1发过来的请求,就能被顺利接收。
🛠️ 避坑解决方案
当你遇到容器无法访问宿主机特定端口时,第一步,请务必在宿主机上执行:
netstat -tlnp | grep 3000
# 或者
ss -tlnp | grep 3000
- ❌ 错误状态:
tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN - ✅ 正确状态:
tcp 0 0 0.0.0.0:3000 0.0.0.0:* LISTEN(或者:::3000)
如何修复?修改宿主机服务的配置!
- Node.js / Express:
app.listen(3000, '0.0.0.0') - MySQL: 编辑
my.cnf,将bind-address = 127.0.0.1改为bind-address = 0.0.0.0 - Redis: 编辑
redis.conf,将bind 127.0.0.1改为bind 0.0.0.0或直接注释掉。 - (修改后记得重启对应的宿主机服务)
6. 🧠 大牛进阶:剥开 iptables 与内核路由的硬核外衣
📌 小小提示: 这一章节主要为有一定网络基础的进阶读者准备。小白如果看不懂没关系,可以直接跳到第 7 节。但如果你想成为团队里的 Docker 救火队长,这里的原理必须死磕下来。
前文我们提到了“网桥”、“网关”,这仅仅是第一层。Docker 之所以能在 Linux 上如鱼得水,其幕后的终极黑手其实是:Linux iptables(Netfilter)防火墙规则。
当容器不仅仅是访问宿主机,而是要通过宿主机访问外网(比如去拉取 Github 的代码),或者外部网络要访问容器(比如 -p 8080:80),单靠 docker0 是不够的,必须依赖 iptables 进行网络地址转换(NAT)。
🔍 Docker 对 iptables 做了什么手脚?
只要你启动了 Docker 服务,Docker Daemon 就会极其霸道地接管你宿主机内核的 iptables,向里面注入大量私有规则。我们可以通过宿主机的终端查看:
sudo iptables -t nat -L -n
你会看到几条极其关键的规则链(Chains):
1. SNAT(源地址转换)与 MASQUERADE
当容器(172.17.0.2)试图访问外网(比如 8.8.8.8)时,数据包来到宿主机的 docker0 网关。如果宿主机直接把带有源 IP 172.17.0.2 的包发到公网上,公网路由器会直接丢弃(因为 172.17.x.x 是私有网段,不能在公网路由)。
Docker 写入了类似这样的规则:
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
原理: MASQUERADE(伪装)。当 172.17.x.x 网段的数据包即将离开宿主机(POSTROUTING 阶段)时,宿主机内核会自动将数据包的 源 IP 篡改为宿主机自己的物理网卡 IP(例如 192.168.1.100)。外网响应回来时,宿主机内核再聪明地把目标 IP 翻译回容器的 IP。
这叫做 SNAT (Source Network Address Translation)。
2. DNAT(目标地址转换)与端口映射 (-p)
我们常写 docker run -p 8080:80 nginx。为什么访问宿主机的 8080 端口,就能神奇地打入容器内部的 80 端口?
这是因为 Docker 在 PREROUTING 和 DOCKER 链中写了规则:
Chain DOCKER (2 references)
target prot opt source destination
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80
原理: 当外部请求访问宿主机的 8080 端口时,宿主机内核在数据包刚刚到达(PREROUTING 阶段)时,直接拦截,将数据包的 目标 IP 和目标端口 强行篡改为容器的 IP 172.17.0.2 和端口 80。然后数据包被丢进 docker0 网桥,顺着 veth pair 掉进了容器里。
这叫做 DNAT (Destination Network Address Translation)。
7. 💣 跨平台噩梦:Mac 和 Windows 玩家的专属“深坑”
好了,在 Linux 下,172.17.0.1 的底层逻辑已经无懈可击了。
但是!如果你的开发机器是 MacBook 或者 Windows,你会发现前面讲的这些,在你的机器上全部 失!效!了!
你在 Mac 的 Docker 容器里 curl 172.17.0.1:3000,绝对是超时(Timeout)或者无响应。
为什么呢?这难道是玄学?
🧐 揭穿 Docker Desktop 的谎言:多了一层“虚拟机”!
我们必须要知道一个扎心的残酷事实:Docker 容器的核心本质是依赖于 Linux 内核特性的(Namespace, Cgroups)。Mac OS (Darwin) 和 Windows (NT) 的内核根本没有这些东西!
那怎么能在 Mac/Windows 上跑 Docker 呢?
真相大白: 当你安装 Docker Desktop for Mac/Win 时,它其实是在你的系统里偷偷启动了一个极其轻量级的 Linux 虚拟机(VM / Hypervisor)!所有的容器,都跑在这个不可见的虚拟机里面。
我们来看这幅残酷的架构对比图:
graph TD
subgraph Linux 原生环境
L_Host[宿主机 Host OS]
L_Docker0[docker0: 172.17.0.1]
L_Container[容器: 172.17.0.2]
L_Host --- L_Docker0
L_Docker0 --- L_Container
end
subgraph "Mac / Windows 桌面版 Docker (Docker Desktop)"
M_Host[你的电脑 Mac/Win Host]
subgraph 隐藏的 Linux VM
M_Docker0[docker0: 172.17.0.1]
M_Container[容器: 172.17.0.2]
end
M_Host -.隔离.- M_Docker0
M_Docker0 --- M_Container
end
style L_Host fill:#f9f,stroke:#333,stroke-width:4px
style M_Host fill:#f9f,stroke:#333,stroke-width:4px
style 隐藏的 Linux VM fill:#ccf,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5
致命断层分析:
在 Mac/Win 上,那个大家熟悉的 docker0 网桥(172.17.0.1),是存在于那台隐藏的 Linux 虚拟机内部的!
它 并不在你的 Mac/Windows 宿主机上!
所以,当容器在 Mac 环境下请求 172.17.0.1:3000 时,请求抵达了那台虚拟机的内核,然后虚拟机内核一看:“我身上没有进程监听 3000 端口啊。”(因为你的 Node/MySQL 是跑在 Mac 的操作系统上的,而不是虚拟机里)。于是,请求石沉大海。
🚀 终极解决大招:host.docker.internal
为了解决这种跨平台的网络割裂,Docker Desktop 官方提供了一个非常优雅、跨时代的魔法 DNS 域名:
👉 host.docker.internal
从 Docker 18.03 版本开始,针对 Mac 和 Windows,你只需要在容器里把地址写成:
http://host.docker.internal:3000
Docker 守护进程会在内部动态运行一个 DNS 解析器。当容器查询 host.docker.internal 时,Docker 会将其智能解析为 你 Mac/Windows 电脑在局域网内的真实物理 IP 地址。这样,请求就能顺利绕出虚拟机,打到你的物理机上!
8. 💡 小小的最佳实践与架构建议
看完了原理,是时候拔高我们的架构视野了。在 2026 年的今天,硬编码 172.17.0.1 早就不是最佳实践了。作为有追求的开发者,小小推荐你采用以下姿势:
🥇 最佳实践一:全平台通杀的 --add-host 参数
如果你想让一套代码(一份配置)同时在 Linux 服务器和 Mac/Win 开发机上完美运行,你应该使用 --add-host 注入机制。
自 Docker 20.10+ 起,Linux 版本的 Docker 也开始原生支持 host.docker.internal 了,但需要我们在启动时显式声明:
docker run -d \
--name my_app \
--add-host=host.docker.internal:host-gateway \
my_image
- 魔法解析:
host-gateway是 Docker 内部的一个特殊占位符。在 Linux 下,它会被自动替换为docker0的网关 IP(即 172.17.0.1);在 Mac/Win 下,它由 Docker Desktop 自动处理。 - 收益: 无论什么环境,你的代码只需要认准
host.docker.internal这个域名即可,告别因为平台不同而修改配置文件的痛苦!
🥈 最佳实践二:慎用默认的 bridge(桥接)模式,使用自定义网络
在真实的生产环境中,极少有企业会把业务容器全扔进默认的 docker0 (172.17.0.1) 里。
- 痛点: 默认 bridge 不支持通过容器名互访(内置 DNS 机制残缺)。
- 推荐: 使用
docker network create my_net创建自定义网络。在自定义网络中,不仅网段可以自由规划(避免与公司办公网段冲突),容器之间还可以直接通过名字(如http://mysql_db:3306)互相解析,优雅至极。
🥉 最佳实践三:极端性能下的 host 网络模式
如果你的容器和宿主机之间的网络交互存在海量的高吞吐量(比如千万级 QPS 的 Redis),每次穿越 veth pair 和 iptables 的 NAT 转发会带来微秒级的延迟损耗。
在 Linux 环境下,你可以使用 --network host。
- 原理: 打破结界!容器不再创建单独的 Network Namespace,而是直接和宿主机共享同一个网络栈。
- 结果: 容器直接使用宿主机的真实 IP,性能达到 100% 物理机原生级别。但代价是隔离性变差,端口可能发生冲突。
9. 🙋 高频 Q&A (疑难杂症专诊)
在实际排查中,你可能还会遇到各种千奇百怪的问题。小小专门整理了几个高频的疑难杂症,对症下药:
Q1:为什么我 Linux 服务器上的 docker0 网关不是 172.17.0.1,而是 172.18.0.1 或者其他的?
小小学姐: 这是因为你的服务器之前可能经历过网络冲突。如果你的物理机所在局域网本身就在使用
172.17.x.x网段,Docker 启动时很聪明地发现了冲突,就会自动顺延,使用172.18.x.x或其他内网保留网段。要以ip addr show docker0输出的实际 IP 为准。如果你想写死配置,可以通过修改/etc/docker/daemon.json中的"bip"属性强制指定docker0的网段。
Q2:我的服务绑定了 0.0.0.0,容器 ping 宿主机 172.17.0.1 也能通,但访问端口就是不通(Timeout),怎么回事?
小小学姐: 敲黑板!如果是 Timeout(超时)而不是 Connection refused(拒绝),99% 的概率是宿主机的防火墙(Firewalld / UFW / iptables 规则)把来自
docker0网卡的请求包给拦截丢弃了!
尝试在宿主机执行命令开放端口:
- CentOS:
firewall-cmd --zone=public --add-port=3000/tcp --permanent && firewall-cmd --reload- Ubuntu:
ufw allow from 172.17.0.0/16 to any port 3000
让防火墙信任来自 Docker 网段的流量即可解决。
Q3:我能在宿主机上直接用 172.17.0.2 (容器的 IP) 来访问容器吗?
小小学姐: 在原生的 Linux 系统上,完全可以! 因为宿主机本身的内核拥有到 172.17.0.0/16 路由表条目,且宿主机和容器共享底层的 veth,它是互通的。
但在 Mac 和 Windows (Docker Desktop) 上,绝对不行! 因为前面说过,容器和那个 172.17.x.x 的网段是在隐藏的虚拟机里面的,对你的 Mac 物理机是不可见的。要访问容器,必须通过-p端口映射暴露给宿主机。
10. 🎓 总结
呼~跟着小小一口气走了这么远,不知你是否有一种“拨开云雾见青天”的通透感?
让我们最后再回顾一下这段知识旅程的精髓:
当你在讨论 172.17.0.1 时,你实际上在讨论的是:
- Linux 的 Network Namespace 创造了隔离的平行宇宙。
- Linux Bridge (
docker0) 和veth pair搭建了跨宇宙的桥梁。 172.17.0.1既是docker0网桥在宿主机上的 真实 IP,也是容器通往外部世界的 默认网关。- 因为这是宿主机的 IP,所以容器向网关发包,本质就是发给宿主机。
- 成功的关键不仅在于网络通畅,更在于宿主机服务必须绑定
0.0.0.0,且防火墙不拦截。 - 不要忘了,平台是有差异的,跨平台最优雅的解法是利用
host.docker.internal。
真正的技术大牛,从来不是记住某一段魔法代码或者神秘 IP,而是能站在系统的制高点,俯瞰数据包穿梭于虚拟与现实之间的每一个节点,洞察每一次连接的生死。
希望这篇超级详尽的教程,不仅让你搞懂了 172.17.0.1,更能让你对 Docker 和网络底层有一层全新的感悟。如果你的团队里还有小伙伴对 Docker 网络一知半解,或者还在饱受跨平台网络不通的折磨,快把这篇文章转给他们看看吧!
我是小小,那个热衷于把硬核原理揉碎了讲给你听的技术布道师。我们下期再见啦!💖🚀