几种通过 iproute2 来打通不同节点间容器网络的方式

几种通过 iproute2 来打通不同节点间容器网络的方式

背景

之前由于需要打通不同节点间的容器网络,对 flannel 进行修改增加了网络相关信息的获取逻辑,进而可以完整使用 backend 的功能。

最近想拿掉这个 flannel,所以分析一下 backend 的功能,使用 ip 命令来进行模拟

flannelbackend 提供了 7 种类型,这里只对以下 3 种内核提供的功能作模拟

  • host-gw
  • ipip
  • vxlan

环境

容器使用网络命名空间隔离网络相关资源,为了操作简单直接使用网络命名空间作为测试环境。

vm1(192.168.32.245) 和 vm2(192.168.32.246) 是物理机上的两个虚拟机,操作系统为 CentOS 7.2。

目标为将 172.245.0.0/24 和 172.246.0.0/24 网段打通。

┌─────────────────────────────┐          ┌─────────────────────────────┐
│ vm1 │ │ vm2 │
│ ┌─────────────────┐ │ │ ┌─────────────────┐ │
│ │ ns245 │ │ │ │ ns246 │ │
│ │ 172.245.0.2 │ │ │ │ 172.246.0.2 │ │
│ │ eth0 │ │ │ │ eth0 │ │
│ └────────|────────┘ │ │ └────────|────────┘ │
│ │ │ │ │ │
│ veth245 │ │ veth246 │
│ │ │ │ │ │
│ br245 │ │ br246 │
│ 172.245.0.1/24 │ │ 172.246.0.1/24 │
│ │ │ │
│ │ │ │
│ 192.168.32.245/24 │ │ 192.168.32.246/24 │
│ eth0 │ │ eth0 │
└──────────────│──────────────┘ └──────────────│──────────────┘
│ │
└────────────────────────────────────────┘

环境配置

需要打开 ip_forward 选项,让流量能够通过网桥进入命名空间

sysctl -w net.ipv4.ip_forward=1

设置网桥

# 创建网桥
ip link add br245 type bridge # 启用网桥
ip link set br245 up

创建命名空间、设置虚拟网卡

# 创建网络命名空间
ip netns add ns245 # 创建 veth-peer,并且一端设置在 netns 中
ip link add veth245 type veth peer name eth0 netns ns245 # 启用 netns 中的 veth-peer
ip netns exec ns245 ip link set eth0 up # 启用 host 中的 veth-peer
ip link set veth245 up # 将 host 中的 veth-peer 挂载到 br245 网桥上
ip link set veth245 master br245

设置网卡地址和路由

# 设置网桥地址
ip addr add 172.245.0.1/24 dev br245 # 设置命名空间内的 veth-peer 地址
ip netns exec ns245 ip addr add 172.245.0.2/24 dev eth0 # 设置命名空间内的默认路由(新建容器也会存在一条这个默认路由)
ip netns exec ns245 ip route add default via 172.245.0.1 dev eth0

vm2 的设置只需将 245 替换为 246 即可

设置完成后,vm1 的网卡、地址和路由信息如下(略去无关网卡)

$ ip addr
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:ce:51:a5 brd ff:ff:ff:ff:ff:ff
inet 192.168.32.245/24 brd 192.168.32.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fece:51a5/64 scope link
valid_lft forever preferred_lft forever
9: br245: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 02:8d:b1:91:fa:7a brd ff:ff:ff:ff:ff:ff
inet6 fe80::7426:b5ff:fea9:d35/64 scope link
valid_lft forever preferred_lft forever
10: veth245@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br245 state UP group default qlen 1000
link/ether 02:8d:b1:91:fa:7a brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::8d:b1ff:fe91:fa7a/64 scope link
valid_lft forever preferred_lft forever $ ip route
default via 192.168.32.1 dev eth0 proto static metric 100
172.245.0.0/24 dev br245 proto kernel scope link src 172.245.0.1
192.168.32.0/24 dev eth0 proto kernel scope link src 192.168.32.245 metric 100 $ ip netns exec ns245 ip addr
2: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether be:9c:d4:57:58:5a brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.245.0.2/24 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::bc9c:d4ff:fe57:585a/64 scope link
valid_lft forever preferred_lft forever $ ip netns exec ns245 ip route
default via 172.245.0.1 dev eth0
172.245.0.0/24 dev eth0 proto kernel scope link src 172.245.0.2

host-gw

只需要在 vm 中设置一条指向对方的路由即可

