ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Docker v1.6 网络架构深度解析:libnetwork 诞生前 Engine 与 libcontainer 的协同设计

Docker v1.6 网络架构深度解析:libnetwork 诞生前 Engine 与 libcontainer 的协同设计
  • 容器运行时
  • 云原生

【免费下载链接】docker-ce

:warning: This repository is deprecated and will be archived (Docker CE itself is NOT deprecated) see the https://github.com/docker/docker-ce/blob/master/README.md :warning:

项目地址:https://gitcode.com/gh_mirrors/do/docker-ce
点击查看免费下载

导读:在 libnetwork 出现之前,Docker 的容器网络完全由 Docker Engine 与 libcontainer 两个组件分工完成——前者负责网络栈配置与策略,后者负责设备创建与命名空间装配。本文以 legacy.md 为骨架,结合 docker-ce 仓库内 bridge 驱动与命名空间实现的真实源码,还原这套"前 libnetwork 时代"的单主机网络方案(linux bridge + iptables + NAT 端口映射),并梳理它如何演化为今天的 CNM(Container Network Model)。

1. 背景:一篇 TLD&R 式的历史档案

legacy.md在 libnetwork 文档目录中的定位非常特殊:它并不是 libnetwork 自身的设计文档,而是对 Docker v1.6 时代网络设计的"太长不看版"(TLD&R)速记。该文档开篇就说明:若想了解更详细的运维级设计,需要查阅原始官方文档;它保留在这里的核心意义,正如 design.md 所明确指出的——libnetwork 的诸多设计决策正是从 Docker v1.6 网络设计的学习中获得的灵感。

因此,理解这篇 legacy 文档,就等于理解 libnetwork 诞生的历史动因:一套什么架构、存在什么问题,才催生了后来模块化的容器网络模型。

2. 双组件分工:Engine 负责"策略",libcontainer 负责"装配"

在 libnetwork 之前,Docker 容器网络由两个组件协同完成:

  • Docker Engine(daemon 进程):负责生成并持有容器网络栈的配置——包括选择哪种网络方案、如何分配地址、如何连通容器、如何开放端口。
  • libcontainer(容器运行时库):作为 Engine 的"执行器",读取这份配置,创建必要的网络设备并把它们移入网络命名空间(network namespace)。这个命名空间随后在容器启动时被真正投入使用。

这条调用链的关键在于"配置与执行的分离":Engine 只做抽象层面的网络规划,libcontainer 只做内核层面的网络对象装配。两者的交界处就是一份网络配置描述——它决定了 veth 对、地址、路由最终以什么形态出现在容器的隔离网络栈里。

3. Engine 侧:Bridge Driver、linux bridge 与 iptables

legacy 文档明确指出,Docker Engine 借助Bridge Driver提供单主机(single-host)网络方案,底层依赖两样东西:

  • linux bridge:一个内核级二层交换机,把所有接入同一主机网络的容器虚拟网卡桥接在同一个二层域内;
  • iptables:负责三类关键工作——容器间隔离(filter 表)、出站流量的地址伪装(nat 表 MASQUERADE)、入站流量的端口转发(nat 表 DNAT)。

这套机制的雏形在今天的 libnetwork bridge 驱动源码中依然可以精确对上号:

  • 默认网桥名docker0定义于 drivers/bridge/interface.go(DefaultBridgeName = "docker0");
  • iptables 侧的DOCKER链(nat 与 filter 两张表)、用于桥接网络间隔离的DOCKER-ISOLATION-STAGE-1/STAGE-2链,全部创建于 drivers/bridge/setup_ip_tables.go;
  • 出站 NAT 规则的本质见 setup_ip_tables.go:当配置了HostIP时使用显式SNAT --to-source,否则退化为MASQUERADE——让内核依据路由表自动挑选出口地址。

