一、Pod网络
在K8S集群里,多个节点上的Pod相互通信,要通过网络插件来完成,比如Calico网络插件。
使用kubeadm初始化K8S集群时,有指定一个参数 --pod-networkcidr=10.18.0.0/16 它用来定义Pod的网段。而我们在配置Calico的时候,同样也有定义一个CALICO_IPV4POOL_CIDR的参
数,它的值同样也是Pod的网段。
容器网络尤其是在跨主机容器间的网络是非常复杂的。目前主流的容器网络模型主要有Docker公司提出的Container Network Model(CNM)模型和CoreOS公司提出的Container NetworkInterface(CNI)模型,而Kubernetes采用了由CoreOS公司提出的CNI模型。
1)CNI
首先我们介绍一下什么是 CNI,它的全称是 Container Network Interface,即容器网络的 API 接口。CNI本身并不能提供网络服务,它只是定义了对容器网络进行操作和配置的规范。CNI仅关注在创建容器时分配网络资源,和在销毁容器时删除网络资源,这使得CNI规范非常轻巧、易于实现,得到了广泛的支持。而真正实现和落地这些规范的是CNI插件。常见的CNI插件包括Calico、flannel、Terway、Weave Net 以及 Contiv。
2)K8S如何使用CNI插件
K8s 通过 CNI 配置文件来决定使用什么 CNI。
基本的使用方法为:
- 在每个节点上配置 CNI 配置文件(/etc/cni/net.d/xxnet.conf),其中 xxnet.conf 是某一个网络配置文件的名称,不同插件名称格式也不同;
[root@aminglinux01 ~]# ls /etc/cni/net.d/
10-calico.conflist calico-kubeconfig
[root@aminglinux01 ~]#
- 安装 CNI 配置文件中所对应的二进制插件;
[root@aminglinux01 bin]# ls
bandwidth calico dhcp firewall host-device install loopback portmap sbr tuning vrf
bridge calico-ipam dummy flannel host-local ipvlan macvlan ptp static vlan
[root@aminglinux01 bin]#
- 在这个节点上创建 Pod 之后,Kubelet 就会根据 CNI 配置文件执行前两
步所安装的 CNI 插件;
具体的流程如下图所示:
在集群里面创建一个 Pod 的时候,首先会通过 apiserver 将 Pod 的配置写入。apiserver 的一些管控组件(比如 Scheduler)会调度到某个具体的节点上去。Kubelet 监听到这个 Pod 的创建之后,会在本地进行一些创建的操作。当执行到创建网络这一步骤时,它首先会读取刚才我们所说的配置目录中的配置文件,配置文件里面会声明所使用的是哪一个插件,然后去执行具体的 CNI 插件的二进制文件,再由 CNI 插件进入 Pod 的网络空间去配置 Pod 的网络。配置完成之后,Kuberlet 也就完成了整个 Pod 的创建过程,这个 Pod 就在线了。
3)基于Calico的Pod网络
pod1自己的IP,pod1里有一个网卡,eth0。eth0,向外经过node节点的网卡,如calico是网桥
9: cali1779cc140b5@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP group default
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netns cni-44567f0a-fe06-cfc4-3e48-1ccea4e5ea
,接着经过tunl0,tunl0会进行IP的封装。pod之间通信,将源node节点的pod的封装源IP和目的IP封装,使用node节点的IP和目的node节点的IP封装,到对端节点后,依次解封装。
3: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
inet 10.18.61.0/32 scope global tunl0
valid_lft forever preferred_lft forever
二、Service网络
在介绍Service这个api资源对象时,我们已经汇总过Service的几个type:ClusterIP、NodePort、LoadeBalancer,除了这三个还有其它的类型,暂且不去讨论。
这三种类型的Service,LoadBalancer依赖NodePort,而NodePort通常要和ClusterIP一起使用,如果在Service的yaml文件里定义type为LoadBalancer,则它会自动创建NodePort,而NodePort也会自动创建ClusterIP。
下面,再来演绎一下从Pod到Service的网络变化情况:
1)单个Pod之间通信
单个Pod和Pod之间通信只能通过Pod的IP和Port来通信,如下图
2)Pod有多个
当引入了Deployment,并为Pod设置多个副本时,那么提供某一个服务(如Nginx服务)的Pod就不止一个了,此时即使知道了这些Pod的IP,那访问起来也并不方便。所以,这里需要有一个统一入口,其它Pod通过这个统一入口去请求该服务(Nginx)对应的所有Pod。 这时就有了Service这个资源对象,它主要作用就是用来提供统一入口,也就是说只需要一个IP就能访问所有的Pod,而这个入口IP就是ClusterIP,也就是Service的IP。
3)外部资源访问内部Pod
有了Service,的确可以很方便为内部的Pod提供入口,但是在集群外面访问这个内部的资源就没办法了。于是,就有了这个NodePort,使用Service的NodePort类型,可以将Service的ClusterIP对应的Port映射到每一个Node的IP上,映射出去的Port范围为30000~32767
4)借助公有云的负载均衡器
使用这个NodePort并不方便,毕竟它带着一个长长的端口号,而且还有一个非常尴尬的问题,就是访问时还得带着Node的IP,如果这个Node挂掉,那么就无法访问此资源,虽然可以通过另外一个Node去访问,但这样太麻烦了!所以,此时的解决方案是:借助三方的负载均衡器,将请求分发到所有的Node上,其底层还是NodePort。
总结:Service为内部Pod的统一入口,内部资源之间可以通过最简单的ClusterIP进行通信,而外部资源访问需要借助NodePort的形式,但是带着长长端口不方便,于是又衍生了LoadBalancer的形式,这种形式需要借助三方的负载均衡器,将请求分发到每一个NodePort上。
三、网络插件Calico
1)Calico是什么
Calico 是一个用于容器、虚拟机和主机的开源网络和网络安全解决方案。它是一个纯三层(L3)解决方案,利用 BGP(Border Gateway Protocol)协议为容器或虚拟机提供 IP 地址,并提供网络安全功能,包括网络策略和加密。
Calico 通过将网络策略应用于标签和选择器,提供了一种简单而强大的方法来保护容器或虚拟机之间的通信,并限制容器或虚拟机可以访问的网络资源。它还支持基于 Kubernetes 和 OpenStack 等平台的网络自动化和集成。
Calico 的另一个重要特点是其可扩展性。它使用了基于 BGP 的路由技术,这使得它能够轻松地扩展到非常大规模的网络中,而不会降低性能。
由于Calico是一种纯三层的方案,因此可以避免与二层方案相关的数据包封装的操作,中间没有任何的NAT,没有任何的overlay,所以它的转发效率是所有方案中最高的,因为它的包直接走原生TCP/IP的协议栈,它的隔离也因为这个栈而变得好做。因为TCP/IP的协议栈提供了一整套的防火墙的规则,所以它可以通过IPTABLES的规则达到比较复杂的隔离逻辑。
2)Calico架构
各组件介绍:
- Felix:Calico Agent,跑在K8S集群中的每台节点上,主要负责管理和维护该节点上的网络和安全策略,如 网络接口管理和监听、路由、ARP 管理、ACL 管理和同步、状态上报等;
- Etcd:分布式键值存储,用来存储网络元数据、安全策略以及节点的状态信息,确保Calico网络状态的一致性和准确性,可以和K8S的etcd合用;
- BGP Client(BIRD):跟Felix一样,每一个节点上都会部署BGP Client,主要负责把Felix写入Kernel的路由信息分发到当前Calico网络,确保各节点间的通信的有效性;
- BGP Route Reflector(BIRD): 在大型网络规模中,如果仅仅使用BGPClient 形成mesh全网互联的方案就会导致规模限制,因为所有节点之间俩俩互联,需要 N^2 个连接,为了解决这个规模问题,可以采用 BGP 的 Router Reflector 的方法,使所有BGP Client仅与特定RR节点互联并做路由同步,从而大大减少连接数大规模部署时使用。
关键点:
Felix会定期查询Etcd数据库,从而获取到IP变化信息,比如说用户在这台机器上创建了一个容器,增加了一个IP等。当它发现数据变更后,比如用户创建pod后,Felix负责将其网卡、IP、MAC都设置好,然后在内核的路由表里面写一条,注明这个IP应该到这张网卡。同样如果用户制定了隔离策略,Felix同样会将该策略创建到ACL中,以实现隔离。BIRD是一个标准的路由程序,它会从内核里面获取哪一些IP的路由发生了变化,然后通过标准BGP的路由协议扩散到整个其他的宿主机上,让外界都知道这个IP在这里,你们路由的时候得到这里来。
3)calico三种网络工作模式
模式 | 说明 | 特点 |
VXLAN | 封包, 在vxlan设备上将pod发来的数据包源、目的mac替换为本机vxlan网卡和对端节点vxlan网卡的mac。外层udp目的ip地址根据路由和对端vxlan的mac查fdb表获取 | 只要k8s节点间三层互通, 可以跨网段,对主机网关路由没有特殊要求。各个node节点通过vxlan设备实现基于三层的“二层”互通, 三层即vxlan包封装在udp数据包中, 要求udp在k8s节点间三层可达;二层即vxlan封包的源mac地址和目的mac地址是自己的vxlan设备mac和对端vxlan设备mac。 |
IPIP | 封包,在tunl0设备上将pod发来 的数据包的mac层去掉,留下ip 层封包。 外层数据包目的ip地址 根据路由得到。相当于建立了隧 道,把两个本来不通的节点网络 通过点对点连接起来。 | 只要k8s节点间三层互通, 可以跨网段,对主机网关路由没有特殊要求。解包、封包都会造成一定的资源损耗。 适用于互相访问的pod不在同一个网段中、跨网段访问的场景。外层封装的ip能够解决跨网段的路由问题。 |
BGP | 边界网关协议(Border Gateway Protocol, BGP)是互联网上一个 核心的去中心化自治路由协议。 通俗的讲就是讲接入到机房的多 条线路(如电信、联通、移动 等)融合为一体,实现多线单IP | 不用封包解包,通过bgp协议可实现pod网络在主机间的三层可达, k8s节点不跨网段时和flannel的host-gw相似,支持跨网段,跨网段时,需要主机网关路由也充当BGP Speaker能够学习到pod子网路由并实现pod子网路由的转发。总之bgp适用于大规模网络场景。 |
4)IPIP模式说明
默认网络模式即IPIP模式,在所有节点上查看网卡,会有tunl0网卡。
aminglinux02
8: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
inet 10.18.206.192/32 scope global tunl0
valid_lft forever preferred_lft forever
aminglinux03
4: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
inet 10.18.68.128/32 scope global tunl0
valid_lft forever preferred_lft forever
查看路由
aminglinux02
[root@aminglinux03 ~]# ip route
default via 192.168.100.2 dev ens160 proto static metric 100
10.18.61.0/26 via 192.168.100.151 dev tunl0 proto bird onlink
blackhole 10.18.68.128/26 proto bird
10.18.68.137 dev calidfd03e8da13 scope link
10.18.68.138 dev cali3d8c7289157 scope link
10.18.68.139 dev cali3aa6bf70edf scope link
10.18.68.140 dev cali8861f5125a1 scope link
10.18.68.141 dev cali9098d3a3e23 scope link
10.18.68.142 dev calif069201ae7b scope link
10.18.68.143 dev calid680d4640d8 scope link
10.18.68.144 dev cali33493131077 scope link
10.18.68.146 dev cali1ab6d5dd596 scope link
10.18.68.177 dev cali5c0f02f5b9f scope link
10.18.206.192/26 via 192.168.100.152 dev tunl0 proto bird onlink
192.168.100.0/24 dev ens160 proto kernel scope link src 192.168.100.153 metric 100
[root@aminglinux03 ~]#
aminglinux03
[root@aminglinux03 ~]# ip route
default via 192.168.100.2 dev ens160 proto static metric 100
10.18.61.0/26 via 192.168.100.151 dev tunl0 proto bird onlink
blackhole 10.18.68.128/26 proto bird
10.18.68.137 dev calidfd03e8da13 scope link
10.18.68.138 dev cali3d8c7289157 scope link
10.18.68.139 dev cali3aa6bf70edf scope link
10.18.68.140 dev cali8861f5125a1 scope link
10.18.68.141 dev cali9098d3a3e23 scope link
10.18.68.142 dev calif069201ae7b scope link
10.18.68.143 dev calid680d4640d8 scope link
10.18.68.144 dev cali33493131077 scope link
10.18.68.146 dev cali1ab6d5dd596 scope link
10.18.68.177 dev cali5c0f02f5b9f scope link
10.18.206.192/26 via 192.168.100.152 dev tunl0 proto bird onlink ##100.152是02的ip
192.168.100.0/24 dev ens160 proto kernel scope link src 192.168.100.153 metric 100
[root@aminglinux03 ~]#
查看Pod
[root@aminglinux01 ~]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ng-deploy-6d94878b66-8t2hq 1/1 Running 2 (6d ago) 6d23h 10.18.68.140 aminglinux03 <none> <none>
ng-deploy-6d94878b66-gh95m 1/1 Running 2 (6d ago) 6d23h 10.18.206.207 aminglinux02 <none> <none>
① ng-deploy-6d94878b66-8t2hq 在aminglinux03上,它的IP为10.18.68.140
② 如果68.140要访问另外一个pod ng-deploy-6d94878b66-gh95m,其IP为10.18.206.207,
③ 它会找路由 10.18.206.192/26 via 192.168.100.152 dev tunl0 proto bird onlink,这条路由对应着aminglinux02的节点IP 192.168.100.152,所以它通过这个IP就能找到10.18.206.211
以上可以说明,IPIP模式就是将节点与节点之间建立了一条隧道,并且建立了对应的路由信息,Pod之间通信时只需要知道目标IP所对应的路由就可以直接访问到对应的节点IP,从而达到对方的Pod。
5)BGP模式说明
将IPIP模式改为BGP更改calico-node配置
kubectl edit ds calico-node -n kube-system #会进入vim编辑模式
搜索下面两行
- name: CALICO_IPV4POOL_IPIP
value: Always
在它的下面增加:
- name: CALICO_AUTODETECTION_METHOD
value: interface=eth0
apiVersion: v1
fieldPath: spec.nodeName
- name: CALICO_NETWORKING_BACKEND
valueFrom:
configMapKeyRef:
key: calico_backend
name: calico-config
- name: IP_AUTODETECTION_METHOD
value: interface=ens160
- name: CLUSTER_TYPE
value: k8s,bgp
- name: IP
value: autodetect
- name: CALICO_IPV4POOL_IPIP
value: Always
- name: CALICO_AUTODETECTION_METHOD
value: interface=eth0
- name: CALICO_IPV4POOL_VXLAN
value: Never
- name: CALICO_IPV6POOL_VXLAN
value: Never
- name: FELIX_IPINIPMTU
valueFrom:
configMapKeyRef:
key: veth_mtu
name: calico-config
保存即可生效
更改ippool,保存即可生效
kubectl edit ippool #会进入vim编辑模式
搜索ipipMode
将ipipMode: Always 改为 ipipMode:Never
spec:
allowedUses:
- Workload
- Tunnel
blockSize: 26
cidr: 10.18.0.0/16
ipipMode: Never
natOutgoing: true
nodeSelector: all()
vxlanMode: Never
查看ip,会发现三台机器的tunl0都没有IP地址了
aminglinux01
3: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
6: cali1779cc140b5@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP group default
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netns cni-44567f0a-fe06-cfc4-3e48-1ccea4e5ea15
inet6 fe80::ecee:eeff:feee:eeee/64 scope link
valid_lft forever preferred_lft forever
aminglinux02
8: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
11: cali22131720f2f@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP group default
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netns cni-415b9925-bf28-0e6b-2a78-b0e0e7f182e6
inet6 fe80::ecee:eeff:feee:eeee/64 scope link
valid_lft forever preferred_lft forever
aminglinux03
4: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
8: calid680d4640d8@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP group default
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netns cni-d3becb09-3aa7-3bf4-35f4-0495f04f8edc
inet6 fe80::ecee:eeff:feee:eeee/64 scope link
valid_lft forever preferred_lft forever
再查看route,使用BGP模式不再显示tunl0
[root@aminglinux01 ~]# ip route
default via 192.168.100.2 dev ens160 proto static metric 100
blackhole 10.18.61.0/26 proto bird
10.18.61.12 dev cali1779cc140b5 scope link
10.18.61.13 dev cali2bb677a33f4 scope link
10.18.61.14 dev caliee756e9471b scope link
10.18.61.15 dev calibc526a63b1c scope link
10.18.68.128/26 via 192.168.100.153 dev ens160 proto bird
10.18.206.192/26 via 192.168.100.152 dev ens160 proto bird
192.168.100.0/24 dev ens160 proto kernel scope link src 192.168.100.151 metric 100
[root@aminglinux01 ~]#
[root@aminglinux02 ~]# ip route
default via 192.168.100.2 dev ens160 proto static metric 100
10.18.61.0/26 via 192.168.100.151 dev ens160 proto bird
10.18.68.128/26 via 192.168.100.153 dev ens160 proto bird
blackhole 10.18.206.192/26 proto bird
10.18.206.202 dev cali3e85ae8f09d scope link
10.18.206.203 dev cali07a3ec98e37 scope link
10.18.206.204 dev cali5ab9559459f scope link
10.18.206.205 dev caliba0d741a9b9 scope link
10.18.206.206 dev calidc1633488d2 scope link
10.18.206.207 dev calia0d6b652089 scope link
10.18.206.208 dev cali00890ee0ce4 scope link
10.18.206.209 dev cali1325c4c14d4 scope link
10.18.206.210 dev cali21fe2709e6b scope link
10.18.206.212 dev cali22131720f2f scope link
192.168.100.0/24 dev ens160 proto kernel scope link src 192.168.100.152 metric 100
[root@aminglinux02 ~]#
[root@aminglinux03 ~]# ip route
default via 192.168.100.2 dev ens160 proto static metric 100
10.18.61.0/26 via 192.168.100.151 dev ens160 proto bird
blackhole 10.18.68.128/26 proto bird
10.18.68.137 dev calidfd03e8da13 scope link
10.18.68.138 dev cali3d8c7289157 scope link
10.18.68.139 dev cali3aa6bf70edf scope link
10.18.68.140 dev cali8861f5125a1 scope link
10.18.68.141 dev cali9098d3a3e23 scope link
10.18.68.142 dev calif069201ae7b scope link
10.18.68.143 dev calid680d4640d8 scope link
10.18.68.144 dev cali33493131077 scope link
10.18.68.146 dev cali1ab6d5dd596 scope link
10.18.68.177 dev cali5c0f02f5b9f scope link
10.18.206.192/26 via 192.168.100.152 dev ens160 proto bird
192.168.100.0/24 dev ens160 proto kernel scope link src 192.168.100.153 metric 100
[root@aminglinux03 ~]#
同样还是ng-deploy的两个Pod,IP地址依然是68和206
[root@aminglinux01 ~]# kubectl get pod -owide | grep ng-deploy
ng-deploy-6d94878b66-8t2hq 1/1 Running 2 (6d1h ago) 7d 10.18.68.140 aminglinux03 <none> <none>
ng-deploy-6d94878b66-gh95m 1/1 Running 2 (6d1h ago) 7d 10.18.206.207 aminglinux02 <none> <none>
[root@aminglinux01 ~]#
如果使用BGP模式,68.140访问206.207时,它的路由是10.18.206.192/26 via 192.168.100.152 dev ens160 proto bird 但此时并不需要借助tunl0了,而是直接通过ens160了。
4.4 网络插件Flannel
1)Flannel简介
Flannel也是一个CNI插件,它的功能跟Calico一样,为K8S集群中的Pod提供网络支撑。
Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务。
Flannel的设计目的就是为集群中的所有节点重新规划IP地址的使用规则,从而使得不同节点上Pod能够获得“同属一个内网”且”不重复的”IP地址,并让属于不同节点上的Pod能够直接通过内网IP通信。简单来说,它的功能是让集群中的不同节点主机创建的Pod都具有全集群唯一的虚拟IP地址。
Flannel实质上是一种“覆盖网络(overlaynetwork)”,也就是将TCP数据包装在另一种网络包里面进行路由转发和通信,目前已经支持udp、vxlan、hostgw、aws-vpc、gce和alloc路由等数据转发方式。
核心关键点:
- 网络配置:Flannel 配置存储在etcd中。Flannel节点会从etcd中读取这些配置信息,并根据配置创建和管理网络。
- 子网分配:Flannel会为每个节点分配一个不重叠的子网,以便在节点上运行的Pod可以使用该子网内的IP。这样,集群内的每个Pod都将具有唯一的IP地址。
- 数据包封装与转发:Flannel使用数据包封装技术(例如 VXLAN、UDP等)将Pod之间的通信封装为跨节点的通信。当一个节点上的Pod 需要与另一个节点上的Pod通信时,源节点上的Flannel程序会将数据包封装,添加上目标子网信息,并将封装后的数据包发送到目标节点。目标节点上的Flannel程序会解封装数据包,并将其转发给目标Pod。
- 兼容性:Flannel可以与k8s中的其他网络插件(如 Calico)一起使用,以实现更复杂的网络功能。这使得Flannel可以很好地适应不同的集群环境和需求。
工作模式:
- UDP 模式:使用设备 flannel.0 进行封包解包,不是内核原生支持,频繁地内核态用户态切换,性能非常差,目前官方不建议使用了;
- VxLAN 模式:使用 flannel.1 进行封包解包,内核原生支持,性能较强;
- host-gw 模式:无需 flannel.1 这样的中间设备,直接宿主机当作子网的下一跳地址,性能最强;
2)Flannel架构
Flannel在底层实现上要比Calico简单。
Flannel 最主要的两个组件是flanneld跟 flannel.1:
flanneld:控制面,运行在用户态,负责为宿主机分配子网,并监听Etcd,维护宿主机的FDB/ARP跟路由表
flannel.1:数据面,运行在内核态,作为VTEP,VXLAN 数据包的封包跟解包
3)VxLAN
VxLAN的设计思想是: 在现有的三层网络之上,“覆盖”一层虚拟的、由内核VxLAN模块负责维护的二层网络,使得连接在这个VxLAN二层网络上的“主机”(虚拟机或容器都可以),可以像在同一个局域网(LAN)里那样自由通信。 为了能够在二层网络上打通“隧道”,VxLAN会在宿主机上设置一个特殊的网络设备作为“隧道”的两端,叫VTEP:VxLAN Tunnel End Point(虚拟
隧道端点)
VXLAN是Flannel默认和推荐的模式。当我们使用默认配置安装Flannel时,它会为每个节点分配一个24位子网,并在每个节点上创建两张虚机网卡: cni0 和flannel.1 。
- cni0 是一个网桥设备,节点上所有的Pod都通过veth pair的形式与cni0相连。
- flannel.1 则是一个VXLAN类型的设备,充当VTEP的角色,实现对VXLAN报文的封包解包。
同一个节点内的Pod之间通信,只需要通过cni0即可,而我们要讨论的重点是跨
节点通信。
假设两个节点Node1和Node2,两个节点上分别有两个Pod:PodA和PodB,现在Node1上的PodA要和Node2上的PodB通信,通信过程如下:
大致概括一下整个过程:
- 发送端:在PodA中发起 ping 10.244.1.21 ,ICMP 报文经过 cni0 网桥后交由 flannel.1 设备处理。 Flannel.1 设备是一个VXLAN类型的设备,负责VXLAN封包解包。 因此,在发送端,flannel.1 将原始L2报文封装成VXLAN UDP报文,然后从 eth0 发送。
- 接收端:Node2收到UDP报文,发现是一个VXLAN类型报文,交由flannel.1 进行解包。根据解包后得到的原始报文中的目的IP,将原始报文经由 cni0 网桥发送给PodB。
路由:
Flanneld 从 etcd 中可以获取所有节点的子网情况,以此为依据为各节点配置路由,将属于非本节点的子网IP都路由到 flannel.1 处理,本节点的子网路由到cni0 网桥处理。
[root@Node1 ~]# ip route 10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1
# Node1子网为10.224.0.0/24, 本机PodIP都交由cni0处理
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink # Node2子网为10.224.1.0/24,Node2的PodID都交由flannel.1处理
4)host-gw网络模式
跟VxLAN不同,host-gw模式下没有flannel.1虚拟网卡,无需建立VxLAN隧道。但它有个缺点,必须要保证各Node在同一个网段。
Flanneld 模式的工作原理,就是将每个Flannel子网的下一跳,设置成了该子网对应的宿主机的 IP 地址,也就是说,宿主机(host)充当了这条容器通信路径的“网关”(Gateway),这正是 host-gw 的含义。
所有的子网和主机的信息,都保存在 Etcd 中,flanneld 只需要 watch 这些数
据的变化 ,实时更新路由表就行了。
核心是IP包在封装成帧的时候,使用路由表的“下一跳”设置上的MAC地址,这样可以经过二层网络到达目的宿主机
[root@Node1 ~]# ip r
...
10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1
10.244.1.0/24 via 192.168.50.3 dev eth0 # Node2子网的下一跳地址指向Node2的public ip。
由于没有封包解包带来的消耗,host-gw是性能最好的。不过一般在云环境下,都不支持使用host-gw的模式,在私有化部署的场景下,可以考虑。