# vm1
ip route add 172.246.0.0/24 via 192.168.32.246 dev eth0 onlink # vm2
ip route add 172.245.0.0/24 via 192.168.32.245 dev eth0 onlink

在命名空间内测试 172.246.0.2 是否能通

$ ip netns exec ns245 ping -c 1 172.246.0.2
PING 172.246.0.2 (172.246.0.2) 56(84) bytes of data.
64 bytes from 172.246.0.2: icmp_seq=1 ttl=62 time=0.656 ms --- 172.246.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.656/0.656/0.656/0.000 ms

从 172.245.0.2 访问 172.246.0.2 的时序图如下(回包方向逻辑一致)

172.245.0.2  ns245:eth0   br245       vm1:eth0    vm2:eth0        br246    ns246:eth0    172.246.0.2
| | | | | | | |
| default | | | | | | |
| routing | | | | | | |
| --------> | | | | | | |
| | veth-peer | | | | | |
| | master | | | | | |
| | --------> | | | | | |
| | | 172.246.0.2 | | | | |
| | | routing | | | | |
| | | ----------> | | | | |
| | | | layer 2 | | | |
| | | | --------> | | | |
| | | | | 172.246.0.2 | | |
| | | | | routing | | |
| | | | | ----------> | | |
| | | | | | master | |
| | | | | | veth-peer | |
| | | | | | --------> | |
| | | | | | | 172.246.0.2 |
| | | | | | | ----------> |
| | | | | | | |
172.245.0.2 ns245:eth0 br245 vm1:eth0 vm2:eth0 br246 ns246:eth0 172.246.0.2

Q&A

Q: 为何 host-gw 模式下的容器所在宿主机必须在同一网段(二层互通)

A: 路由不会修改源IP,回包交换源目的 IP 后,网关查询路由表不能确定发包接口,二层互通不存在这个问题,不需要查询路由表,直接根据 MAC 地址选路

ipip

IPIP(IP-in-IP)协议是一种网络层隧道协议,用于在一个IP网络上传输另一个IP数据包。IPIP协议的主要目的是在网络之间提供透明的通信通道,使得内部网络的数据包可以通过外部网络传输,而不需要改变数据包的内容。

协议格式如下

// 原始 TCP 数据包
+--------------------------------+
| .... |
+--------------------------------+
| TCP |
+--------------------------------+
| IP |
+--------------------------------+
| Ethernet |
+--------------------------------+ // ipip 封装后的数据包
+----------------------------------------+
| .... |
+----------------------------------------+
| TCP |
+----------------------------------------+
| IP |
+----------------------------------------+
/ IP (tunnel) /
+----------------------------------------+
| Ethernet |
+----------------------------------------+

在 vm1 中设置 ipip 隧道

# 创建 IPIP 隧道接口
ip tunnel add tun245 mode ipip local 192.168.32.245 remote 192.168.32.246 # 配置 IPIP 隧道接口的 IP 地址
ip addr add 172.245.1.1/30 dev tun245 # 启用 IPIP 隧道接口
ip link set tun245 up # 添加路由,使 172.246.0.0/24 网段的数据包通过 IPIP 隧道传输
ip route add 172.246.0.0/24 via 172.245.1.2 dev tun245

在 vm2 中访问 172.245.0.2 (增加访问 192.168.32.245 进行对比)

$ ping -c 1 192.168.32.245
$ ip netns exec ns246 ping -c 1 172.245.0.2

在 vm1 中对 eth0 进行抓包

$ tcpdump -s0 -i eth0 host 192.168.32.246  -nn
11:28:01.268176 IP 192.168.32.246 > 192.168.32.245: ICMP echo request, id 1730, seq 1, length 64
11:28:01.268299 IP 192.168.32.245 > 192.168.32.246: ICMP echo reply, id 1730, seq 1, length 64
11:28:08.697558 IP 192.168.32.246 > 192.168.32.245: IP 172.246.0.2 > 172.245.0.2: ICMP echo request, id 1708, seq 26, length 64 (ipip-proto-4)
11:28:08.697760 IP 192.168.32.245 > 192.168.32.246: IP 172.245.0.2 > 172.246.0.2: ICMP echo reply, id 1708, seq 26, length 64 (ipip-proto-4)

在 wireshark 更直观的看到 ipip 多了一层 ip,用来作为隧道通信。

Frame 3: 118 bytes on wire (944 bits), 118 bytes captured (944 bits)
Ethernet II, Src: 52:54:00:b9:5d:53 (52:54:00:b9:5d:53), Dst: 52:54:00:ce:51:a5 (52:54:00:ce:51:a5)
Internet Protocol Version 4, Src: 192.168.32.246, Dst: 192.168.32.245
Internet Protocol Version 4, Src: 172.246.0.2, Dst: 172.245.0.2
Internet Control Message Protocol

