Kubernetes CNI之Flannel网络模型分析

Kubernetes CNI之Flannel网络模型分析

前面,我们在搭建Kubernetes集群时,用了比较常见的Flannel做为集群的CNI,它会负责集群内跨Node的通信。

该CNI的yaml文件定义在这里:https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

其中,跟本文相关的重点内容是:

data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }

在net-conf.json部分,可以看到,集群内Pod的网段是:10.244.0.0/16;默认启用的backend类型是VXLAN。

本文将分析两种不同情况下的Pod之间的网络通信方式:

  1. 相同Node,不同Pod;

  2. 不同Node,不同Pod。

实验的集群,带了两个Node,其中的Master Node,已经被去除了污点,允许被调度。

为了实验相同Node、不同Node的两种情况,计划建立4个Replicas的Busybox。这样可以保证:每个Node上都有两个Pod,用来做相同Node通信的情况;每个Node上都会有Pod,用来实验不同Node通信的情况。

OK, let's hit the road.

1. 创建YAML文件

首先创建Deployment的YAML文件:

$ vi busybox_deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: busybox-deployment
spec:
  selector:
    matchLabels:
      app: busybox
  replicas: 4
  template:
    metadata:
      labels:
        app: busybox
    spec:
      containers:
      - name: busybox
        image: busybox
        command:
          - sleep
          - "3600"
        imagePullPolicy: IfNotPresent
      restartPolicy: Always

按:wq保存退出。

2. 创建Deployment

用上一步的YAML文件,创建K8S的Deployment:

$ kubectl apply -f busybox_deployment.yaml
deployment.apps/busybox-deployment configured

可以看到,K8S已经按照预期,在两个Node上,分别创建了两个Pod:

$ kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE                   NOMINATED NODE   READINESS GATES
busybox-deployment-6fc48fb64-4c5l2   1/1     Running   0          12s     10.244.0.19   ycwang-ubuntu          <none>           <none>
busybox-deployment-6fc48fb64-4nccz   1/1     Running   0          12s     10.244.1.14   ycwang-ubuntu-worker   <none>           <none>
busybox-deployment-6fc48fb64-jbhxl   1/1     Running   0          12s     10.244.1.13   ycwang-ubuntu-worker   <none>           <none>
busybox-deployment-6fc48fb64-vd89t   1/1     Running   0          12s     10.244.0.18   ycwang-ubuntu          <none>           <none>

其中,10.244.0.18、10.244.0.19的两个Pod,运行在Master Node;10.244.1.13、10.244.1.14的两个Pod,运行在Worker Node。

3. 节点上的网卡

先看一下此时在Master Node上的网卡情况:

$ ip addr
......
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:49:39:91 brd ff:ff:ff:ff:ff:ff
    altname enp2s1
    inet 192.168.111.128/24 brd 192.168.111.255 scope global dynamic noprefixroute ens33
       valid_lft 1628sec preferred_lft 1628sec
    inet6 fe80::72bf:3960:42cd:13cb/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
......
4: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
    link/ether ce:5f:f6:73:cf:b9 brd ff:ff:ff:ff:ff:ff
    inet 10.244.0.0/32 scope global flannel.1
       valid_lft forever preferred_lft forever
    inet6 fe80::cc5f:f6ff:fe73:cfb9/64 scope link
       valid_lft forever preferred_lft forever
5: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
    link/ether e6:62:4d:8e:51:21 brd ff:ff:ff:ff:ff:ff
    inet 10.244.0.1/24 brd 10.244.0.255 scope global cni0
       valid_lft forever preferred_lft forever
    inet6 fe80::e462:4dff:fe8e:5121/64 scope link
       valid_lft forever preferred_lft forever
.......

我们只要观察上面的三个网卡即可。

ens33:是Node的物理网卡,所有跨Node的通信,不管用了什么技术,最终都是要通过它进出的。

flannel.1:是Flannel安装的网卡/VTEP,用来实现VXLAN的支持。跨Node的Pod之间通信,都需要经过它来进行Overlay网络的封装和解封装。

可以看一下它的具体信息:

$ ip -details link show flannel.1
4: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default 
    link/ether 36:a8:31:9e:3e:5d brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535 
    vxlan id 1 local 192.168.111.128 dev ens33 srcport 0 0 dstport 8472 nolearning ttl auto ageing 300 udpcsum noudp6zerocsumtx noudp6zerocsumrx addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535

可以看到,这个VXLAN设备,VNI是1、本地IP是192.168.111.128、目标端口是8472(不是标准VXLAN的4789)。

cni0:这个跟Docker里面带的Docker0感觉没什么区别,就是一个Linux Bridge。每个Pod会产生一个veth pair,一端接在Pod里面;另一端接在cni0里面。Pod之间的通信,都需要经过这个网桥。

