13. 使用tun设备封包@flannel
introduction
我们先说说比较好理解的 udp 模式吧, 在 udp 模式下运行的 flanneld 会打开一个 /dev/net/tun (不是吧.. 这东西真的有人用wtf?) , 简单回顾一下, 这东西是用来发包的, 你读写这个东西, 而不是读写 socket 对象, 就允许那一头打开这个文件的人来修改你的包, 然后由他帮你发包.
那么这个人是谁? 这个人就是 flanneld, 你封出来的包使用的是虚拟IP, 发不出去的, 他帮你再封出一个IP头, 上面写对方宿主机IP, 这样你的包才能被发出去, 对方宿主机上的flanneld 会收到这个包, 然后由他帮你递给他的容器
快递员flanneld
现在详细聊聊如何做到跨宿主机的通信, 实验条件如下, 假设现在容器A想要Ping容器B, 他俩的环境是:
容器A先发出 ICMP 报文, 容器A封出来的包IP为 → [10.244.1.96(源) , 10.244.2.194(目的)]
这个包怎么发? 查容器A的路由表, 目的IP(10.244.2.194) 匹配中第二条, 发送给容器A的eth0(一个veth), 继而到达veth的另一头, 宿主机A的 cni0 网桥 (类似docker0, 也是一个网桥)
cni0 网桥拿到这个包以后, 比对宿主机A的路由表, 匹配中第一条, 发给 flannel0网卡
这个 flannel0 网卡本质上是一个 tun设备, 因此这个包继而就会被 flanneld 拿到并开始二次封包, 经过查询etcd能得知两个容器的IP对应的宿主机IP, 因此封上一个20字节的IP头, 与8字节的 udp 头, 此时封出来的包:
IP报头为 → [172.16.130.140(源宿主机) , 172.16.130.164(目的宿主机)]
UDP报头为 → [8285, 8285]
flanneld 处理完了要把这个包发出去, 继续查询宿主机A的路由表, 命中第三条, 此时应该走宿主机的eth0
到达宿主机B的8285端口, 这个端口是 flanneld 监听的, flanneld会拆掉最外层的 udp报头以及 ip报头, 露出真实的ip报头, 然后发出, 经过检查宿主机B上的路由表, 这个包应该发给 cni0 网桥
宿主机B上的 cni0 网桥将这个包转发给容器B, 完成本次通信
flanneld 都起着什么作用
总结一下这个过程, flanneld 在投递的整个过程中, 负责了拆包与封包, 如果这个flanneld 封装了这个包, 这个包就会被另一个 flanneld 拆开, 除此之外, 宿主机之所以能把包交给 flanneld , 也是因为 flanneld 在刷新宿主机的路由表. 在这个过程中:
cni0处在内核态下, 然后发给 flannel0 (tun设备), 将数据从内核态里复制到用户态
flanneld 封好包以后再经由 eth0 发出, 需要再进入一次内核态
这种进出用户态/内核态的做法, 成为 udp 模式比较蛋疼的地方
Last updated
Was this helpful?