/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
1. 引言
上一篇文章我们聊了 Docker 网络的基础概念,包括 veth pair、网桥、iptables 这些底层组件。今天我们把视角拉高一层,从「容器如何通信」这个实际问题出发,把 Docker 提供的五种网络模式——bridge、host、none、macvlan、overlay——逐个拆开揉碎,讲清楚它们各自的工作原理、适用场景和坑位。
这篇文章会用到 nsenter 和 ip 命令直接「扒开」容器的网络栈,让你亲眼看到 veth pair 是怎么把容器和宿主机连起来的,iptables 又是怎么在背后做端口转发的。建议你跟着操作,在自己的机器上跑一遍,理解会深刻得多。
2. 前置准备:把容器网络栈「扒开」看
在正式讲五种模式之前,先学会一个核心技能:进入容器的网络命名空间,直接查看它的网络栈。
2.1 找到容器的 PID
# 启动一个容器
docker run -d –name web –rm nginx
# 获取容器主进程 PID
docker inspect -f '{{.State.Pid}}' web
假设输出是 12345,这个 PID 就是容器内主进程在宿主机上的 PID。
2.2 用 nsenter 进入网络命名空间
# 进入容器的网络命名空间,执行 ip addr
nsenter -t 12345 -n ip addr
# 查看路由表
nsenter -t 12345 -n ip route
# 查看 iptables 规则(容器内视角)
nsenter -t 12345 -n iptables -t nat -L -n
-t 指定目标进程 PID,-n 表示进入网络命名空间。执行后你会看到容器内的 eth0、lo 接口,以及它自己的路由表——这就是容器「独立网络栈」的直接证据。
2.3 在宿主机上找 veth pair
# 在宿主机上查看所有 veth 接口
ip link show type veth
# 找到与容器 eth0 配对的 veth(通过 ifindex 关联)
# 容器内 eth0 的 ifindex 通常是 3,宿主机上对应 vethXXXX
容器内的 eth0 和宿主机上的 vethXXXX 是一对 veth pair,数据从一端进入,必然从另一端出来。这就是容器网络的最基本单元。
3. bridge 模式:默认选择,也是理解一切的基石
3.1 工作原理
当你执行 docker run 不指定 –network 时,默认就是 bridge 模式。它的拓扑结构如下:
#mermaid-svg-TQRyEUXf8yinFBD9{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TQRyEUXf8yinFBD9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TQRyEUXf8yinFBD9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TQRyEUXf8yinFBD9 .error-icon{fill:#552222;}#mermaid-svg-TQRyEUXf8yinFBD9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TQRyEUXf8yinFBD9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TQRyEUXf8yinFBD9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TQRyEUXf8yinFBD9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TQRyEUXf8yinFBD9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TQRyEUXf8yinFBD9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TQRyEUXf8yinFBD9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TQRyEUXf8yinFBD9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TQRyEUXf8yinFBD9 .marker.cross{stroke:#333333;}#mermaid-svg-TQRyEUXf8yinFBD9 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TQRyEUXf8yinFBD9 p{margin:0;}#mermaid-svg-TQRyEUXf8yinFBD9 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-TQRyEUXf8yinFBD9 .cluster-label text{fill:#333;}#mermaid-svg-TQRyEUXf8yinFBD9 .cluster-label span{color:#333;}#mermaid-svg-TQRyEUXf8yinFBD9 .cluster-label span p{background-color:transparent;}#mermaid-svg-TQRyEUXf8yinFBD9 .label text,#mermaid-svg-TQRyEUXf8yinFBD9 span{fill:#333;color:#333;}#mermaid-svg-TQRyEUXf8yinFBD9 .node rect,#mermaid-svg-TQRyEUXf8yinFBD9 .node circle,#mermaid-svg-TQRyEUXf8yinFBD9 .node ellipse,#mermaid-svg-TQRyEUXf8yinFBD9 .node polygon,#mermaid-svg-TQRyEUXf8yinFBD9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TQRyEUXf8yinFBD9 .rough-node .label text,#mermaid-svg-TQRyEUXf8yinFBD9 .node .label text,#mermaid-svg-TQRyEUXf8yinFBD9 .image-shape .label,#mermaid-svg-TQRyEUXf8yinFBD9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-TQRyEUXf8yinFBD9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TQRyEUXf8yinFBD9 .rough-node .label,#mermaid-svg-TQRyEUXf8yinFBD9 .node .label,#mermaid-svg-TQRyEUXf8yinFBD9 .image-shape .label,#mermaid-svg-TQRyEUXf8yinFBD9 .icon-shape .label{text-align:center;}#mermaid-svg-TQRyEUXf8yinFBD9 .node.clickable{cursor:pointer;}#mermaid-svg-TQRyEUXf8yinFBD9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TQRyEUXf8yinFBD9 .arrowheadPath{fill:#333333;}#mermaid-svg-TQRyEUXf8yinFBD9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TQRyEUXf8yinFBD9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TQRyEUXf8yinFBD9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TQRyEUXf8yinFBD9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TQRyEUXf8yinFBD9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TQRyEUXf8yinFBD9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TQRyEUXf8yinFBD9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TQRyEUXf8yinFBD9 .cluster text{fill:#333;}#mermaid-svg-TQRyEUXf8yinFBD9 .cluster span{color:#333;}#mermaid-svg-TQRyEUXf8yinFBD9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TQRyEUXf8yinFBD9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TQRyEUXf8yinFBD9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-TQRyEUXf8yinFBD9 .icon-shape,#mermaid-svg-TQRyEUXf8yinFBD9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TQRyEUXf8yinFBD9 .icon-shape p,#mermaid-svg-TQRyEUXf8yinFBD9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TQRyEUXf8yinFBD9 .icon-shape .label rect,#mermaid-svg-TQRyEUXf8yinFBD9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TQRyEUXf8yinFBD9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TQRyEUXf8yinFBD9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TQRyEUXf8yinFBD9 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
veth pair
veth pair
iptables MASQUERADE
容器A eth0
vethA
容器B eth0
vethB
docker0 网桥
宿主机 eth0
外部网络
关键点:
- 每个容器有一个独立的网络命名空间,有自己的 eth0。
- 容器的 eth0 通过 veth pair 连接到宿主机上的 docker0 网桥。
- 同一 bridge 下的容器可以直接通过 IP 通信,不需要经过宿主机路由。
- 容器访问外部网络时,数据包经过 docker0 → 宿主机路由 → iptables 的 MASQUERADE 规则做 SNAT,源 IP 变成宿主机 IP。
3.2 动手验证
# 启动两个容器
docker run -d –name c1 –rm nginx
docker run -d –name c2 –rm nginx
# 查看 c1 的 IP
docker inspect -f '{{.NetworkSettings.IPAddress}}' c1
# 从 c2 ping c1 的 IP
docker exec c2 ping -c 2 <c1的IP>
你会发现能 ping 通。但注意:默认 bridge 下,容器之间不能用容器名通信,只能用 IP。这是新手最容易踩的坑。
3.3 适用场景
- 单机多容器通信,不需要跨主机。
- 需要端口映射给外部访问。
- 对网络隔离有一定要求(默认 bridge 容器间可以互通,但可以通过自定义 bridge 加限制)。
4. host 模式:共享宿主机网络栈
4.1 工作原理
–network host 模式下,容器不创建独立的网络命名空间,直接使用宿主机的网络栈。容器内的进程看到的 eth0、路由表、iptables 规则,就是宿主机的。
docker run -d –name web –network host nginx
此时访问 http://宿主机IP:80 就能直接打到容器里的 nginx,因为容器和宿主机共享同一个 80 端口。
4.2 最大的坑:-p 失效
# 这样写是无效的!
docker run -d –name web –network host -p 8080:80 nginx
在 host 模式下,-p 参数会被静默忽略。因为容器已经共享宿主机的网络栈,不存在「端口映射」这回事——容器监听什么端口,宿主机就监听什么端口。如果你需要 8080,就得让容器内的服务直接监听 8080。
4.3 适用场景
- 性能敏感型应用,不想经过 NAT 和网桥转发。
- 需要容器访问宿主机上的特定网络接口(如抓包、VPN)。
- 单机部署,端口冲突可控。
4.4 坑位提醒
- 端口冲突:容器内服务监听的端口会直接占用宿主机端口,多个 host 模式容器不能监听同一端口。
- 网络隔离失效:容器和宿主机完全共享网络栈,安全边界消失。
5. none 模式:完全隔离
5.1 工作原理
–network none 模式下,容器有独立的网络命名空间,但没有任何网络接口(除了 loopback)。没有 eth0,没有路由,没有 iptables 规则。
docker run -d –name isolated –network none nginx
# 查看容器网络接口
docker exec isolated ip addr
# 只有 lo,没有 eth0
5.2 适用场景
- 纯计算任务,不需要任何网络通信。
- 安全敏感场景,需要彻底隔离网络。
- 作为自定义网络配置的起点(后面手动加 veth)。
5.3 坑位提醒
- 容器内无法访问外网,也无法被外部访问。
- 如果应用需要网络,用 none 模式会直接报错。
6. macvlan 模式:让容器拥有独立 MAC 地址
6.1 工作原理
macvlan 模式让每个容器在宿主机物理网络上直接分配一个 MAC 地址,容器看起来就像局域网里的一台独立物理机。
# 创建 macvlan 网络
docker network create -d macvlan \\
–subnet=192.168.1.0/24 \\
–gateway=192.168.1.1 \\
-o parent=eth0 \\
my_macvlan
# 使用 macvlan 网络启动容器
docker run -d –name web –network my_macvlan –ip 192.168.1.100 nginx
6.2 工作原理图
#mermaid-svg-0YrWqRGK45pEO7rx{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0YrWqRGK45pEO7rx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0YrWqRGK45pEO7rx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0YrWqRGK45pEO7rx .error-icon{fill:#552222;}#mermaid-svg-0YrWqRGK45pEO7rx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0YrWqRGK45pEO7rx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0YrWqRGK45pEO7rx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0YrWqRGK45pEO7rx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0YrWqRGK45pEO7rx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0YrWqRGK45pEO7rx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0YrWqRGK45pEO7rx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0YrWqRGK45pEO7rx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0YrWqRGK45pEO7rx .marker.cross{stroke:#333333;}#mermaid-svg-0YrWqRGK45pEO7rx svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0YrWqRGK45pEO7rx p{margin:0;}#mermaid-svg-0YrWqRGK45pEO7rx .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-0YrWqRGK45pEO7rx .cluster-label text{fill:#333;}#mermaid-svg-0YrWqRGK45pEO7rx .cluster-label span{color:#333;}#mermaid-svg-0YrWqRGK45pEO7rx .cluster-label span p{background-color:transparent;}#mermaid-svg-0YrWqRGK45pEO7rx .label text,#mermaid-svg-0YrWqRGK45pEO7rx span{fill:#333;color:#333;}#mermaid-svg-0YrWqRGK45pEO7rx .node rect,#mermaid-svg-0YrWqRGK45pEO7rx .node circle,#mermaid-svg-0YrWqRGK45pEO7rx .node ellipse,#mermaid-svg-0YrWqRGK45pEO7rx .node polygon,#mermaid-svg-0YrWqRGK45pEO7rx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0YrWqRGK45pEO7rx .rough-node .label text,#mermaid-svg-0YrWqRGK45pEO7rx .node .label text,#mermaid-svg-0YrWqRGK45pEO7rx .image-shape .label,#mermaid-svg-0YrWqRGK45pEO7rx .icon-shape .label{text-anchor:middle;}#mermaid-svg-0YrWqRGK45pEO7rx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0YrWqRGK45pEO7rx .rough-node .label,#mermaid-svg-0YrWqRGK45pEO7rx .node .label,#mermaid-svg-0YrWqRGK45pEO7rx .image-shape .label,#mermaid-svg-0YrWqRGK45pEO7rx .icon-shape .label{text-align:center;}#mermaid-svg-0YrWqRGK45pEO7rx .node.clickable{cursor:pointer;}#mermaid-svg-0YrWqRGK45pEO7rx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0YrWqRGK45pEO7rx .arrowheadPath{fill:#333333;}#mermaid-svg-0YrWqRGK45pEO7rx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0YrWqRGK45pEO7rx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0YrWqRGK45pEO7rx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0YrWqRGK45pEO7rx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0YrWqRGK45pEO7rx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0YrWqRGK45pEO7rx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0YrWqRGK45pEO7rx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0YrWqRGK45pEO7rx .cluster text{fill:#333;}#mermaid-svg-0YrWqRGK45pEO7rx .cluster span{color:#333;}#mermaid-svg-0YrWqRGK45pEO7rx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0YrWqRGK45pEO7rx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0YrWqRGK45pEO7rx rect.text{fill:none;stroke-width:0;}#mermaid-svg-0YrWqRGK45pEO7rx .icon-shape,#mermaid-svg-0YrWqRGK45pEO7rx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0YrWqRGK45pEO7rx .icon-shape p,#mermaid-svg-0YrWqRGK45pEO7rx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0YrWqRGK45pEO7rx .icon-shape .label rect,#mermaid-svg-0YrWqRGK45pEO7rx .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0YrWqRGK45pEO7rx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0YrWqRGK45pEO7rx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0YrWqRGK45pEO7rx :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
直接接入
容器A MAC: 02:42:ac:11:00:01
物理交换机
容器B MAC: 02:42:ac:11:00:02
宿主机 eth0 MAC: 00:11:22:33:44:55
局域网
6.3 适用场景
- 容器需要直接暴露在局域网中,被其他物理机直接访问。
- 需要容器拥有独立 MAC 地址的场景(如 DHCP 分配、MAC 过滤)。
- 对性能要求高,不想经过 NAT。
6.4 坑位提醒
- 宿主机与容器无法直接通信:macvlan 模式下,宿主机和容器之间默认不通,因为 MAC 地址隔离。需要额外配置或使用 ipvlan。
- 需要物理网卡支持混杂模式。
- 跨主机通信需要依赖物理交换机配置,Docker 本身不处理。
7. overlay 网络:跨主机通信的正解
7.1 工作原理
overlay 网络是 Docker Swarm 模式下的跨主机网络方案。它通过 VXLAN 隧道技术,把多个宿主机上的容器「虚拟」地连接在同一个二层网络里。
# 初始化 Swarm
docker swarm init
# 创建 overlay 网络
docker network create -d overlay –attachable my_overlay
# 在不同主机上启动容器,加入同一 overlay 网络
docker service create –name web –network my_overlay –replicas 2 nginx
7.2 数据流转过程
#mermaid-svg-hErVWrABVLif9vr7{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hErVWrABVLif9vr7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hErVWrABVLif9vr7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hErVWrABVLif9vr7 .error-icon{fill:#552222;}#mermaid-svg-hErVWrABVLif9vr7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hErVWrABVLif9vr7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hErVWrABVLif9vr7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hErVWrABVLif9vr7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hErVWrABVLif9vr7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hErVWrABVLif9vr7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hErVWrABVLif9vr7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hErVWrABVLif9vr7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hErVWrABVLif9vr7 .marker.cross{stroke:#333333;}#mermaid-svg-hErVWrABVLif9vr7 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hErVWrABVLif9vr7 p{margin:0;}#mermaid-svg-hErVWrABVLif9vr7 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-hErVWrABVLif9vr7 .cluster-label text{fill:#333;}#mermaid-svg-hErVWrABVLif9vr7 .cluster-label span{color:#333;}#mermaid-svg-hErVWrABVLif9vr7 .cluster-label span p{background-color:transparent;}#mermaid-svg-hErVWrABVLif9vr7 .label text,#mermaid-svg-hErVWrABVLif9vr7 span{fill:#333;color:#333;}#mermaid-svg-hErVWrABVLif9vr7 .node rect,#mermaid-svg-hErVWrABVLif9vr7 .node circle,#mermaid-svg-hErVWrABVLif9vr7 .node ellipse,#mermaid-svg-hErVWrABVLif9vr7 .node polygon,#mermaid-svg-hErVWrABVLif9vr7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hErVWrABVLif9vr7 .rough-node .label text,#mermaid-svg-hErVWrABVLif9vr7 .node .label text,#mermaid-svg-hErVWrABVLif9vr7 .image-shape .label,#mermaid-svg-hErVWrABVLif9vr7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-hErVWrABVLif9vr7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hErVWrABVLif9vr7 .rough-node .label,#mermaid-svg-hErVWrABVLif9vr7 .node .label,#mermaid-svg-hErVWrABVLif9vr7 .image-shape .label,#mermaid-svg-hErVWrABVLif9vr7 .icon-shape .label{text-align:center;}#mermaid-svg-hErVWrABVLif9vr7 .node.clickable{cursor:pointer;}#mermaid-svg-hErVWrABVLif9vr7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hErVWrABVLif9vr7 .arrowheadPath{fill:#333333;}#mermaid-svg-hErVWrABVLif9vr7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hErVWrABVLif9vr7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hErVWrABVLif9vr7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hErVWrABVLif9vr7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hErVWrABVLif9vr7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hErVWrABVLif9vr7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hErVWrABVLif9vr7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hErVWrABVLif9vr7 .cluster text{fill:#333;}#mermaid-svg-hErVWrABVLif9vr7 .cluster span{color:#333;}#mermaid-svg-hErVWrABVLif9vr7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hErVWrABVLif9vr7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hErVWrABVLif9vr7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-hErVWrABVLif9vr7 .icon-shape,#mermaid-svg-hErVWrABVLif9vr7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hErVWrABVLif9vr7 .icon-shape p,#mermaid-svg-hErVWrABVLif9vr7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hErVWrABVLif9vr7 .icon-shape .label rect,#mermaid-svg-hErVWrABVLif9vr7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hErVWrABVLif9vr7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hErVWrABVLif9vr7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hErVWrABVLif9vr7 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
VXLAN 封装
UDP 4789 隧道
VXLAN 解封装
容器A(主机1)
主机1 VTEP
主机2 VTEP
容器B(主机2)
- 每个主机上有一个 VTEP(VXLAN Tunnel Endpoint),负责封装/解封装。
- 容器间的流量被封装成 VXLAN 包,通过 UDP 4789 端口在主机间传输。
- 对容器来说,它们就像在同一个二层网络里,可以直接用容器名通信(overlay 自带 DNS 解析)。
7.3 适用场景
- 跨主机多容器通信,特别是 Swarm 服务编排。
- 需要容器名即域名的跨主机解析。
- 微服务架构中服务间调用。
7.4 坑位提醒
- 需要 4789 端口在主机间开放。
- 性能比 bridge 略低(有封装开销)。
- 需要 Swarm 或 Kubernetes 等编排工具配合。
8. 自定义 bridge:容器名即域名
8.1 为什么默认 bridge 没有 DNS
默认的 docker0 网桥不提供 DNS 解析,容器之间只能用 IP 通信。这是 Docker 设计上的取舍——默认 bridge 为了兼容性和简单性,牺牲了内置 DNS。
8.2 创建自定义 bridge
# 创建自定义 bridge 网络
docker network create my_bridge
# 启动两个容器,加入同一网络
docker run -d –name c1 –network my_bridge nginx
docker run -d –name c2 –network my_bridge nginx
# 现在可以直接用容器名通信!
docker exec c2 ping c1
自定义 bridge 自带嵌入式 DNS,容器名会自动注册为域名。c1 这个名字在 my_bridge 网络内就是一个可解析的域名。
8.3 原理
自定义 bridge 的 DNS 由 Docker 内置的 127.0.0.11 提供。每个容器内的 /etc/resolv.conf 会指向这个地址,Docker 的 DNS 服务再把请求转发到上游 DNS。
# 查看容器内的 DNS 配置
docker exec c1 cat /etc/resolv.conf
# nameserver 127.0.0.11
8.4 适用场景
- 单机多容器服务发现,用容器名互相调用。
- 需要自定义网段、网关的场景。
- 需要容器间网络隔离(不同 bridge 之间默认不通)。
9. 端口映射 vs 容器直连:什么时候该映射,什么时候不该
9.1 端口映射的本质
端口映射(-p 8080:80)本质上是 iptables 的 DNAT 规则:把宿主机 8080 端口的流量转发到容器 80 端口。
# 查看端口映射对应的 iptables 规则
iptables -t nat -L DOCKER -n
9.2 什么时候该用端口映射
- 外部客户端需要访问容器:比如浏览器访问 Web 服务、App 调用后端 API。
- 需要固定宿主机端口:对外暴露的服务需要稳定入口。
- 多容器共享同一端口:多个容器都监听 80,通过不同宿主机端口区分。
9.3 什么时候不该用端口映射
- 容器间通信:同一网络内的容器直接用容器名或 IP 通信,不需要映射,避免绕一圈 NAT。
- 内部服务:数据库、缓存、消息队列等只对内部开放的服务,不要映射到宿主机,减少攻击面。
- 性能敏感:NAT 有轻微性能损耗,内部通信直连更快。
9.4 端口冲突排查
# 查看端口占用
ss -tlnp | grep 8080
# 查看 Docker 端口映射
docker ps –format '{{.Names}} {{.Ports}}'
# 查看 iptables 中 DOCKER 链
iptables -t nat -L DOCKER -n
常见冲突原因:
- 宿主机端口已被其他进程占用。
- 两个容器映射到同一宿主机端口。
- iptables 规则残留(容器删除后规则未清理)。
10. 跨主机通信:overlay 与经典方案对比
10.1 三种方案概览
| Docker overlay | VXLAN | Swarm 编排 | 集成度高,自带 DNS | 依赖 Swarm |
| Calico | BGP + IPIP | Kubernetes | 性能好,策略丰富 | 配置复杂 |
| Flannel | VXLAN / host-gw | Kubernetes | 简单易用 | 功能较少 |
10.2 Calico 的核心思路
Calico 不走隧道封装,而是用 BGP 协议直接在宿主机之间交换路由信息。每个容器分配一个 IP,宿主机通过 BGP 学习到其他主机上容器的路由,数据包直接路由过去,性能接近物理网络。
10.3 Flannel 的核心思路
Flannel 默认用 VXLAN 隧道,和 Docker overlay 类似。它把每个宿主机分配一个子网段,容器 IP 从子网段中分配,跨主机通信通过隧道封装。
10.4 怎么选
- 用 Docker Swarm → 直接用 overlay,零额外成本。
- 用 Kubernetes 且追求性能 → Calico。
- 用 Kubernetes 且追求简单 → Flannel。
- 小规模跨主机 → 也可以考虑手动配置 VXLAN 或使用 VPN 方案。
11. 坑位总结
11.1 默认 bridge 无 DNS
默认 docker0 网桥不支持容器名解析,容器间只能用 IP。解决方案:创建自定义 bridge,用 –network my_bridge 启动容器。
11.2 –network host 下 -p 失效
host 模式共享宿主机网络栈,-p 参数被静默忽略。解决方案:直接让容器内服务监听目标端口,或改用 bridge 模式。
11.3 端口冲突排查
- 用 ss -tlnp 查宿主机端口占用。
- 用 docker ps 查容器映射。
- 用 iptables -t nat -L DOCKER -n 查残留规则。
11.4 macvlan 宿主机与容器不通
macvlan 模式下宿主机无法直接访问容器。解决方案:用 ipvlan 模式,或额外添加一个 bridge 网络作为管理通道。
11.5 overlay 需要开放 4789 端口
跨主机通信依赖 UDP 4789,防火墙要放行。解决方案:在主机防火墙和安全组中开放 UDP 4789。
12. 总结
五种网络模式各有定位:
- bridge:默认选择,单机多容器通信,端口映射。
- host:性能优先,共享宿主机网络栈,注意 -p 失效。
- none:完全隔离,纯计算任务。
- macvlan:容器拥有独立 MAC,直接暴露局域网。
- overlay:跨主机通信,Swarm 标配。
理解它们的关键在于:网络命名空间、veth pair、iptables 这三板斧。用 nsenter 和 ip 命令亲手扒开容器网络栈,比背十遍文档都管用。
下一篇文章我们会深入 iptables 的 NAT 链,把端口映射的完整数据流一步步拆开,敬请期待。