4. 网络拓扑

这张图,是Pod在相同Node通信、不同Node通信的总结。后面的实验,都是为了验证这张图。

Flannel.png

相同Node、不同Pod之间的通信,走的是黑色 + 绿色的线。Pod A和Pod B都通过veth接在同一个网桥cni0上。Pod A将数据通过veth发到cni0之后,cni0将数据转发到Pod B的veth。

不同Node、不同Pod之间的通信,走的是黑色 + 蓝色的线。Node 1上的Pod A,给Node 2上的Pod C发数据时,途径cni0,然后经过flannel.1进行VXLAN封装,最后依靠Node 1的物理网卡将数据发送给Node 2的物理网卡。Node 2的物理网卡再将数据依次发送给Node 2上的flannel.1、cni0,最后到达Pod C。

5. 相同Node通信实验

登录运行在Master Node上的一个Pod:

$ kubectl exec -it busybox-deployment-6fc48fb64-4c5l2 -- sh
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
    link/ether a6:72:78:4a:0b:72 brd ff:ff:ff:ff:ff:ff
    inet 10.244.0.19/24 brd 10.244.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a472:78ff:fe4a:b72/64 scope link
       valid_lft forever preferred_lft forever

该Pod的IP是:10.244.0.19。用它去ping相同Node上的另一个Pod:10.244.0.18:

/ # ping 10.244.0.18
PING 10.244.0.18 (10.244.0.18): 56 data bytes
64 bytes from 10.244.0.18: seq=0 ttl=64 time=0.373 ms
64 bytes from 10.244.0.18: seq=1 ttl=64 time=0.065 ms
......

然后在Node上的cni0抓包:

$ sudo tcpdump -i cni0 -s 0 -X -nnn -vvv
17:06:16.588123 IP (tos 0x0, ttl 64, id 58509, offset 0, flags [DF], proto ICMP (1), length 84)
    10.244.0.19 > 10.244.0.18: ICMP echo request, id 15, seq 17, length 64
      0x0000:  4500 0054 e48d 4000 4001 400f 0af4 0013  E..T..@.@.@.....
      0x0010:  0af4 0012 0800 f64d 000f 0011 e9d3 17be  .......M........
      0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0040:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0050:  0000 0000                                ....
17:06:16.588135 IP (tos 0x0, ttl 64, id 12216, offset 0, flags [none], proto ICMP (1), length 84)
    10.244.0.18 > 10.244.0.19: ICMP echo reply, id 15, seq 17, length 64
      0x0000:  4500 0054 2fb8 0000 4001 34e5 0af4 0012  E..T/...@.4.....
      0x0010:  0af4 0013 0000 fe4d 000f 0011 e9d3 17be  .......M........
      0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0040:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0050:  0000 0000

可以看到,ICMP的往返报文在cni0上传递。

如果此时在Node上的flannel.1抓包,可以发现什么报文都没有:

$ sudo tcpdump -i flannel.1 -s 0 -X -nnn -vvv

所以,相同Node、不同Pod之间的通信,依靠的是veth + cni0网桥。

6. 不同Node通信实验

继续用Master Node的Pod 10.244.0.19,用它去ping在另一个Node上的Pod 10.244.1.13:

/ # ping 10.244.1.13
PING 10.244.1.13 (10.244.1.13): 56 data bytes
64 bytes from 10.244.1.13: seq=0 ttl=62 time=1.099 ms
64 bytes from 10.244.1.13: seq=1 ttl=62 time=0.544 ms
......

此时,在Master Node上的cni0抓包:

$ sudo tcpdump -i cni0 -s 0 -X -nnn -vvv
tcpdump: listening on cni0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
17:10:01.770478 IP (tos 0x0, ttl 64, id 48266, offset 0, flags [DF], proto ICMP (1), length 84)
    10.244.0.19 > 10.244.1.13: ICMP echo request, id 19, seq 4, length 64
      0x0000:  4500 0054 bc8a 4000 4001 6717 0af4 0013  E..T..@.@.g.....
      0x0010:  0af4 010d 0800 0647 0013 0004 6dd6 83cb  .......G....m...
      0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0040:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0050:  0000 0000                                ....
17:10:01.771463 IP (tos 0x0, ttl 62, id 15347, offset 0, flags [none], proto ICMP (1), length 84)
    10.244.1.13 > 10.244.0.19: ICMP echo reply, id 19, seq 4, length 64
      0x0000:  4500 0054 3bf3 0000 3e01 29af 0af4 010d  E..T;...>.).....
      0x0010:  0af4 0013 0000 0e47 0013 0004 6dd6 83cb  .......G....m...
      0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0040:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0050:  0000 0000

