← 全部笔记

Docker · 5 容器网络

bridge 网络:
隔离之后,怎样连通?

网络命名空间分开各自的接口与路由;veth 对跨过边界;docker0 把主机侧的端点接到同一网桥。

约 15 分钟 · 截至 2026-11-03,Docker Engine 29.x · 实验未实测

图示范围:原生 Linux、以 root 运行的 Docker 守护进程、默认 IPv4 bridge。虚线表示网络命名空间边界;接口名为示意。

两个容器通过各自的 veth 对连接到 docker0 容器 A 和 B 各有网络命名空间与 eth0。每个 eth0 都是 veth 对的一端,另一端在主机网络命名空间,接入 docker0 网桥。容器命名空间同样属于这台 Linux 主机。 容器 A · netns容器 B · netns 自己的 lo、路由自己的 lo、路由 主机网络命名空间 veth 对veth 对 eth0eth0 veth-Aveth-B docker0 · 软件网桥
图 1 每个容器有一对跨边界的接口,主机端共同接入 docker0。

模型 · 各做一件事

隔离后再连通

容器共享内核,但可以有独立的网络视图。忘了这个前提,可以先回看容器和虚拟机的区别。

网络命名空间(network namespace,netns)隔离网络接口、IP 路由表和端口等资源。lo 是本地回环接口;A 里的 127.0.0.1 指向 A 自己。A、B 都叫 eth0,也不代表它们是同一个接口。[1]

A 和 B 都有 eth0。A 访问 127.0.0.1:80,能到 B 的 Web 服务吗?先解释你的判断。

不能。A 的回环地址属于 A 的网络命名空间,包不会因此进入 veth。访问 B 要使用 B 的可达 IP;如果 B 只监听自己的回环地址,A 也无法经 B 的 eth0 访问它。

虚拟以太网设备(virtual Ethernet,veth)总是成对创建。从一端发出的包会在另一端收到。Docker 把一端放入容器,通常命名为 eth0;主机端常见名字以 veth 开头。单个端点属于一个命名空间。[2]

网桥(bridge)按以太网帧的目标 MAC 地址转发。MAC 是接口的链路层地址;帧是链路上传输的单位,里面可承载 IP 包。默认网络在 Docker 里叫 bridge,对应的 Linux 网桥通常叫 docker0。主机侧 veth 接入它;主机的物理网卡通常不直接接入它。[3]

同桥通信:A eth0 → A 的主机端 veth → docker0 → B 的主机端 veth → B eth0

在默认允许容器互通的配置下,同桥容器可以直接用 IP 通信;这条路径不需要把源 IP 换成主机 IP。网桥负责同一链路内的转发,出网还需要主机路由。

沿图 1 回忆:跨两个命名空间的是哪一对接口?主机侧端点接在哪个网桥?

跨边界:;网桥名:。

veth 对负责跨边界传递包,docker0 连接主机侧的多个端点。Docker 网络对象名 bridge 与 Linux 接口名 docker0 要分开记。

动手 · 从输出还原图

三组命令对照

先看接口,再找地址,最后把 Docker 的网络配置对应回去。ip link 查看接口与连接关系;ip addr 查看接口地址;docker network inspect 查看 Docker 记录的网络详情。[4] [5]

未实测

编写环境没有 Docker。以下为待你运行的实验命令与预期观察,未提供冒充实测的输出。维护者需补 Docker Engine 29.x 的实测记录;IP、接口索引和名称以你的机器为准。

运行位置:原生 Linux 的 Docker 主机,使用本地、以 root 运行的守护进程。主机需装 iproute2,并能执行 Docker 命令。Docker Desktop 和 rootless 环境先看适用边界。

会改动什么:启动容器会由 Docker 临时创建网络命名空间、veth 并接入默认网桥;镜像不存在时会下载。这里不手改宿主机的路由、防火墙或网络设置,不需要 --privileged。实验会访问外网,清理时只停止本实验容器。

1. 留一个容器供观察

docker run --rm -d --name lp-bridge-24 --network bridge alpine:3.22 sleep 1800

预期输出(未实测):-d 会返回容器 ID;若需拉取镜像,还会出现拉取进度。容器最多保留 30 分钟,退出后由 --rm 删除。[6]

2. 看容器端,再找主机端

docker exec lp-bridge-24 ip link
docker exec lp-bridge-24 ip addr
docker exec lp-bridge-24 ip route
docker exec lp-bridge-24 cat /sys/class/net/eth0/iflink
ip link show docker0
ip link show master docker0
ip addr show docker0

