Kubernetes Network 由浅入深
次要是学习深刻分析Kubernetes
专栏课的笔记。
一、单机容器网络
名词
- 网络栈:网络栈包含了网卡(
Network Interface
)、回环设施(Loopback Device
)、路由表(Routing Table
)和Iptables
规定,对于一个过程来说,这些因素,就形成了它发动申请和响应网络申请的根本环境。 - 网桥(
Bridge
):bridge
是一个虚构网络设备,所以具备网络设备的特色,能够配置IP
、MAC
地址;Bridger
是一个虚构交换机,具备和物理交换机相似的性能。它是工作在数据链路层的设施。 Veth Pair
: 虚构网线,用来连贯容器到网桥上的;它被创立进去当前,总是以两张虚构网卡(Veth Peer
)的模式成对呈现,并且,从其中一个网卡收回的数据包会主动呈现在与之对应的网卡上,哪怕是这两张\_*网卡\_在不同的Network Namespace
中。ARP
: 是一个通过三层的IP
地址找到对应二层MAC
地址的协定。CAM表
:虚构交换机(这里是网桥)通过MAC
地址学习保护的端口和MAC
地址的对应表。
Host网络
作为一个容器,在启动时能够通过指定-net=host
,应用宿主机的Network Namespace
。
$ docker run -d -net=host --name nginx-1 nginx
应用Host
网络的长处是网络性能较好,间接应用宿主机的网络栈,毛病是会引入共享网络资源的问题,比方端口抵触。所以,在少数状况下,咱们都心愿能应用本人Network Namespace里的网络栈,领有属于本人的IP和端口。
如何通信
如上图,形容了单节点容器网络的通信流程,上面次要按C1->C2
的拜访流程来详细描述交互流程:
# 先创立两个容器,用于模仿发动申请,启动两个centos容器,并在外面装置net-tools工具,才能够应用ifconfig命令# 创立C1,并装置net-tools$ docker run -d -it --name c1 centos /bin/bash$ docker exec -it c1 bash$ [root@60671509044e /]# yum install -y net-tools# 创立C2,并装置net-tools$ docker run -d -it --name c2 centos /bin/bash$ docker exec -it c2 bash$ [root@94a6c877b01a /]# yum install -y net-tools
容器
C1
和C2
启动之后,在容器中都有一条默认的路由规定,以后容器网段的所有申请都会走eth0
网卡设施。- C1
# 进入c1容器,查看ip以及路由表$ docker exec -it c1 bash# 查看IP$ ifconfigeth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.7 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:ac:11:00:07 txqueuelen 0 (Ethernet) RX packets 6698 bytes 9678058 (9.2 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3518 bytes 195061 (190.4 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0# 查看路由 $ routeKernel IP routing tableDestination Gateway Genmask Flags Metric Ref Use Ifacedefault _gateway 0.0.0.0 UG 0 0 0 eth0172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
C2
# 进入C2容器查看IP和路由表$ docker exec -it c2 bash$ ifconfigeth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.8 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:ac:11:00:08 txqueuelen 0 (Ethernet) RX packets 6771 bytes 9681937 (9.2 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3227 bytes 179347 (175.1 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0# 查看路由$ routeKernel IP routing tableDestination Gateway Genmask Flags Metric Ref Use Ifacedefault _gateway 0.0.0.0 UG 0 0 0 eth0172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
上述容器事实有本人的IP
以及MAC
地址,并且每个容器中都有默认路由_gateway
指向eth0
网卡;并且_gateway
有对应的MAC
地址曾经存在于本地ARP
缓存中。
- 主机之间网络通信须要用到
MAC
地址,这是数据链路层辨认主机的形式,C1
拜访C2
的时候会先从本地ARP
缓存中查找是否有C2
容器对应的IP:172.17.0.3
的MAC
地址。如果没有就会发动ARP
协定查找MAC
地址。
# c1 -> c2 ,先发动ARP申请查找MAC地址,能够在容器中查看ARP缓存对应IP的MAC$ docker exec -it c1 bash# 先查看本地的ARP缓存$ [root@94a6c877b01a /]# arpAddress HWtype HWaddress Flags Mask Iface_gateway ether 02:42:2e:8d:21:d6 C eth0# 执行ping命令就会发动ARP寻址申请$ ping 172.17.0.8# 再查问本地arp缓存,发现曾经有MAC地址存在了$ [root@60671509044e /]# arpAddress HWtype HWaddress Flags Mask Iface172.17.0.8 ether 02:42:ac:11:00:08 C eth0_gateway ether 02:42:2e:8d:21:d6 C eth0
ARP
寻址流程:C1
容器发动ARP
申请,进过本地路由协定之后会把申请路由到网桥上,此时网桥(Bridge
)充当一个虚构交换机,虚构替换机会把ARP
播送到其它插入到网桥的所有容器,C2
收到ARP
协定之后会回复MAC
地址。
- 查找到
C2
的MAC
地址之后就能够发动通信。
二、跨主机容器通信
跨主机之间容器通信按是否依赖底层网络环境来划分次要分为Overlay
和Underlay
两种网络结构,Overlay
网络要求只是主机之间网络可达即可,不要求主机之间同处二层域;Underlay
对底层的基础设施有要求,依照实现的形式对底层的网络基础设施有不同的要求,比方Flanan host-gw
组件要求主机之间同处二层域,也就是主机之间要连贯到一个交换机上。
名词
Overlay Network
(笼罩网络): 在已有的宿主机网络之上,通过软件构建一个笼罩在宿主机网络之上的、能够把所有容器连通在一起的虚构网络。Tun设施(Tunnel设施)
:在Linux
中,TUN
设施是一种工作在三层(Network Layer
)的虚构网络设备;Tun
设施的性能就是在操作系统内核和用户应用程序之间传递IP
包,VXLAN
: 虚构可扩大局域网(Virtual Extensible LAN
),是LINUX
内核反对的一种网络虚拟化技术,VXLAN
齐全在内核态实现网络数据包的封装和解封装。VTEP
:虚构隧道端点设施,它既有IP
,也有MAC
地址。BGP
: 边界网关协定(Border Gateway Protocol
),它是一个Linux
内核原生就反对的、专门用在大规模数据中心里保护不同的自治零碎之间路由信息的、无核心的路由协定。
跨主机通信
跨主机之间的容器通信,通过采纳Overlay Network
来实现跨主机之间的容器通信,Overlay Network
的实现有多种形式。
Overlay 模式
1、三层Flannel UDP
Flannel UDP
模式是Flannel
最开始提供的一种最简略且最易实现的容器跨主网络计划,然而因为性能最差,所以起初被弃用。然而对于了解Overlay
的实现形式还是很有参考意义的。
咱们以一个例子来讲述这个网络拜访的流程,在这个流程中,有两台宿主机,四个容器,咱们须要通过Container-1
容器申请Container-4
。
Container-1
容器向Container-4
容器发动申请,Docker0
是位于Root Network Namespace
的,通过veth peer
一头连着容器的Network Namespace
一头连着位于Root Netwrok Namespace
的Docker0
虚构网络设备。
- 容器
100.96.1.2
拜访100.96.2.2
,因为目标地址不在Docker0
网桥的网段内(通过ARP
申请一次就晓得指标容器不在此网桥上),所以这个IP
会执行Container-1
的默认路由规定中,容器中的默认路由规定就是如下的default via 172.17.0.1 dev eth0
。对应到上图的步骤1。
# 容器中默认设置的的路由规定,[root@94a6c877b01a /]# ip routedefault via 172.17.0.1 dev eth0 172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2 # 下一跳是172.17.0.1且从eth0设施上进来,通过查看docker的网络,172.17.0.1就是bridge设施的网关IPlengrongfu@MacintoshdeMacBook-Pro ~ % docker network ls NETWORK ID NAME DRIVER SCOPEe522990979b3 bridge bridge local# 查看网络lengrongfu@MacintoshdeMacBook-Pro ~ % docker inspect network e522990979b3[ { "Name": "bridge", "Id": "e522990979b365e9df4d967c3600483e598e530361deb28513b6e75b8b66bedf", "Created": "2021-04-12T12:11:57.321486866Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "94a6c877b01ac3a1638f1c5cde87e7c58be9ce0aafd4a78efcb96528ab00ed94": { "Name": "c2", "EndpointID": "a5c12fb3800991228f8dc3a2a8de1d6f4865439701a83558e4430c2aebf783a8", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", "IPv6Address": "" } }, "Options": { "com.docker.network.bridge.default_bridge": "true", "com.docker.network.bridge.enable_icc": "true", "com.docker.network.bridge.enable_ip_masquerade": "true", "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", "com.docker.network.bridge.name": "docker0", "com.docker.network.driver.mtu": "1500" }, "Labels": {} }]
- 进入到
Docker0
网桥之后就依照主机上的路由取决于后续如何走。如下就是主机的路由表,拜访指标IP
为100.96.2.2
的设施会命中第二条匹配规定,意思是拜访100.96.0.0/16
网段的数据去flannel0
设施,并且愿IP
为100.96.1.0
。对应到上图的步骤2。
# Node1路由表$ ip route1 Default via 10.168.0.1 dev eth02 100.96.0.0/16 dev flannel0 proto kernel scope link src 100.96.1.03 100.96.1.0/24 dev docker0 proto kernel scope link src 100.96.1.14 10.168.0.0/24 dev eth0 proto kernel scope link src 10.168.0.2
Flannel0设施
上述说了
Flannel0
是一个TUN
虚构三层网络设备,次要是在内核态和用户态之间传递IP
包;持续按上述的流程剖析,数据报文从内核态达到Flannel0
设施之后,会被传递给创立Flannel0
设施的过程也就是FlannelD
过程,而后flanneld
过程看到目标地址是100.96.2.2
,就把数据报文发送到Node2
节点上的flanneld
过程监听的UDP
端口上。flanneld
会把要发送的数据封装为一个UDP
数据包收回去。对应到上图的步骤3、4、5、6。flanneld
过程是怎么晓得100.96.2.2
这个ip
在Node2
上呢,这是因为它利用了子网,在每个节点启动的时候都会被指定一个字网段,通过字网就能确定这个ip
是属于那个节点的,子网被存在etcd
外面。
Node2
上的flanneld
过程收到数据包之后,会发送到flannel0
设施上,这是一个从用户态到内核态的过程,所以Linux
内核网络协议栈就会负责解决这个IP
包,具体的解决办法,就是通过本机的路由表来寻找这个IP
包的下一步流向。对应到上图的步骤7、8。
# node2上的路由表$ ip route1 default via 10.168.0.1 dev eth02 100.96.0.0/16 dev flannel0 proto kernel scope link src 100.96.2.03 100.96.2.0/24 dev docker0 proto kernel scope link src 100.96.2.14 10.168.0.0/24 dev eth0 proto kernel scope link src 10.168.0.3
- 通过解析出指标
ip
为100.96.2.2
,他和第三条的路由规定匹配更加准确,这条路由规定的意思是把发往100.96.2.0/24
网段的的数据包发送到docker0
设施下来,并且设置源IP
为100.96.2.1
。对应到上图的步骤9。 - 数据包进入到
docker0
设施之后,docker0
网桥会表演二层交换机的角色,将数据包发送给正确的veth pair
对,进过此设施之后就进入到Contaniner-2
的网络协议栈中。对应到上图的步骤10。
Flannel UDP
模式提供的是一个三层的Overlay
网络,它首选对收回端的IP
包进行UDP
封装,而后在接收端进行解封装拿到原始IP
包,进而把这个IP
包转发给指标容器。
Flannel UDP
模式有重大的性能问题,次要问题是,因为应用了TUN
设施,仅在收回IP
包的过程中,就须要通过三次用户态和内核态之间的数据拷贝。
2、三层Calico ipip
3、二层+三层VXLAN
VXLAN
网络的设计思维是,在现有的三层网络之上,笼罩一层虚构的、由内核VXLAN
模块负责保护的二层网络,使得连贯在这个VXLAN
二层网络上的主机之间,能够像在同一个局域网那样自在通信。为了能在二层网络上买通隧道,
VXLAN
会在宿主机上设置一个非凡的网络设备作为隧道的两端,这个设施就叫作VTEP
,全称是:(VXLAN Tun End Poin
)虚构隧道端点。
VTEP
设施的作用和flanneld
过程的作用是一样的,就是做数据包的封装和解封装,只不过,它进行封装和解封装的是二层数据帧,而且这个工作流程,全都是在内核里实现的。
Underlay 模式
1、三层模式BGP
如上图是一个典型的BGP
网络拓扑图,通过Route1
和Route2
作为边界路由网关,把其它LAN
的路由信息写入到以后的路由中,就实现了不同LAN
下的路由信息同步,达到三层网络全通。
Calico BGP 应用
在理解了BGP
之后,Calico
我的项目的架构就非常容易了解了,它把每个主机节点当做一个边界路由来对待,所以在每个节点上都保留了所有其余节点的路由信息,咱们来剖析一下它的实现,它由三个局部组成:
Calico
的CNI
插件,这是Caclico
和Kubernetes
对接的局部。BIRD
是BGP
的客户端,专门负责在集群外面散发路由信息。Felix
,它是一个Demoset
,负责在宿主机上插入路由规定(写入Linux
内核的FIB
转发信息表),以及保护Calico
所需的网络设备等工作。
Calico BGP
模式和Flannel host-gw
模式不同,Calico
没有创立任何的虚构网桥设施,Calico
的工作形式采纳如下图来阐明。
Calico BGP
模式的网络交互图如上所示,如container1
须要拜访Container3
,咱们来剖析下网络如何达到。因为没有采纳cni0
虚构网桥设施,因而veth
设施对的一端是在容器的Network Namespace
中的,一端是在宿主机的容器网络空间的,
- 首先
Calico CNI
插件还须要在每个宿主机上为每个容器的Veth Pair
设施配置一条路由规定,因为承受传入的IP
包,比方:
# 192.168.0.2节点上的路由信息有$ ip route10.20.0.2 dev cali1 scope link10.20.0.3 dev cali2 scope link# 192.168.0.3节点上的路由信息有$ ip route10.20.1.2 dev cali3 scope link10.20.1.3 dev cali4 scope link
- 每个节点上还有
BGP
播送的其它节点路由协定,比方:
# 192.168.0.2上有一条指向192.169.0.3的路由$ ip route10.20.1.0/24 via 192.168.0.3 dev eth0# 192.168.0.3上有一条指向192.168.0.2的路由$ ip route10.20.0.0/24 via 192.168.0.2 dev eth0
- 默认的
Calico BGP
应用的是Node to Node
的模式,会导致每个节点上的连贯以N^2
的数独增长,个别举荐少于应用100
个节点的集群中。在大规模集群中,须要用到一个叫Route Reflector
的模式,所有的路由会对立上报到一个核心节点,其它节点都从核心节点进行同步。
Calico BGP
模式和Flannel host-gw
模式一样,都有一个对根底网络设施的依赖,要求集群宿主机之间是二层可达的。如果宿主机之间处在不同的LAN
下,就须要应用Calico ipip
的Overlay
模式了。
2、二层VLAN
3、Flannel host-gw
Flannel host-gw
模式一张图就能够讲清楚他们之间的实现原理。
CNI0
设施是一个三层交换机,具备二层交换机的性能,同时具备独立IP
flannel
以Daemonset
的形式在每个节点上启动一个Flanneld
过程,用于保护每个节点上的路由信息,实现形式是,本地
如:192.168.1.0/24 via 10.20.0.3 dev eth0
路由定义了拜访192.168.1.0/24
网段的下一跳为10.20.0.3
并从eth0
设施出。
而后IP
包被封装成帧发送进来的时候,会应用路由表里的下一跳来设置目标MAC
地址;这样,就能通过二层网络达到目标宿主机。
因为他会应用下一跳的目标MAC
地址,所以它要求宿主机之间是二层联通的,不如就没法通过应用ARP
协定用IP
去获取MAC
地址了。