可以看到,ICMP的往返报文也是通过cni0进行传递的。

继续在Master Node上的flannel.1抓包:

$ sudo tcpdump -i flannel.1 -s 0 -X -nnn -vvv
tcpdump: listening on flannel.1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
17:12:02.155017 IP (tos 0x0, ttl 63, id 10040, offset 0, flags [DF], proto ICMP (1), length 84)
    10.244.0.19 > 10.244.1.13: ICMP echo request, id 20, seq 3, length 64
      0x0000:  4500 0054 2738 4000 3f01 fd69 0af4 0013  E..T'8@.?..i....
      0x0010:  0af4 010d 0800 cc53 0014 0003 7ac2 b0d2  .......S....z...
      0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0040:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0050:  0000 0000                                ....
17:12:02.156094 IP (tos 0x0, ttl 63, id 36934, offset 0, flags [none], proto ICMP (1), length 84)
    10.244.1.13 > 10.244.0.19: ICMP echo reply, id 20, seq 3, length 64
      0x0000:  4500 0054 9046 0000 3f01 d45b 0af4 010d  E..T.F..?..[....
      0x0010:  0af4 0013 0000 d453 0014 0003 7ac2 b0d2  .......S....z...
      0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0040:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0050:  0000 0000

这种情况下,报文经cni0,传送到了flannel.1。Flannel.1进行VXLAN封装后,会继续传送到Master Node的物理网卡。

继续在Master Node上的ens33抓包:

$ sudo tcpdump -i ens33 udp -s 0 -X -nnn -vvv
tcpdump: listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
17:12:46.181905 IP (tos 0x0, ttl 64, id 21130, offset 0, flags [none], proto UDP (17), length 134)
    192.168.111.128.60568 > 192.168.111.129.8472: [bad udp cksum 0x60d6 -> 0x76a1!] OTV, flags [I] (0x08), overlay 0, instance 1
IP (tos 0x0, ttl 63, id 15296, offset 0, flags [DF], proto ICMP (1), length 84)
    10.244.0.19 > 10.244.1.13: ICMP echo request, id 20, seq 47, length 64
      0x0000:  4500 0086 528a 0000 4011 c78a c0a8 6f80  E...R...@.....o.
      0x0010:  c0a8 6f81 ec98 2118 0072 60d6 0800 0000  ..o...!..r`.....
      0x0020:  0000 0100 3a87 cf81 6ace ce5f f673 cfb9  ....:...j.._.s..
      0x0030:  0800 4500 0054 3bc0 4000 3f01 e8e1 0af4  ..E..T;.@.?.....
      0x0040:  0013 0af4 010d 0800 2e59 0014 002f 788e  .........Y.../x.
      0x0050:  50d5 0000 0000 0000 0000 0000 0000 0000  P...............
      0x0060:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0070:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0080:  0000 0000 0000                           ......
17:12:46.182333 IP (tos 0x0, ttl 64, id 8026, offset 0, flags [none], proto UDP (17), length 134)
    192.168.111.129.55939 > 192.168.111.128.8472: [udp sum ok] OTV, flags [I] (0x08), overlay 0, instance 1
IP (tos 0x0, ttl 63, id 42036, offset 0, flags [none], proto ICMP (1), length 84)
    10.244.1.13 > 10.244.0.19: ICMP echo reply, id 20, seq 47, length 64
      0x0000:  4500 0086 1f5a 0000 4011 faba c0a8 6f81  E....Z..@.....o.
      0x0010:  c0a8 6f80 da83 2118 0072 88b6 0800 0000  ..o...!..r......
      0x0020:  0000 0100 ce5f f673 cfb9 3a87 cf81 6ace  ....._.s..:...j.
      0x0030:  0800 4500 0054 a434 0000 3f01 c06d 0af4  ..E..T.4..?..m..
      0x0040:  010d 0af4 0013 0000 3659 0014 002f 788e  ........6Y.../x.
      0x0050:  50d5 0000 0000 0000 0000 0000 0000 0000  P...............
      0x0060:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0070:  0000 0000 0000 0000 0000 0000 0000 0000  ................
      0x0080:  0000 0000 0000 

可以看到,这是Overlay的报文。报文内层是10.244.0.19 > 10.244.1.13的ICMP请求;报文外层是192.168.111.128 > 192.168.111.129的UDP请求。只不过由于它的目标端口是自定义的8472,而不是RFC定义的4789,tcpdump没把它解释成VXLAN报文而已。

所以,不同Node、不同Pod之间的通信,依靠的是veth + cni0 + flannel.1(VXLAN)。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容