从 172.245.0.2 访问 172.246.0.2 的时序图如下(省略命名空间内的部分,回包方向逻辑一致)

br245        tun245      vm1:eth0    vm2:eth0      tun246         br246
| | | | | |
| 172.246.0.2 | | | | |
| routing | | | | |
| ----------> | | | | |
| | ipip pack | | | |
| | --------> | | | |
| | | layer 2 | | |
| | | --------> | | |
| | | | ipip unpack | |
| | | | ----------> | |
| | | | | 172.246.0.2 |
| | | | | routing |
| | | | | ----------> |
| | | | | |
br245 tun245 vm1:eth0 vm2:eth0 tun246 br246

Q&A

Q: 和 host-gw 最大的区别是什么

A: 对容器(网络命名空间)所在节点的网络不再限制二层互通,只要节点网络(二层、三层)互通即可。

vxlan

vxlan 旨在解决大型云数据中心和多租户环境中传统 vlan(虚拟局域网)技术的局限性。通过在 UDP 之上封装第二层以太网帧,实现在第三层(IP)网络上的二层网络扩展,从而允许创建多达 1600 万个隔离的虚拟网络,远超 vlan 的4096 个网络限制。

协议格式如下

// 原始 TCP 数据包
+----------------------------------------+
| .... |
+----------------------------------------+
| TCP |
+----------------------------------------+
| IP |
+----------------------------------------+
| Ethernet |
+----------------------------------------+ // vxlan 封装后的数据包
+----------------------------------------+
| .... |
+----------------------------------------+
| TCP |
+----------------------------------------+
| IP |
+----------------------------------------+
| Ethernet |
+----------------------------------------+
/ VXLAN Header (8 bytes) /
+----------------------------------------+
/ UDP (tunnel) /
+----------------------------------------+
/ IP (tunnel) /
+----------------------------------------+
/ Ethernet (tunnel) /
+----------------------------------------+

在 vm1 中设置

# 创建 VXLAN 隧道接口
ip link add vtep245 type vxlan id 1 local 192.168.32.245 dev eth0 dstport 8472 nolearning # 配置 IP
ip addr add 172.245.0.0/32 dev vtep245 # 设置 MTU
ip link set vtep245 mtu 1450 # 启动 vtep
ip link set veth245 up # 配置路由
ip route add 172.246.0.0/24 via 172.246.0.0 dev vtep245 onlink

vm2 中配置和 vm1 中相反,245 和 246 需要互换

查看虚拟网卡,看到设置的 vxlan id、网卡和本地 ip

root@vm1# ip -d link show vtep245
12: vtep245: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/ether 52:3a:8c:c9:08:e8 brd ff:ff:ff:ff:ff:ff promiscuity 0
vxlan id 1 local 192.168.32.245 dev eth0 srcport 0 0 dstport 8472 nolearning ageing 300 noudpcsum noudp6zerocsumtx noudp6zerocsumrx addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 root@vm2# ip -d link show vtep246
10: vtep246: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/ether 02:38:4a:12:3b:43 brd ff:ff:ff:ff:ff:ff promiscuity 0
vxlan id 1 local 192.168.32.246 dev eth0 srcport 0 0 dstport 8472 nolearning ageing 300 noudpcsum noudp6zerocsumtx noudp6zerocsumrx addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535

查看监听 UDP 端口,看到内核监听了 8742

$ netstat -nulp
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
udp 0 0 0.0.0.0:8472 0.0.0.0:* -

当前的网络拓扑图如下

┌─────────────────────────────┐          ┌─────────────────────────────┐
│ vm1 │ │ vm2 │
│ ┌─────────────────┐ │ │ ┌─────────────────┐ │
│ │ ns245 │ │ │ │ ns246 │ │
│ │ 172.245.0.2 │ │ │ │ 172.246.0.2 │ │
│ │ eth0 │ │ │ │ eth0 │ │
│ └────────|────────┘ │ │ └────────|────────┘ │
│ │ │ │ │ │
│ veth245 │ │ veth246 │
│ │ │ │ │ │
│ br245 │ │ br246 │
│ 172.245.0.1/24 │ │ 172.246.0.1/24 │
│ │ │ │
│ vtep245 │ │ vtep246 │
│ vni:1 172.245.0.0 │ │ vni:1 172.246.0.0 │
│ │ │ │
│ 192.168.32.245/24 │ │ 192.168.32.246/24 │
│ eth0 │ │ eth0 │
└──────────────│──────────────┘ └──────────────│──────────────┘
│ │
└────────────────────────────────────────┘

