xiaohanliang
Docker
Docker
  • hi
  • STORAGE DRIVER
    • 1. 什么叫联合挂载
    • 2. 镜像ID是从哪来的
    • 3. 如何组装出一个镜像
    • 4. 为什么有这么多fs@aufs
    • 5. 为什么有这么多fs@overlay
    • 6. 为什么有这么多fs@dm
    • 7. 正确安装devicemapper
  • EXEC DRIVER
    • 1. 资源限制-cgroup
    • 2. 制造小型监狱
    • 3. 切换根目录是什么概念
    • 4. 标准极简容器runC
    • 5. 尝试安装runc工具
  • KUBERNETES NETWORK
    • 0. [WIP]我想串联容器网络的故事
    • 1. 容器网络是什么样的网络
    • 2. cnm认为应该怎样让容器组网
    • 3. 为什么会有一大堆cni插件
    • 4. 为什么要设计出pod
    • 5. 怎样形成一个服务
    • 6. Service就是iptables规则
    • 7. IPVS也能实现Service
    • 8. 从集群外访问服务-nodeport
    • 9. 从集群外访问服务-ingress
    • 10. 想要把域名变成IP
    • 11. DNS是怎么实现的
    • 12. 最常见的方案@flannel
    • 13. 使用tun设备封包@flannel
    • 14. 使用vxlan设备封包@flannel
    • 15. 可不可以不封包@flannel
Powered by GitBook
On this page
  • introduction
  • 快递员flanneld
  • flanneld 都起着什么作用

Was this helpful?

  1. KUBERNETES NETWORK

13. 使用tun设备封包@flannel

introduction

我们先说说比较好理解的 udp 模式吧, 在 udp 模式下运行的 flanneld 会打开一个 /dev/net/tun (不是吧.. 这东西真的有人用wtf?) , 简单回顾一下, 这东西是用来发包的, 你读写这个东西, 而不是读写 socket 对象, 就允许那一头打开这个文件的人来修改你的包, 然后由他帮你发包.

那么这个人是谁? 这个人就是 flanneld, 你封出来的包使用的是虚拟IP, 发不出去的, 他帮你再封出一个IP头, 上面写对方宿主机IP, 这样你的包才能被发出去, 对方宿主机上的flanneld 会收到这个包, 然后由他帮你递给他的容器

# flanneld 帮你创建了一个类型为 tun 的网卡, 名为 flannel0
$ ip -d link show flannel0
5. flannel0: <POINTTOPOINT> MTU=1472 tun

# flanneld 自己正在监听 8285 端口
$ netstat -ulnp |  grep flanneld
udp     0     0    172.16.130.140:8285

快递员flanneld

现在详细聊聊如何做到跨宿主机的通信, 实验条件如下, 假设现在容器A想要Ping容器B, 他俩的环境是:

# ------------------------------------------------  容器-A

# 容器A的IP (也就是容器A下, eth0网卡绑定的IP, 这玩意本质上是veth)
10.244.1.96     
# 容器A的路由表
0.0.0.0      10.244.1.1   0.0.0.0        eth0     
10.244.0.0   10.244.1.1   255.255.0.0    eth0

# 宿主机A的IP
172.16.130.140  
# 宿主机A的路由表
10.244.0.0    0.0.0.0     255.255.255.0  flannel0 
10.244.1.0    0.0.0.0     255.255.255.0  cni0
172.16.130.0  0.0.0.0     255.255.255.0  eth0

# ------------------------------------------------  容器-B

# 容器B的IP
10.244.2.194    
# 宿主机B的IP
172.16.130.164  
# 宿主机B的路由表
10.244.2.0   0.0.0.0    255.255.255.0   cni0
  • 容器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 模式比较蛋疼的地方

Previous12. 最常见的方案@flannelNext14. 使用vxlan设备封包@flannel

Last updated 4 years ago

Was this helpful?