☰
Weave Net 网络中的 IP 地址、路由与子网:从 CIDR 记法到路由表与源码级解析
2026/10/9 2:37:47 网站建设 项目流程
  • 网络
  • 云原生

【免费下载链接】weave

Simple, resilient multi-host containers networking and more.

项目地址:https://gitcode.com/gh_mirrors/weave4/weave
点击查看免费下载

Weave Net 在多个主机之间搭建了一个私有容器网络,容器获得的 IP 地址与公网隔离,因此无需担心与外部地址冲突。本文围绕 Weave Net 的 IP 编址模型展开:先厘清 IP、网络、路由三个基础概念,再解读 Weave Net 使用的 CIDR 记法,然后逐行分析一个真实容器内的路由表,并深入其底层实现(地址类型定义、默认分配范围、重叠检测与 IPAM 机制),最后给出手动指定容器 IP 的三种实战方式。读完本文,你将能够读懂 Weave Net 容器内的任何一条路由,能判断--ipalloc-range是否与宿主机路由冲突,并能按需为容器分配固定 IP。

IP 基础概念:地址、网络与路由

在深入 Weave Net 之前,先统一几个术语(这也是官方文档定义的基础概念):

  • IP(Internet Protocol,互联网协议):全球数十亿联网设备之间通信的基本协议,是网络通信的基础。
  • IP 地址:绝大多数场景下,指用点分隔的四个数字,例如192.168.48.12。每个数字占一个字节(8 位),取值范围是 0~255,因此一个 IPv4 地址恰好是 32 位。
  • 网络(Network):一组彼此知道如何通信的 IP 地址的集合。网络地址是 IP 地址的某个前缀,例如192.168.48。为了标明地址中哪一部分属于网络前缀,会在地址后追加一个斜杠和前缀位数,例如/24,表示前 24 位(即前三个字节)构成网络部分。
  • 路由(Route):一条关于"发往别处的流量该如何处理"的指令——它指定一个网络,以及与该网络通信的途径。每一台使用 IP 的设备都维护着一张路由表,对于任何目的地址,设备都会查表找到匹配的路由,并按表中指示的方向把数据发送出去。

从源码角度看,Weave Net 将上述模型落到了非常直接的实现上:net/address/address.go 中用type Address uint32将整个 IPv4 地址表示为一个 32 位整数(第 10 行),并提供了Range(地址区间,采用[Start, End)半开区间)、CIDR(地址 + 前缀长度)、Add/Subtract/Length等算术辅助类型与方法。ParseCIDR(第 117-126 行)在解析时明确拒绝非 IPv4 地址并返回Non-IPv4 address not supported,说明 Weave Net 的地址核心模型以 IPv4 为准;CIDR.HostRange()(第 154-157 行)则按 RFC 1122 剔除子网的第一个和最后一个地址(网络地址与广播地址),只返回可分配给容器的主机范围。

Weave Net 中的 IP 地址记法:看懂 CIDR 前缀

Weave Net 使用标准的 CIDR(无类域间路由)记法书写地址与子网。以10.4.2.6/8为例:网络前缀是前 8 位,即10,把这个网络完整写出来就是10.0.0.0/8——它覆盖了从10.0.0.0到10.255.255.255的全部地址。

最常见的三种前缀长度是8、16、24,分别对应前 1、2、3 个字节为网络部分,但完全没有理由限制只能用这三种长度:你完全可以使用/9或/26这样的非字节对齐前缀。例如,地址6.250.3.1/9属于6.128.0.0/9网络——因为前 9 位为000001100(十进制前两段是 6.128),而6.250的前 9 位恰好落在这个范围内。

这类地址换算(互联网上有大量 CIDR 计算器可辅助验证)在 Weave Net 中有非常直接的工程意义:

  • --ipalloc-range等参数全部以 CIDR 记法书写,例如--ipalloc-range 10.2.0.0/16表示分配所有以10.2开头的地址;
  • 地址区间与 CIDR 之间的相互转换是 IPAM 的核心操作。在 net/address/address.go 中,Range.CIDRs()(第 77-108 行)把一个任意连续地址区间拆解成一组 CIDR 对齐的连续子网(掩码逐位右移探测,找出能覆盖区间且不过长的最小掩码);CIDR.Range()(第 151-153 行)则把 CIDR 还原为区间。只有当区间大小恰为 2 的幂且起始地址对齐时(AsCIDRString,第 27-36 行)才能无损表达为单个 CIDR,否则就会拆成多个。

阅读一个真实容器的路由表

下面是一张附着到 Weave 网络上的容器内的真实路由表(ip route show输出,摘自官方文档):

# ip route show default via 172.17.42.1 dev eth0 10.2.2.0/24 dev ethwe proto kernel scope link src 10.2.2.1 172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.170

这个容器有两个网络接口:

  • eth0:Docker 分配给它、用于连接 Docker 默认桥接网络的接口,所在网络是172.17.0.0/16;
  • ethwe:Weave Net 为它添加的接口,所在网络是10.2.2.0/24。