在 vm1 上尝试通过 172.245.0.2 访问 172.246.0.2,无法访问,通过 tcpdump 诊断流量到达虚拟网卡 vtep245,但是不知道网关 172.246.0.0 的 MAC 地址

$ ip netns exec ns245 ping -c 1 172.246.0.2

$ tcpdump -s0 -i vtep245 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
17:44:26.916277 ARP, Request who-has 172.246.0.0 tell 172.245.0.0, length 28

在上面已经知道了网关的 MAC 地址,直接进行手动设置(flannel 中有 etcd 进行集中管理)

# vm1
ip neigh add 172.246.0.0 dev vtep245 lladdr 02:38:4a:12:3b:43 # vm2
ip neigh add 172.245.0.0 dev vtep246 lladdr 52:3a:8c:c9:08:e8

解决 MAC 地址问题后,还有一个问题:vxlan 封的包如何发送出去,这里使用 fdb 来根据 MAC 指定 vxlan 包发送的地址

fdb 是一个用于存储 MAC 地址及其对应端口的信息表,以便桥接设备能够高效地转发数据帧。

# vm1
bridge fdb add 02:38:4a:12:3b:43 dev vtep245 dst 192.168.32.246 # vm2
bridge fdb add 52:3a:8c:c9:08:e8 dev vtep246 dst 192.168.32.245

从 172.245.0.2 访问 172.246.0.2 的时序图如下(省略命名空间内的部分,回包方向逻辑一致)

br245        vtep245      vm1:eth0    vm2:eth0      vtep246         br246
| | | | | |
| 172.246.0.2 | | | | |
| routing | | | | |
| ----------> | | | | |
| | vxlan pack | | | |
| | ---------> | | | |
| | | udp 8742 | | |
| | | --------> | | |
| | | | vxlan unpack | |
| | | | -----------> | |
| | | | | 172.246.0.2 |
| | | | | routing |
| | | | | ----------> |
| | | | | |
br245 vtep245 vm1:eth0 vm2:eth0 vtep246 br246

Q&A

Q: 为何 vm1 上的路由要使用 172.246.0.0 作为网关地址

A:

  • 网关不能使用本机的 IP 或者处于本机网段内的 IP,没有路由的情况下,流量转发不到外部;
  • 172.246.0.0 不是一个可用的地址,用来标识整个网络,使用其他的地址会有冲突;

总结

从功能上看:

  1. host-gw 最简单,只需要一条路由就可以打通不同节点的容器网络,但只能在二层互通的场景下完成
  2. ipiphost-gw 的基础上建立了一条 IP 隧道,这样在三层互通的情况下也可以打通容器网络
  3. vxlan 在类似 ipip 的基础上,基于三层隧道实现了二层的覆盖网络,提供了极高的网络隔离能力,相对也最复杂

从性能上看:

  1. host-gw 最快,因为没有任何封包的消耗
  2. ipip 次之,多了二十字节的 IP 头的封装
  3. vxlan 相对最慢,多了一整个 以太网、IP 层和 UDP 层的封装

参考

  1. https://www.rfc-editor.org/rfc/inline-errata/rfc7348.html, Virtual eXtensible Local Area Network (VXLAN): A Framework for Overlaying Virtualized Layer 2 Networks over Layer 3 Networks