如上图(摘自 network.md 的 bridge 模式流程示意)所示,这套拓扑正是 legacy 文档所描述的架构的完整落地形态:容器被装入独立的网络命名空间,一端 veth 挂到宿主机docker0,另一端进容器;容器获得docker0子网内地址并以docker0为默认网关;出站流量经 POSTROUTING 链 MASQUERADE 伪装,入站则靠 DOCKER nat 链 DNAT 到容器地址。

4. 面向用户的抽象:--link、--expose与"完全透明"

legacy 文档强调了一个非常重要的设计取向:Docker Engine 通过--link、--expose这类简单配置让同一主机内的容器互相连通,把网络配置完全从容器视角中抽象掉——容器本身不需要关心自己的 IP、网关、路由,一切由 Engine 在背后打理。

  • --expose:声明容器内部的服务端口,为后续端口映射做准备;
  • --link:在两个容器间建立"链接"关系,通过容器名/别名在目标容器的网络栈中注入对方的连接信息,实现同主机内容器互联;
  • 端口映射(port mapping):把容器内端口映射到宿主机端口,供外部访问。

值得注意的一个细节:legacy 链接(--link)在今天已是"历史特性",仓库源码明确标注其适用范围被严格限制。见 daemon/container_operations.go 的注释:"Legacy Link 特性仅支持默认 bridge 网络;Legacy Link 只能通过docker run --link使用"。也就是说,--link从诞生起就与默认 bridge(docker0)网络深度绑定,属于单主机、单默认网络的产物——这也是多主机时代它迅速让位于自定义网络与服务发现的原因。

5. 外部连通性:NAT 与端口映射

单主机模式下,容器的 IP 是网桥子网内的私有地址,天然不可被外部访问。legacy 文档指出,外部连通性完全依赖 NAT(网络地址转换)与端口映射(Port-mapping):

  • 出站:容器访问外网时,流量在路由后被 MASQUERADE 规则改写源地址为宿主机出口接口的 IP;
  • 入站:宿主机上监听特定端口(publishedPort),命中该端口的流量经 DNAT 规则改写目的地址/端口,转发到容器内部的监听端口(targetPort)。

这套"私有子网 + 双 NAT"的模式在源码中同样可以溯源:DNAT 规则被编程进DOCKER(nat 表)链,而接受转发的规则进入DOCKER(filter 表)链,端口映射的宿主端绑定信息由OptionPortMapping传入,相关逻辑集中在 drivers/bridge/port_mapping.go 与 daemon 侧 container_operations.go。

局限性也随之而来:这套方案本质上是"单主机 + 网桥 + 伪装"的组合,端口映射是宿主机粒度的——集群中多个节点、多副本服务之间的负载均衡与跨主机寻址,它完全无能为力。这为后面 swarm/overlay 模式(同样由 iptables、独立网桥与 VXLAN 组合实现,见 network.md)以及 libnetwork 的模块化架构埋下了伏笔。

6. libcontainer 侧:设备创建与网络命名空间

legacy 文档勾勒了执行侧的职责:libcontainer 依据 Engine 提供的配置,创建必要的网络设备,并把这些设备移入网络命名空间;该命名空间在容器启动时被使用。

这里的核心概念是network namespace——Linux 内核的隔离机制,让每个容器拥有独立的网络栈视图(接口、路由表、iptables 规则、DNS 配置互不影响)。

这套"为容器建立隔离网络栈"的思想在 libnetwork 中被完整继承并抽象为Sandbox概念。在 design.md 中 Sandbox 被明确定义为"容器网络栈配置的载体,包含接口、路由表与 DNS 设置的托管"。其 Linux 实现直接落在命名空间层面:libnetwork 的networkNamespace类型注释明确写着——"是 Sandbox 接口的 linux 实现,代表一个 linux 网络命名空间",每个 sandbox 通过宿主文件系统上的唯一路径标识,接口在命名空间间的移动与路由表管理依赖 netlink 调用。见 libnetwork/osl/namespace_linux.go(命名空间基路径默认挂载于/var/run/docker/netns)。