预期观察(未实测):容器通常列出 lo、eth0;eth0 有 IPv4 地址,路由表有经网关的默认路由。主机上能看到 docker0 与接入它的 veth。容器内的 BusyBox ip 与主机 iproute2 的排版可能不同。

iflink 在这里给出 eth0 的对端接口索引。在主机 ip link show master docker0 的结果中,找行首相同的数字;那就是这一个容器对应的主机端 veth。不要只凭名字猜,也不要把容器自己的接口索引当成对端索引。[7]

3. 用网络对象校验

docker network inspect bridge
输出对照清单(观察目标,未实测)
你找的字段应当对应什么
Name / Driver网络名 bridge / 驱动 bridge;二者含义不同。
IPAM.Config 的 Subnet、Gateway地址分配配置中的子网、网关。默认设置下,Gateway 对应 docker0 的 IPv4 地址与容器默认路由的下一跳。
Containers 中的 lp-bridge-24IPv4Address 对应容器 eth0 的地址与前缀。不要把它当成 docker0 的地址。
主机接口里的 master docker0该接口接入 docker0 网桥;master 这里指所属网桥,并非容器名。

IPAM 指 IP 地址管理(IP Address Management)。子网和地址可以配置,因此不要硬背某个 172.17.* 地址。network inspect 也不会替你列出完整 veth 配对;它要与 ip link 合看。

不抄整段输出:记录自己的“容器 IP → 主机端 veth → docker0 网关”三项证据,并解释它们如何对应。

容器 ip addr 中的 eth0 地址应与 inspect 中该容器的 IPv4Address 对应。eth0 的 iflink 应对应某个接入 docker0 的主机接口索引。默认路由的网关应与 inspect 的 Gateway、docker0 地址对应。

  • 区分容器地址与网关地址
  • 通过对端索引找到 veth,而非猜名字
  • 把 Docker 网络对象与 Linux 接口对应起来

你想找到实验容器的主机侧接口。哪组证据最直接?

主机可能运行多个容器,列出的第一个 veth 没有身份保证。

网关是下一跳,容器有自己的 IP;两者在正常配置下不同。

iflink 把容器 eth0 指向它的 veth 对端。再确认该主机接口属于 docker0,就能把图 1 的跨边界连接落到具体接口上。

机制 · 走出容器子网

出站会换源

默认 IPv4 bridge 通过主机转发并做地址伪装,让容器访问外部网络。地址转换(Network Address Translation,NAT)改写包的地址;这里的源 NAT 把源 IP 从容器地址换成主机出站接口地址。地址伪装(masquerading)是按出站接口地址选择源 IP 的一种做法。[8]

图中用 A 表示容器 IP,H 表示主机出站 IP,R 表示外部服务 IP。这些是符号,不是抓包值;端口、MAC、上游路由器在图中省略。

容器出站与回包的六步路径 A 发往 R,经过 eth0、veth、docker0、主机路由与源 NAT,源地址变为 H。R 的回包发往 H,主机依据连接跟踪把目标还原为 A,经网桥和 veth 送回容器。 容器 netns 应用 → eth0 · 地址 A 主机 netns 主机侧 veth docker0 · 网关入口 主机路由 + 源 NAT 主机出站接口地址 H 外部服务 R 源 A → 目标 R 发送 经网桥 交网关 源 H → 目标 R 回包:R → H 还原为 R → A
  1. 应用要访问子网外的 R:初始 IP 包是“源 A,目标 R”。预测:它的下一跳是 R 本身,还是容器的默认网关?
  2. 容器路由选择默认网关。包从 eth0 发出,经 veth 对到达主机侧端点。
  3. docker0 将发往网关的帧交给主机网络栈。源 IP 仍是 A。
  4. 主机路由选择出站接口;转发规则需要允许这条流量。此处仍需经过主机防火墙。
  5. 离开主机时,masquerading 把源 A 换成 H,目标仍为 R。预测:R 的回包先发给谁?主机怎样知道要送回 A?
  6. 回包先发往 H。主机用连接跟踪记录,把回包目标还原为 A,再经 docker0、veth、eth0 送回容器。右侧箭头概括同一路径的反向传输。
图 2 源 IP 在主机出站 NAT 处改变,回包依据已有连接的记录反向转换。

连接跟踪(connection tracking)是内核对连接及其转换关系的记录。端口也可能被改写,用于区分连接。H 若是局域网地址,上游路由器还可能再做一次 NAT,外部服务最终看到的地址就可能是路由器的公网 IP。[8] [9]