[解决方案] 几种通过 iproute2 来打通不同节点间容器网络的方式的更多相关文章

  1. Android4种网络连接方式HttpClient、HttpURLConnection、OKHttp和Volley优缺点和性能对比

    比较的指标: 1.cpu 2.流量 3.电量 4.内存占用 5.联网时间 功能点: 1.重试机制 2.提供的扩展功能 3.易用性 4.是否https 5.是否支持reflect api,OkHttp有 ...

  2. VMware的三种网络连接方式区别

    关于VMware的三种网络连接方式,NAT,Bridged,Host-Only ,在刚接触的时候通常会遇到主机Ping不通虚拟机而虚拟机能Ping得通主机:主机与虚拟机互不相通等等网络问题.本文就这三 ...

  3. VirtualBox的四种网络连接方式

    VirtualBox中有4中网络连接方式:a. NAT                          网络地址转换模式(Network Address Translation)b. Bridged ...

  4. VirtualBox的四种网络连接方式详解

    VirtualBox中有4中网络连接方式: 1. NAT 2. Bridged Adapter 3. Internal 4. Host-only Adapter VMWare中有三种,其实他跟VMWa ...

  5. Kvm虚拟化的一种打包及部署方案(采用tar包,lvm方式)

    Kvm虚拟化的一种打包部署方案(采用tar包,lvm方式) –-–-–-2016年终总结 一 毕业之后跟师兄学到的第一块主要内容,理解花了不少时间.期间经历了shell的入门.linux基础知识入门. ...

  6. bridged(桥接模式)、NAT(网络地址转换模式)和host-only(主机模式)-VMware下三种网络配置方式

    VMWare提供了三种工作模式,它们是bridged(桥接模式).NAT(网络地址转换模式)和host-only(主机模式).要想在网络管理和维护中合理应用它们,你就应该先了解一下这三种工作模式. 1 ...

  7. Android进阶(一)几种网络请求方式详解

    Ref:http://blog.csdn.net/zuolongsnail/article/details/6373051 Android应用经常会和服务器端交互,这就需要手机客户端发送网络请求,下面 ...

  8. 快速理解VirtualBox的四种网络连接方式

    VirtualBox中有4中网络连接方式: NAT Bridged Adapter Internal Host-only Adapter VMWare中有三种,其实他跟VMWare 的网络连接方式都是 ...

  9. Linux虚拟机的三种网络连接方式

    Linux虚拟机的三种网络连接方式 虚拟机网络模式 无论是vmware,virtual box,virtual pc等虚拟机软件,一般来说,虚拟机有三种网络模式: 1.桥接 2.NAT 3.Host- ...

  10. G.711是一种由国际电信联盟(ITU-T)制定的音频编码方式

    http://zh.wikipedia.org/zh-cn/G.711 ITU-T G.711 page ITU-T G.191 software tools for speech and audio ...

随机推荐

  1. RabbitMq高级特性之死信队列 通俗易懂 超详细 【内含案例】

    RabbitMq高级特性之死信队列 又称 死信交换机 DLX 介绍 当消息成为 Dead message 后,会重新发送到另一个交换机,这个交换机就是 DLX(死信交换机) 消息成为死信的情况公有三种 ...

  2. Ubuntu 写入磁盘映像

    使用 dd 命令 dd 命令是 Unix 和 Unix-like 操作系统中用于低级别数据复制和转换的命令.它可以直接操作设备文件(如硬盘.光盘.USB 驱动器等),适用于备份.恢复.制作启动盘等任务 ...

  3. man 切换颜色配置

    man 命令显示的命令手册默认是没有颜色的.为了使 man 命令的输出更为生动,可以使用如下两种方法修改 man 命令的颜色配置. 方法一:设置环境变量 在你的 .zshrc / .bashrc 中添 ...

  4. LOTO示波器统计曲线和故障分析pass/fail测试

    LOTO示波器统计曲线和故障分析pass/fail测试 虚拟示波器可以应用在工业自动化检测中,除了常规的检测波形和测量值参数以外,由多个行业客户定制和验证的统计曲线和故障分析(pass/fail)功能 ...

  5. Unity 中 Color 与 Color32 的区别

    1. 存储方式 Color用四个浮点数(float)来表示RGBA,取值范围均是0到1 举例: var orange = new Color(1f, 0.5f, 0f, 1f); 而Color32使用 ...

  6. OData – Get Started 搭建单侧环境

    前言 之前写过 EF Core – Get Started 搭建单侧环境, 这篇补上一个 WebApi + EF Core + OData 创建项目 dotnet new webapi -o EfCo ...

  7. RxJS 系列 – Join Operators

    前言 前几篇介绍过了 Creation Operators Filtering Operators Join Creation Operators Error Handling Operators T ...

  8. Shiro-认证绕过漏洞(CVE-2020-1957)

    漏洞原理 核心点就是shiro和spring对uri进行配合匹配的时候有缺陷导致的,shiro中很轻易就能绕过,其次spring中对;分号好像情有独钟,被大牛们发现后也就一下子绕过了. 主流paylo ...

  9. Windows Terminal3.1

    其实就是为了把之前写的东西集成起来所以搞了一个终端. 下载 集成功能 Wordle ABCG RandTool cmd 便捷功能 FastFile (快速打开目标文件夹) show 文件说明 Term ...

  10. .NET 开源高性能 MQTT 类库

    前言 随着物联网(IoT)技术的迅猛发展,MQTT(消息队列遥测传输)协议凭借其轻量级和高效性,已成为众多物联网应用的首选通信标准. MQTTnet 作为一个高性能的 .NET 开源库,为 .NET ...