k8s的Flannel网络

引: 之前写过一篇文章介绍如何管理linux设备上的bridge(网桥)和docker bridge, 今天我们来看看k8s的网络模型。

我们先来看图示例,下面则个是k8s的网络模型图。

k8s的网络模型

我们知道,在k8s里面最小的管理单元是pod,一个主机可以跑多个pod,一个pod里面可以跑多个容器。

如上面所示,一个pod里面所有的容器共享一个网络命名空间(network namespace),所以,pod里面的容器之间通信,可以直接通过localhost来完成,pod里面的容器之间通过localhost+端口的方式来通信(这和应用程序在宿主机的通信方式是一样的)。

那么pod和pod之间的通信呢?通常来说,我们给应用程序定死端口会给应用程序水平扩展带来很多不便,所以k8s不会使用定死端口这样的方法,而是采用其他方法来解决pod之间寻址的问题

每个pod都会有一个自己的ip,可以将Pod像VM或物理主机一样对待。这样pod和pod之间的通信就不需要像容器一样,通过内外端口映射来通信了,这样就避免了端口冲突的问题。

特殊的情况下(比如运维做网络检测或者程序调试),可以在pod所在的宿主机想向pod的ip+端口发起请求,这些请求会转发到pod的端口,但是pod本身它自己是不知道端口的存在的。

因此,k8s的网络遵循以下原则:

  • 一个节点的pod和其他节点的pod通信不需要通过做网络地址转换(NAT)
  • 一个节点上所有的agent控制程序(如deamon和kubelet)可以和这个节点上的pod通信
  • 节点主机网络中的Pod可以与其他所有节点上的所有Pod通信,而无需NAT

把上面这个pod替换成容器也是成立的,因为pod里面的容器和pod共享网络。

基本上的原则就是,k8s的里面的pod可以自由的和集群里面的任何其他pod通信(即使他们是部署在不同的宿主机),而且pod直接的通信是直接使用pod自己的ip来通信,他们不知道宿主机的ip,所以,对于pod之间来说,宿主机的网络信息是透明的,好像不存在一样。

然后,定了这几个原则之后,具体的实现k8s的这个网络模型有好多种实现,我们这里介绍的是Flannel,是其中最简单的一种实现。

Flannel实现pod之间的通信,是通过一种覆盖网络(overlay network),把数据包封装在另外一个网络来做转发,这个覆盖网络可以给每一个pod分配一个独立的ip地址,使他们看起来都是一台具有独立ip的物理主机一样。

下面这个就是k8s用覆盖网络来实现的一个例子:

flannel覆盖网络

可以看到有3个node,在多个node上建立一个覆盖网络,子网网段是100.95.0.0/16,然后,最终到容器级别,每个容器在这个网段里面获取到一个独立的ip。而宿主机所在的局域网络的网段是172.20.32.0/19

看这两个网段,就知道,fannel给这个集群创建了一个更大的网络给pod使用,可以容纳的主机数量达到65535(2^16)个。

对于每个宿主机,fannel给每个了一个小一点的网络100.96.x.0/24,提供给每个这个宿主机的每一个pod使用,也就是说,每一个宿主机可以有256(2^8)个pod。docker默认的网桥docker0用的就是这个网络,也就是所有的docker通过docker0来使用这个网络。即使说,对于容器来说,都是通过docker0这个桥来通信,和我们平常单机的容器是一样的(如果你不给创建的容器指定网络的话,默认用的是docker0,参考我以前写的关于docker bridge的文章)

那么,对于同一个host里面的容器通信,我们上面说了是通过这个台宿主机的里面的docker0这个网桥来通信。那对于跨宿主机,也即是两个宿主机之间的容器是怎么通信的呢?fannel使用了宿主机操作系统的kernel route和UDP(这是其中一种实现)包封装来完成。下图演示了这个通信过程:

fannel网络中跨宿主机的容器通信

如图所示,100.96.1.2(container-1) 要和100.96.2.3(container-2)通信,两个容器分别处于不同的宿主机。
假设有一个包是从100.96.1.2发出去给100.96.2.3,它会先经过docker0,因为docker0这个桥是所有容器的网关。 然后这个包会经过route table处理,转发出去到局域网172.20.32.0/19. 而这个route table的对应处理这类包的规则又是从哪里来的呢?它们是由fannel的一个守护程序flanneld创建的。

每一台宿主机都会跑一个flannel的deamon的进程,这个进程的程序会往宿主机的route table里面写入特定的路由规则,这个规则大概是这样的。

Node1的route table

admin@ip-172-20-33-102:~$ ip route
default via 172.20.32.1 dev eth0
100.96.0.0/16 dev flannel0  proto kernel  scope link  src 100.96.1.0
100.96.1.0/24 dev docker0  proto kernel  scope link  src 100.96.1.1
172.20.32.0/19 dev eth0  proto kernel  scope link  src 172.20.33.102

图例的数据包发出去的目标地址是100.96.2.3,它属于网段100.96.0.0/16,这个目标地址命中第二条规则,也就是这个包会发到flannel0这个设备(dev),这flannel0是一个TUN设备。是在内核里面的一个虚拟网络设备(虚拟网卡)

在内核(kernel)里面,有两种虚拟网卡设备,分别是TUN和TAP,其中TAP处理的是第二层(数据链路层)的帧,而TUN处理的是第三层(网络层)的ip包。

应用程序可以绑定到TUN和TAP设备,内核会把数据通过TUN或者TAP设备发送给这些程序,反过来,应用程序也可以通过TUN和TAP向内核写入数据,进而由内核的路由处理这些发出去的数据包。