不写 -p,容器能主动访问外网吗?外网机器能因此随时新建一条连接,直达容器任意端口吗?

在本页默认网络条件下,容器可以主动出站,不依赖 -p。回包属于已有连接,能按连接跟踪送回。外部机器主动发起的新连接没有这份转换关系;它需要端口发布等明确的访问配置。

继续实验:验证可达,再清理

docker exec lp-bridge-24 wget -T 10 -qO- http://example.com
docker stop lp-bridge-24

预期输出(未实测):网络和域名解析正常、外部站点可用时,wget 输出网页内容;stop 返回容器名,随后 --rm 清除容器及其网络端点,已下载镜像保留。请求失败也请运行清理命令。

网页请求成功只验证了可达,不能单独证明 NAT 的具体改写值。若失败,先分清域名解析、默认路由、主机转发、防火墙及站点是否可用;不要直接归因于 veth。这里的明文 HTTP 只用于获取公开示例网页。

深入一点:为什么不手写一条 MASQUERADE 规则?

Docker 管理 bridge 所需的过滤和 NAT 规则。Engine 29.x 默认使用 iptables,也可选择 nftables 后端;规则和链名不应当成为理解路径的前提。不要删除或手动覆盖 Docker 创建的规则。这里未提供修改防火墙、开启转发或重启守护进程的操作。[9]

边界 · 先确认你在哪里

先认运行环境

图里的“主机”指运行 Docker Engine 的 Linux 系统。你的终端所在系统,可能只是连接它的客户端。

同一条命令,观察位置可能不同
环境怎样解释 docker0
原生 Linux,rootful本页实验的直接适用场景;主机 ip 命令可查看网桥和 veth。
Docker DesktopLinux 容器的网桥位于 Desktop 的 Linux 虚拟机内;桌面系统看不到同一套接口。不要为了找 docker0 而修改桌面网络。[10]
rootless 模式守护进程本身也以非 root 身份运行;网络视图、出站实现与这里的初始主机命名空间模型不同。不要据此断定“没有网络”。[11]
远程 Docker context(客户端连接配置)docker 命令查询远端 Engine;本地 ip 命令查看本机。应在远端 Linux 主机观察接口。
深入一点:bridge 名字相同,就有自动 DNS 吗?

bridge 既是驱动名,也是默认网络名。默认 bridge 不提供自定义 bridge 那样的容器名自动解析。本页仅按 IP 理解通信;“按名字访问”和应用隔离留给下一页自定义网络。生产应用通常应使用自定义网络。[3]

把现象归到正确的观察位置。先点条目,再点类别。

  • 容器 A 的 lo 和 eth0
  • docker0 和主机侧 veth
  • docker exec 读出的默认路由
  • Desktop 的 Linux 容器网桥
容器 netns
原生 Linux 主机 netns
Desktop 的 Linux 虚拟机内

先定位命令读的是谁的网络视图,再判断有没有接口。虚拟机、命名空间和远程连接都会改变观察位置。

检索 · 合上图再回答

自测与来源

按本页的默认 IPv4 模型,A 主动访问外部 R。哪项正确?

同桥通信通常保留容器源 IP。网桥转发与出站 NAT 是不同环节。

-p 用于发布服务端口。主动出站的回包利用已有连接记录返回。

A → R 离开主机时变成 H → R;R → H 返回后还原为 R → A。docker0 和 veth 提供路径,主机路由选择出口,NAT 与连接跟踪完成地址改写及还原。

下面是本页事实与命令的来源。Docker 行为按 2026-11-03 的官方文档核对,讨论范围为 Docker Engine 29.x;实验仍待实测。

  1. Linux man-pages:network_namespaces(7) — 隔离资源与命名空间边界。
  2. Linux man-pages:veth(4) — 成对接口与跨命名空间传递。
  3. Docker:Bridge network driver — 默认 bridge、互通、网关和自定义网络差别。
  4. ip-link(8)、ip-address(8) — Linux 接口与地址查询。
  5. Docker:docker network inspect — 网络详情和 JSON 输出。
  6. Docker:docker run、Alpine 官方镜像 — 容器运行选项和 3.22 标签。
  7. Docker:Port publishing and mapping — 出站 masquerading 与入站端口发布。
  8. Docker:Packet filtering and firewalls、Docker with iptables — bridge 的过滤、转发、NAT 与连接跟踪。
  9. Docker Desktop:Networking — 虚拟机与桌面系统的网络边界。
  10. Docker:Rootless mode — 非 root 守护进程的适用边界。