路由表如何决定流量的去向?对于目的地址落在172.17.0.0/16或10.2.2.0/24内的数据包,内核会直接沿着对应接口发送(这两条都是proto kernel scope link的直连路由,容器启动时内核根据接口地址自动生成)。对于不匹配任何规则的其他地址,default via 172.17.42.1 dev eth0这条默认路由会把流量交给172.17.42.1,即宿主机的 Docker 桥,由宿主机继续转发。

具体到两个典型场景:

  • 本容器想与地址为10.2.2.9的另一容器通信:查表命中10.2.2.0/24 dev ethwe,数据包从ethwe发出,之后 Weave Net 负责把流量路由到对端主机上的目标容器;
  • 本容器想访问外部服务器74.125.133.128:查表无匹配,走默认路由经eth0交由宿主机处理。

"ethwe" 这个名字并非随意为之,它定义在 net/veth.go 第 109 行:VethName = "ethwe" // name inside container namespace——即容器命名空间内 veth 对一端固定命名为ethwe。而宿主侧的网桥结构(net/bridge.go 第 27-30 行注释)展示了完整拓扑:(container-veth)-+ weave +-(vethwe-bridge)--(vethwe-pcap),即容器内的ethwe连接到宿主机上名为weave的 Linux 网桥,再由vethwe-pcap(或 fastdp 场景下的vethwe-datapath)把报文送入 Weave 的数据通道,实现跨主机的二三层转发。

默认分配范围与主机路由冲突检测

Weave Net 默认把10.32.0.0/12作为自动分配 IP 的地址范围——这是一个 12 位前缀的子网,覆盖从10.32.0.0到10.47.255.255的所有地址。该默认值直接写死在 weave 启动脚本中(第 1154-1155 行:if [ -z "$IPRANGE_SPECIFIED" ] ; then IPRANGE="10.32.0.0/12")。

由于10.32.0.0/12属于私有地址段,如果宿主机自身恰好也在使用重叠的私有路由(例如整体占用10.0.0.0/8),两者就会冲突:内核面对10.32.5.6这样的地址时,将无法确定它属于 Weave 的10.32.0.0/12还是宿主网络的10.0.0.0/8。此时weave launch会给出类似下面的错误:

Network 10.32.0.0/12 overlaps with existing route 10.0.0.0/8 on host. ERROR: Default --ipalloc-range 10.32.0.0/12 overlaps with existing route on host. You must pick another range and set it on all hosts.

这个报错机制与底层实现一一对应:

  • net/route.go 中的CheckNetworkFree(第 13-20 行)遍历宿主全部 IPv4 路由(netlink.RouteList),只要route.Dst与目标子网存在重叠就返回错误,错误文案与上面第一条输出完全一致;overlaps(第 23-25 行)通过"某一网络的起始点是否落在另一网络内"来判断重叠;
  • weave 脚本在启动时调用check_overlap做同样的检查:若默认范围冲突则直接exit 1报错;若用户显式指定的范围冲突则只输出 WARNING(第 1161-1165 行),因为这是用户明知故犯的选择。

处理方式有两种:

  1. 若确信该地址段未被实际使用,可在所有主机上显式传--ipalloc-range强制使用该范围(即使与现有路由重叠);
  2. 更稳妥的做法是换一个不冲突的私有地址段,例如172.30.0.0/16。

无论选哪种,--ipalloc-range必须在所有主机上保持一致,否则各主机会认为彼此管理着不同的地址空间。相关完整讨论见 在特定范围内分配 IP 地址。

地址空间背后的 IPAM 机制

理解了"范围"之后,值得再往下一层看看 Weave Net 如何在这些范围内自动分配地址。机制概述(详见 docs/ipam.md 与 自动 IP 地址管理):

  • 环(Ring)CRDT:Weave Net 把整个分配范围视作一个环,用"令牌(token)"标记每个范围段的起始地址,令牌归属某个 peer,并携带版本号;每个 peer 只能修改自己拥有的令牌,整个环结构始终通过 Gossip 机制整体传播,合并时同一地址的令牌取版本号更高者。每个 peer 在自己拥有的范围段内可以自由分配,用完后再向其他 peer 按权重随机"要空间"。
  • Paxos 初始化:全新集群的环初始状态通过一次性的 basic Paxos 共识建立——参与者在共识值上达成一致(即初始参与分配的各 peer,各自均分地址空间),共识完成后才初始化环。这也是weave launch时--ipalloc-init consensus=参数的原理来源(多数派 = floor(n/2) + 1)。
  • 数据持久化:地址空间在各 peer 间的划分、以及本机容器已获分配的具体地址,会持久化到名为weavedb的数据卷容器内的 BoltDB 文件中(weave 启动脚本第 1186-1191 行会先创建该数据卷容器),peer 重启后立即可用。
  • HTTP 分配接口:每个 peer 上的分配器(allocator)暴露 HTTP 接口供容器基础设施调用,实现在 ipam/http.go:POST /ip/{id}分配默认子网内的地址、POST /ip/{id}/{ip}/{prefixlen}在指定子网内分配、GET /ip/{id}查询、DELETE /ip/{id}释放;weave rmpeer、weave prime分别对应DELETE /peer/{peer}与GET /ring(见 weave 脚本第 1535-1545 行)。

