bigywater.tech
Docker · 58

手动搭一个网络命名空间:ip netns 与 veth 复刻 bridge

容器里的 eth0 在宿主机上对应什么?veth 是什么?这篇从 /sys/class/net 的 ifindex 与 iflink 出发,找到容器网卡在虚拟机里的另一端,验证两端流量一致,再手动造一对 veth。

eth0@if2364
容器 eth0 的对端编号 = 虚拟机里 veth8554796 的 ifindex
10504 = 10504
容器 eth0 发送增量与虚拟机 veth 接收增量
ping 3/3
手动搭的 v0 / v1 两个命名空间之间的连通性

找到另一端

实测 · 本机执行输出
  容器里 eth0:ifindex = 11,iflink = 2364(iflink 是对端设备的编号)
  容器里 ip link:eth0@if2364:
  虚拟机里 ifindex = 2364 的设备:veth8554796 ifindex=2364 iflink=11
  它的类型:veth;它挂在哪个网桥上(master):docker0
  容器主进程在虚拟机里的 PID 98747:它的 net 命名空间 = net:[4026534595]

每个 veth 设备的 iflink 是对端的 ifindex。容器 eth0 的 iflink 是 2364,虚拟机里 ifindex 为 2364 的是 veth8554796,它的 iflink 又指回 11。这个 veth 挂在 docker0 网桥下(master)。

同一份流量

实测 · 本机执行输出
  容器 eth0 发送增量 10504 字节;虚拟机 veth8554796 接收增量 10504 字节(ping 10 个 1000 字节负载的包,两个增量相同)

容器的 tx_bytes 和虚拟机端的 rx_bytes 增量完全一样,因为它们是同一根线的两头。

自己造

实测 · 本机执行输出
  v0:ifindex=12 iflink=11;v1:ifindex=11 iflink=12
  3 packets transmitted, 3 packets received, 0% packet loss
  round-trip min/avg/max = 0.059/0.085/0.133 ms
  blue (id: 1)
  10.77.0.0/24 dev v1 proto kernel scope link src 10.77.0.2

用 iproute2 在特权容器里建了命名空间 blue 和一对 veth,配上地址后互相 ping 通。这些都在那个特权容器自己的网络命名空间里,容器退出后一并消失,没有碰虚拟机的网络。iproute2 是我在镜像里 apk add 装的(busybox 的 ip 不支持把 veth 一端放进命名空间)。

分步演示

veth 与网络命名空间
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。ifindex / iflink / 计数器读自 /sys/class/net;虚拟机侧用特权容器加 nsenter 读取(方法见 c19);手动 veth 实验用 apk 装了 iproute2 的 alpine 镜像,在特权容器自己的网络命名空间里完成;设备编号每次运行都不同,文中取自最后一次运行;实验后已删除容器和镜像
    • 没有验证:Linux 宿主机上同样的对应关系、macvlan / ipvlan、veth 的 offload 与性能、网桥上的 MAC 学习与转发表、多网卡容器的第二对 veth(见 c46)
    京ICP备2026067502号-1京公网安备11010502063487号