4.1 四种网络模式拓扑


4.1 四种网络模式拓扑

摘要:docker run 的 --network 参数决定容器要不要新建 NET namespace、以及怎么接入宿主机。本节拆解 bridge、host、none、container 四种模式的设备拓扑与数据路径,给出验证命令与选型依据。

学习目标

  1. 画出 bridge 模式下 veth pair 与 docker0 的连接关系
  2. 解释 host 模式为什么零 NAT 开销、又有什么代价
  3. 用命令验证容器当前所处的网络模式
  4. 按场景选择正确的网络模式

模式之争的本质:三道选择题

四种网络模式看着繁杂,其实只是同一组内核机制的不同组合。把选择过程拆成三道题就清楚了:要不要新建独立的网络栈?不要,就是 host 模式,直接借宿主机的;要,接着问第二道——这个网络栈里放不放设备与地址?什么都不放,就是 none 模式,只剩一个回环;放,就是 bridge 或自定义网络,由 Docker 造 veth、分地址、配路由。第三道题:独立网络栈是自己新建,还是复用另一个容器的?复用即 container 模式,两容器同吃一锅饭。三道题答完,模式自然确定,不需要死记参数表。下面按使用频率逐个展开。

bridge:一条内网街

不指定 --network 时容器落在 bridge 模式。它的物理结构分三件:

docker0 网桥。宿主机上一个虚拟二层设备,配网段通常是 172.17.0.0/16,自己占 172.17.0.1,充当这条内网街的网关。

veth pair。一对虚拟网线,从任何一端塞进去的包会从另一端出来。容器创建时 Docker 建一对:一端放进容器的 NET namespace 成为 eth0,另一端留在宿主机并挂到 docker0 上。容器与外界的一切流量都走这根线。

iptables NAT 规则。容器访问外网时做源地址转换(SNAT,把 172.17.0.2 换成宿主机 IP),外部访问映射端口时做目标地址转换(DNAT,4.2 细讲)。

亲手摸一遍:

docker run -d --name net-demo nginx:alpine docker exec net-demo ip addr

容器里 eth0 的地址形如 172.17.0.2。同时在宿主机上能看到线的另一端:

ip link | grep veth

输出一串 vethxxxx@ifY 设备——每跑一个 bridge 容器,宿主机就多一根这样的线。容器里的默认路由指向 172.17.0.1,即 docker0:

docker exec net-demo ip route # default via 172.17.0.1 dev eth0

bridge 模式的隔离性最好、最通用,代价是 NAT 带来的一点点性能损耗与端口映射的心智负担。绝大多数服务用它。

host:借宿主机的网络栈

docker run -d --network host --name host-demo nginx:alpine

host 模式不新建 NET namespace,容器进程直接挂进宿主机的网络栈:容器里看到的网卡就是宿主机的网卡,bind 80 就是占宿主机的 80。两个好处:性能零损耗(无 NAT、无 veth、无协议栈切换);无需端口映射。两个代价:端口空间与宿主机共用,起第二个 bind 80 的 host 容器直接失败;隔离性归零,容器能监听宿主机所有接口。

验证模式:

docker exec host-demo ip addr

输出与宿主机 ip addr 完全一致——因为它就是同一套网络栈。适用场景很窄:高吞吐网关类组件、性能实测基线、需要监听宿主机端口的诊断工具。

none:断网隔离

docker run -it --network none alpine sh

容器里只有一个 lo 回环设备,无路由、无 DNS。看似无用,实际两类任务靠它:安全要求极高的离线处理(密钥运算、敏感数据脱敏),以及需要完全自控网络栈的场景(自己在容器里建 wireguard 之类隧道)。

container:共享邻居的栈

docker run -d --name web nginx:alpine docker run -d --network container:web --name sidecar alpine sleep 3600

sidecar 不新建 NET namespace,直接加入 web 的。两个容器同 IP、同端口空间、可通过 lo 互相访问。一个直接推论:sidecar 里起的服务 bind 80 会与 web 的 80 冲突,共享前要规划好端口。这个模式是 Kubernetes Pod 多容器共址的原理前身——Pod 里的容器就是这样共享一个网络栈、彼此 localhost 直达。

选型速查

模式 NET ns IP 性能 适用
bridge 新建 容器私有 IP 有 NAT 损耗 默认选择,绝大多数服务
host 共享宿主机 宿主机 IP 零损耗 网关、高吞吐、性能敏感
none 新建但空 仅 lo 无网络 离线任务、安全隔离
container 共享另一容器 同宿主容器 同容器间零损耗 sidecar 共址

⚠️ 一个高频困惑先在这里拆掉:bridge 模式的容器访问宿主机上的服务,该用什么地址?容器内的 172.17.0.1 是 docker0 在宿主机一侧的地址,所以宿主机服务只要监听在 0.0.0.0 或明确包含 docker0 接口,容器用 172.17.0.1 就能访问到;宿主机服务若只监听 127.0.0.1,容器是够不着的。反过来,宿主机访问容器直接用容器 IP 即可,同宿主的 bridge 容器彼此也是 IP 直连可达(默认网桥上被 iptables 拦截的其实主要是跨网段情形,同网段互通)。

网络模式的选择题,本质是"要不要新建 NET namespace、新建了接到哪"这两问。把 namespace 概念吃透,四种模式不需要背。

本节要点回顾

  • bridge 三件套:docker0 网关、veth 虚拟网线、iptables NAT
  • host 不是快一点的 bridge,是根本不隔离端口空间的另一种世界
  • none 有真实用途:断网是特性不是缺陷
  • container 模式共享一切网络资源,是 Pod 共址的原理
  • 容器访问宿主机服务用 172.17.0.1,且宿主机服务必须监听非回环地址

下一节把 bridge 模式的两件日常事讲透:对外端口映射、对内按名互访。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U