IPAM 默认把分配集中在10.32.0.0/12,但通过--ipalloc-range可换成任意 CIDR 范围,例如:

host1$ weave launch --ipalloc-range 10.2.0.0/16

这里/16的含义与本文前述的 CIDR 记法完全一致:分配器只会给出前 16 位为10.2的容器地址。范围在集群所有主机上共享,并按各 peer 的实际需求动态切分;即使某组 peer 因网络分区与其余部分隔离,也能继续在自己已有的范围内工作,恢复连通后不会产生冲突。

手动指定容器 IP 地址

自动分配保证了全网络唯一,但你完全可以绕过它,为特定容器指定 IP。先说明如何查看自动分配结果:weave ps会列出容器及其分配的地址(格式为容器 ID、MAC、CIDR 地址),例如:

host1$ weave ps a1 a7aee7233393 7a:44:d3:11:10:70 10.32.0.2/12

容器退出后 Weave Net 会自动回收其地址供后续复用。手动指定 IP 的方式取决于容器如何接入 Weave Net(详见 手动指定容器的 IP 地址):

  1. 使用 CNI 时:调用方需指定支持静态 IP 的 IPAM 插件(如 containernetworking 的 static 分配器);截至文档撰写时 Kubernetes 尚无直接指定静态 IP 的简单途径。
  2. 使用 Weave Net Docker 插件时:直接用 Docker 的--ip标志,例如docker run --network=mynetwork --ip=172.18.0.22 ...。
  3. 使用 Weave Net Docker 代理时:通过WEAVE_CIDR环境变量显式给出 CIDR 记法的地址与子网。例如在$HOST1上启动:
host1$ docker run -e WEAVE_CIDR=10.2.1.1/24 -ti weaveworks/ubuntu root@7ca0f6ecf59f:/#

在$HOST2上启动:

host2$ docker run -e WEAVE_CIDR=10.2.1.2/24 -ti weaveworks/ubuntu root@04c4831fafd3:/#

然后验证双向连通:

root@7ca0f6ecf59f:/# ping -c 1 -q 10.2.1.2 PING 10.2.1.2 (10.2.1.2): 48 data bytes --- 10.2.1.2 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max/stddev = 1.048/1.048/1.048/0.000 ms root@04c4831fafd3:/# ping -c 1 -q 10.2.1.1 PING 10.2.1.1 (10.2.1.1): 48 data bytes --- 10.2.1.1 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max/stddev = 1.034/1.034/1.034/0.000 ms

需要强调的约束:手动指定的地址与掩码虽然可以任意设置,但必须避开宿主机正在使用的 IP 范围、外部服务可能访问的地址段,且容器之间的地址必须全局唯一——如果恰好选中了自动分配器已分配的地址,会收到警告提示。

常见问题与排错

  • weave launch报默认范围重叠:宿主机存在与10.32.0.0/12重叠的路由,按本文第 4 节的两种方式处理(显式指定或改选其他私有段)。
  • 多子网/多租户:需要把分配范围拆成多个子网时,配合--ipalloc-range与--ipalloc-default-subnet使用,相关说明见 多子网自动分配;应用隔离场景见 应用隔离。
  • peer 初始化与扩容:--ipalloc-init seed=、--ipalloc-init consensus=、--ipalloc-init observer三种策略的选择与多数派计算,见 自动 IP 地址管理。
  • 查看当前地址占用:weave status会报告本 peer 拥有的地址范围与容器分配情况,排错细节见 IPAM 故障排查。

延伸阅读

  • 自动 IP 地址管理 —— 初始化策略、quorum 与weave prime、weave rmpeer的完整说明
  • 在特定范围内分配 IP 地址 ——--ipalloc-range与重叠检测
  • 手动指定容器的 IP 地址 —— CNI / 插件 / 代理三种方式
  • 多子网自动分配 —— 多 CIDR 场景
  • docs/ipam.md —— 环 CRDT、Paxos 初始化、peer 退出与rmpeer的底层设计
  • 源码:net/address/address.go(地址/区间/CIDR 类型)、net/route.go(重叠检测)、net/veth.go(ethwe命名)、ipam/http.go(分配 HTTP 接口)、weave(启动参数与默认范围)
  • 网络
  • 云原生

【免费下载链接】weave

Simple, resilient multi-host containers networking and more.

项目地址:https://gitcode.com/gh_mirrors/weave4/weave
点击查看免费下载

相关推荐

上一篇:gogcli 实战:用 `gog classroom courses` 命令行管理 Google Classroom 课程全生命周期
下一篇:Querybook 集成 StarRocks:用 SQLAlchemy 查询引擎实现内外部数据的查询与可视化

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询