那么上面这个flannel0就是一个这样的TUN设备。这个设备连到的是一个flannel的守护进程程序flanneld

而这个flanneld是干嘛的呢?它可以接受所有发往flannel0这个设备的数据包,然后做数据封装处理,它的封装的逻辑也很简单,就是根据目标地址,找到这个这地址对应的在整个flannel网络里面对应物理ip和端口(这里是Node2对应的物理ip),然后增加一个包头,增加的包头里面目标地址为这个实际的物理ip和端口(当然源地址也改成了局域网络的ip),将原来的数据包嵌入在新的数据包中,然后再把这个封装后的包扔回去给内核,内核根据目标地址去路由规则匹配规则,发现目标地址ip是172.20.54.98,端口是8285. 根据ip匹配不到任何特定的规则,就用第一条default(默认)的规则,通过eth0这个物理网卡,把数据包发给局域网(这里是UDP广播出去)

当Node2的收到这个包后,然后根据端口8285发现他的目标地址原来是发给flanneld的,然后就直接交给flanneld这程序,flanneld收到包后,把包头去掉,发现原来目标地址是100.96.2.3,然后就交换flannel0,flannel0把这个解开后的原包交给内核,内核发现它的目标地址是100.96.2.3,应该交给docker0来处理。(图例里面画的是直接由flannel0交给docker0,没有图示出内核,实际上flannel0是一个TUN设备,是跑在内核的,数据经过它后可以交给内核,由内核根据路由决定进一步怎么forward)

以上就是这个通信的过程,那么这里有一个问题: flanneld是怎么知道100.96.2.3对应的目标地址是172.20.54.98:8285的呢?

这是因为flanneld维护了一个映射关系,它没创造一个虚拟的容器ip(分配给容器新ip的时候),它就知道这个容器的ip实际上是在哪台宿主机上,然后把这个映射关系存储起来,在k8s里面flanneld存储的这个映射关系放在etd上,这就是为什么flanneld为什么知道这个怎么去封装这些包了,下面就是etcd里面的数据的:

admin@ip-172-20-33-102:~$ etcdctl ls /coreos.com/network/subnets
/coreos.com/network/subnets/100.96.1.0-24
/coreos.com/network/subnets/100.96.2.0-24
/coreos.com/network/subnets/100.96.3.0-24
admin@ip-172-20-33-102:~$ etcdctl get /coreos.com/network/subnets/100.96.2.0-24
{"PublicIP":"172.20.54.98"}

看上面这个数据,etcd里面存储的100.96.2.0-24这个网段的容器是放在172.20.54.98这台宿主机上的。

那么还有一个问题,端口8285又是怎么知道的?

这个很简单,flanneld的默认监听的端口就是这个8285端口,flanneld启动的时候,就监听了UDP端口8285. 所以发给Node2:8285的所有UDP数据包会,flanneld这个进程会直接处理,如何去掉包头就还原出来原来的包了,还原后交给TUN设备flannel0,由flannel0交给内核,内核根据Node2的路由规则交给docker0(Node2的路由规则和node1是基本上一样的,除了第三位的网段标识不一样,一个是100.96.1一个是100.92.2):

admin@ip-172-20-54-98:~$ ip route
default via 172.20.32.1 dev eth0
100.96.0.0/16 dev flannel0  proto kernel  scope link  src 100.96.2.0
100.96.2.0/24 dev docker0  proto kernel  scope link  src 100.96.2.1
172.20.32.0/19 dev eth0  proto kernel  scope link  src 172.20.54.98

看Node2的这个规则,flannld去掉包头解出来的原包的目标ip是100.96.2.3,由flannel0交回去给kennel,kennel发现命中第三条规则,所以会把这个包叫给docker0,继而就进入了docker0这个桥的子网了,接下去就是docker的事情了,参考以前写的文章

最后一个问题,怎么配置docker去使用100.96.x.0/24这个子网呢,如果是手工创建容器的话,这个也是非常简单的,参考以前写的关于docker bridge的这篇文章,但是在k8s里面,是通过配置来实现的:

flanneld会把子网信息写到一个配置文件/run/flannel/subnet.env

admin@ip-172-20-33-102:~$ cat /run/flannel/subnet.env
FLANNEL_NETWORK=100.96.0.0/16
FLANNEL_SUBNET=100.96.1.1/24
FLANNEL_MTU=8973
FLANNEL_IPMASQ=true

docker会使用这个配置的环境变了来作为它的bridge的配置

dockerd --bip=$FLANNEL_SUBNET --mtu=$FLANNEL_MTU

以上,就是k8s如何使用flannel网络来跨机器通信的原理,总体来讲,由于flanneld这个守护神干了所有的脏活累活(其实已经是k8s的网络实现里面最简单的一种了),使得pod和容器能够连接另外一个pod或者容器变得非常简单,就像连一个大局域网里面任意以太主机一样,他们只需要知道对方的虚拟ip就可以直接通信了,不需要做
NAT等复杂的规则处理。

那么性能怎么样?

新版本的flannel不推荐在生产环境使用UDP的包封装这种实现。只用它来做测试和调试用,因为它的性能表现和其他的实现比差一些。

flannel0 利用的TUN设备做包封装原理

看上面这个图解,一个upd包需要来回在用户空间(user space)和内核空间(kennel space)复制3次,这会大大增加网络开销。

官方的文档里面可以看到其他的包转发实现方式,可以进一步阅读,其中host-gw的性能比较好,它是在第二层去做数据包处理。

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

推荐阅读更多精彩内容