从源码结构可以推断:legacy 时代"libcontainer 装配命名空间"的执行模式,正是后来 libnetwork 中 osl(Operative System Layer,操作系统层抽象)与 sandbox 机制的原始形态——职责相同,只是从"单一运行时库的职责"升级为"可插拔网络模型的标准构件"。

7. 传承与演进:从 v1.6 架构到 Container Network Model

legacy.md 不是一篇孤立的历史档案,它与 libnetwork 的现代架构构成直接的因果链条:

  1. 问题驱动:v1.6 架构把"网络策略(Engine)"与"网络实现(bridge/iptables)"耦合在一起,驱动能力不可插拔,多主机场景无从扩展;
  2. 目标:libnetwork 追求 Docker 与 Linux 的哲学——小而模块化、可独立工作、可组合,将容器网络变为可满足的"可组合需求";
  3. 产出:Container Network Model(CNM),用Sandbox / Endpoint / Network三个构件与 NetworkController、Driver 两类对象,把 legacy 架构中隐式的分工显式化、插件化。

如上图所示,CNM 的核心抽象可以看作 legacy 架构的"理论化重建":

legacy(Docker v1.6)CNM / libnetwork关系
libcontainer 移入容器网络命名空间Sandbox命名空间实现成为 Sandbox 的一种具体实现(Linux netns)
veth 对 + 网桥端口Endpoint端点被抽象为"服务接入点",可先于容器创建
docker0 网桥(linux bridge)Network网桥成为 Network 的一种驱动实现(bridge driver)
Engine 内嵌的网络逻辑Driver(null / bridge / overlay / remote)可插拔、可远程承载
daemon 的 CreateNetwork 流程NetworkController.NewNetwork()见 daemon/network.go 的调用链

其中"Endpoint 先于容器存在"的设定值得一提:CNM 生命周期文档(design.md)解释了为什么要CreateEndpoint与Join两步——因为 Endpoint 代表的是服务而非某个具体容器,创建时即保留资源,任何容器随后接入都能获得一致的网络行为。这与 legacy 时代"容器即网络单元"的朴素模型形成了清晰的分层进步。

8. 结语:历史文档的当代阅读价值

legacy.md只有十几行,却是理解 docker-ce 网络体系的关键钥匙:

  • 它是设计源头:libnetwork 的 CNM 决策直接受其启发(design.md 开篇即引用);
  • 它是概念索引:linux bridge、iptables、NAT、端口映射、网络命名空间这五个词,几乎概括了 Docker 单主机网络的全部物理机制,而这些机制至今仍是 bridge 驱动与 swarm ingress 的底层事实(对照 drivers/bridge 目录与 network.md 即可验证);
  • 它是演进参照系:只有先看懂"Engine + libcontainer 的紧密耦合",才能真正理解 CNM 的 Sandbox / Endpoint / Network 三分模型与驱动插件化设计"解耦了什么、抽象了什么、增强了什么"。

若想继续深入,建议按此顺序阅读仓库内文档:design.md(CNM 完整设计)→ bridge.md(bridge 驱动)→ network.md(bridge 与 overlay 模式数据流)→ overlay.md(跨主机实现)。对照源码时,优先阅读 drivers/bridge/ 下的interface.go、setup_ip_tables.go、port_mapping.go,以及 libnetwork/osl/ 的命名空间实现,即可把这篇历史档案的每一句话还原成可运行的内核行为。

  • 容器运行时
  • 云原生

【免费下载链接】docker-ce

:warning: This repository is deprecated and will be archived (Docker CE itself is NOT deprecated) see the https://github.com/docker/docker-ce/blob/master/README.md :warning:

项目地址:https://gitcode.com/gh_mirrors/do/docker-ce
点击查看免费下载

相关推荐

上一篇:告别权限管理混乱:Accompanist权限组件的终极集成指南
下一篇:kube-bench完全指南:基于CIS基准的Kubernetes安全检测工具终极解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进