【k8s网络】梳理cni发展脉络

news2024/12/24 9:11:04

参考

  • 《深入剖析 Kubernetes(张磊)》

  • 补充 详解 Calico 三种模式(与 Fannel 网络对比学习)_calico vxlan-CSDN博客

容器网络

容器的网络栈
  • 每个容器有自己的 net namespace

    • net namespace 可以称之为网络栈
    • 所谓“网络栈”,就包括了:网卡(Network Interface)、回环设备(Loopback Device)、路由表(Routing Table)和 iptables 规则。对于一个进程来说,这些要素,其实就构成了它发起和响应网络请求的基本环境。
  • 直接使用宿主机的网络栈(–net=host),即:不开启 Network Namespace

    • $ docker run –d –net=host --name nginx-host nginx
      
    • 这个容器启动后,直接监听的就是宿主机的 80 端口。

    • 可能带来的问题 —— 容器需要的端口与宿主机的㐰冲突

      • 像这样直接使用宿主机网络栈的方式,虽然可以为容器提供良好的网络性能,但也会不可避免地引入共享网络资源的问题,比如端口冲突。所以,在大多数情况下,我们都希望容器进程能使用自己 Network Namespace 里的网络栈,即:拥有属于自己的 IP 地址和端口。
  • 这个被隔离的容器进程,该如何跟其他 Network Namespace 里的容器进程进行交互呢?

    • 在 Linux 中,能够起到虚拟交换机作用的网络设备,是网桥(Bridge)。它是一个工作在数据链路层(Data Link)的设备,主要功能是根据 MAC 地址学习来将数据包转发到网桥的不同端口(Port)上。
    • 可以把容器视为独立的主机,网桥视为交换机
    • Docker 项目会默认在宿主机上创建一个名叫 docker0 的网桥,凡是连接在 docker0 网桥上的容器,就可以通过它来进行通信。
    • 如何把这些容器“连接”到 docker0 网桥上呢? —— 如何把这些容器“连接”到 docker0 网桥上呢?
    • veth-pair 可以视为网线
      • 它被创建出来后,总是以两张虚拟网卡(Veth Peer)的形式成对出现的。并且,从其中一个“网卡”发出的数据包,可以直接出现在与它对应的另一张“网卡”上,哪怕这两个“网卡”在不同的 Network Namespace 里。
      • Veth Pair 常常被用作连接不同 Network Namespace 的“网线”。
不同容器间的通信
  • 不同容器之间如何通信?

    • docker 为 container-1 创建的 veth pair,一端插在容器 net namespace 内,名称为 eth0;另一端插在宿主机 net namespace 内的 docker0 网桥上,名称为 vethXXXXXX —— 分为在容器内和宿主机内执行ifconfig命令可查看到这些设备

    • container-1 想要发送数据给 container-2,该怎么走?

      1. 首先 container-1 会查自己容器 net namespace 内的本地路由表 —— 通过route命令可查看

      2. container-1 根据路由表的匹配规则,知道要通过 eth0 设备,发送到网关 0.0.0.0

        • $ route
          Kernel IP routing table
          Destination Gateway Genmask Flags Metric Ref Use Ifacedefault 
          172.17.0.1 0.0.0.0 UG 0 0 0 eth0
          172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
          
        • 【网关0.0.0.0】意味着这是一条直连规则

          • 即:凡是匹配到这条规则的 IP 包,应该经过本机的 eth0 网卡,通过二层网络直接发往目的主机。
      3. 而目前 container-1 只知道目的 container-2 的 ip 地址,但不知道其对应的 mac 地址

        • 因此便通过自身的 eth0 设备发送一个 ARP 查询包(查询 container-2 ip 对应的 mac 地址)
      4. 发出的 ARP 包,通过 veth 设备,传输到了 docker0 网桥上,docker0 会将其广播到所有插到自身网桥上的 veth 设备,此时 container-2 发现查询是自身,因此相应了自身的 mac 地址

        • 一旦一张虚拟网卡被“插”在网桥上,它就会变成该网桥的“从设备”。从设备会被“剥夺”调用网络协议栈处理数据包的资格,从而“降级”成为网桥上的一个端口。而这个端口唯一的作用,就是接收流入的数据包,然后把这些数据包的“生杀大权”(比如转发或者丢弃),全部交给对应的网桥。
        • 在收到这些 ARP 请求之后,docker0 网桥就会扮演二层交换机的角色,把 ARP 广播转发到其他被“插”在 docker0 上的虚拟网卡(vethxxx)上。
      5. 有了目标 container-2 的 mac 地址后,container-1 便可以正常封包将数据发给 container-2 了

        • docker0 处理转发的过程,则继续扮演二层交换机的角色。此时,docker0 网桥根据数据包的目的 MAC 地址,在它的 CAM 表(即交换机通过 MAC 地址学习维护的端口和 MAC 地址的对应表)里查到对应的端口(Port)为:vethb4963f3,然后把数据包发往这个端口。

        • 需要注意的是,在实际的数据传递时,上述数据的传递过程在网络协议栈的不同层次,都有 Linux 内核 Netfilter 参与其中。所以,如果感兴趣的话,你可以通过打开 iptables 的 TRACE 功能查看到数据包的传输过程,具体方法如下所示:

        • # 在宿主机上执行
          $ iptables -t raw -A OUTPUT -p icmp -j TRACE
          $ iptables -t raw -A PREROUTING -p icmp -j TRACE
          
    • 在这里插入图片描述

  • 不同主机的容器如何通信?

    • 答 —— overlay 网络
    • 简单来说,就是在现在【源container ip,目的container ip】上,通过 SNAT、DNAT、路由表等,进行封装,使其能在真正的物理网络上通行
    • 简单理解为,ip 头为【源container ip,目的container ip】的容器包视为数据段,进行再次 ip 头封装等,实现可以到达对面的宿主机
    • 此部分简单了解就行,不看也行,后面也有详解
    • 在 Docker 的默认配置下,不同宿主机上的容器通过 IP 地址进行互相访问是根本做不到的。
      • 在 Docker 的默认配置下,不同宿主机上的容器通过 IP 地址进行互相访问是根本做不到的。(flannel、calico 等)
常用网络命令
  • 常用命令总结
# 可以看到当前 net namespace 下的所有网络设备,veth pair 、bridge、宿主机网卡 eth0 等
$ ifconfig
# 推荐使用ip link show来看veth-eth映射关系
# 查看 bridge 上插入的 veth pair 设备
$ brctl show
# 查看路由表
$ route

# 在宿主机上
$ docker exec -it nginx-1 /bin/bash
# 在容器里
root@2b3c181aecf1:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:acff:fe11:2  prefixlen 64  scopeid 0x20<link>
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 364  bytes 8137175 (7.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 281  bytes 21161 (20.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        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
        
$ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0


  • 找 docker 和 宿主机上 veth 设备的关系
#看到有位同学问怎么找 docker 和 宿主机上 veth 设备的关系,学完后我也有这个疑问,查了一下,
# 结论是没有命令可以直接查到。但是可以查看 container 里的 eth0 网卡的 iflink 找到对应关系。
# 方法1
# 宿主机上
$ ip link 
......
9: veth0e9cd8d@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default 
    link/ether 6a:fb:59:e5:7e:da brd ff:ff:ff:ff:ff:ff link-netnsid 1

# 容器内
$ sudo docker exec -it e151 bash
root@e1517e9d9e1a:/# cat /sys/class/net/eth0/iflink 
9

# 这样就可以确定 container e1517e9d9e1a 在物理机上对应的 veth pair 是 veth0e9cd8d 了。

# 这种方式需要登录到 docker 里执行命令,不是所有的容器都能这么做,不过 github 上有人专门做了个脚本来用实现这个功能,可以参考一下:
# https://github.com/micahculpepper/dockerveth

# 方法2
容器内执行 ethtool -S eth0 | grep peer_ifindex, 可以看到对端序列号,
然后宿主机上 ip link | grep 那个序列号也可以找到
总结
设备非专业术语作用
Docker0网桥理解为二层交换机,处理包头为 mac 的数据包
net namespace网络栈存储用于通信的网络设备和规则等(网卡、路由表、iptables规则等)
一个 net namespace 可以简单理解为,一个主机
–net=host,表示容器共享宿主机的网络栈(此时可理解为两个人共用一套设备),此时可提高通信效率,但可能会端口冲突
docker run –d –net=host --name nginx-host nginx
veth pair网线用于联通不同的 net namespace,可以理解为连接两个主机间的网线
veth-pair 会生成两个 veth 设备,其可以理解为两个虚拟网卡
其中一个,一般放在宿主机 net namespace 内,插在 docker0 网桥上,名称为 vethXXXX
另一个,一般放在容器 net namespace 内,也就是插在容器内,名称为 eth0(一般表示这是容器的主网卡)
本机通信路径container-1 发包给 container-2:首先 container-1 不知道 container-2,通过路由表查询,
需要通过 eth0 网卡(也就是veth pair 设备的一端)发包,之后container-1 发送 ARP 数据包
(用于查询container-2 mac 地址),通过 veth 转发到 docker0 网桥上,网桥会广播给所有插在自身的 veth 网卡,
匹配的 container-2 会进行相应,返回 mac地址;之后 container-1 封装二层数据包(包头为 mac 地址),然后通过 veth 发送到 docker0 上,docker0 网桥将其转发到 container-2

flannel

udp 模式

Flannel0Tunnel设备
(网络设备)
在 Linux 中,TUN 设备是一种工作在三层(Network Layer)的虚拟网络设备。TUN 设备的功能非常简单,即:在操作系统内核和用户应用程序之间传递 IP 包
以 flannel0 设备为例:像上面提到的情况,当操作系统将一个 IP 包发送给 flannel0 设备之后,flannel0 就会把这个 IP 包,交给创建这个设备的应用程序,也就是 Flannel 进程。这是一个从内核态(Linux 操作系统)向用户态(Flannel 进程)的流动方向。
以 flannel0 设备为例:像上面提到的情况,当操作系统将一个 IP 包发送给 flannel0 设备之后,flannel0 就会把这个 IP 包,交给创建这个设备的应用程序,也就是 Flannel 进程。这是一个从内核态(Linux 操作系统)向用户态(Flannel 进程)的流动方向。
flanneld守护程序(用户态程序,是个进程)维护容器 IP 子网范围和 Node 的对应关系,保存在 etcd 中
事实上,在由 Flannel 管理的容器网络里,一台宿主机上的所有容器,都属于该宿主机被分配的一个“子网”。在我们的例子中,Node 1 的子网是 100.96.1.0/24,container-1 的 IP 地址是 100.96.1.2。Node 2 的子网是 100.96.2.0/24,container-2 的 IP 地址是 100.96.2.3。
flanneld 进程在处理由 flannel0 传入的 IP 包时,就可以根据目的 IP 的地址(比如 100.96.2.3),匹配到对应的子网(比如 100.96.2.0/24),从 Etcd 中找到这个子网对应的宿主机的 IP 地址是 10.168.0.3
每台宿主机上的 flanneld,都监听着一个 8285 端口,所以 Node1 flanneld 只要把 UDP 包发往 Node 2 的 8285 端口即可
(涉及到端口通信,当然需要用到传输层协议,此处用的就是 UDP)
docker0网桥docker0 网桥的地址范围必须是 Flannel 为宿主机分配的子网。这个很容易实现,以 Node 1 为例,你只需要给它上面的 Docker Daemon 启动时配置如下所示的 bip 参数即可:
$ FLANNEL_SUBNET=100.96.1.1/24
$ dockerd --bip=$FLANNEL_SUBNET …
通信过程Container-1 向 container-2 发包【源container-1 ip,目的container-2 ip】
1. 首先 container-1 通过 veth-pair,将数据包从 container(容器) net namespace 传输到 host(宿主机) net namespace 中,也就是数据包到达了 docker0 网桥上【这是一个从用户态(容器内应用程序)向内核态(Linux操作系统的流动方向】
2. 接下来根据 host net namespace 中的路由表,发现 container-2 ip 不在当前 node 的 docker0 网桥上,因此匹配了另一条路由规则,发送给 flannel0 设备
3. fannel0 设备就会把这个 IP 包,交给创建这个设备的应用程序,也就是 flanneld 进程。【这是一个从内核态(Linux 操作系统)向用户态(flanneld 进程)的流动方向。
4. flanneld 通过查询 etcd 知道,该 container-2 ip 属于 Node2 的管辖范围,因此发送到 Node2 的 flanneld 程序(也就是8285端口),才能顺利的完成解包,所以又进行 UDP 封包(可指定端口),并通过宿主机 eth0 端口发出【这是一个从用户态(flanneld 进程)向内核态(Linux 操作系统)的流动方向。】
5. 最后变为如下形式【mac包头(源node1,目的node2】【ip头(源node1,目的node2)】【udp头(源端口8285,目的端口8285】【udp数据帧(也就是容器包【源container-1 ip,目的container-2 ip】【要发送的数据】)
TUN 设备工作原理也是 udp 模式废弃原因UDP 模式有严重的性能问题,所以已经被废弃了。通过我上面的讲述,你有没有发现性能问题出现在了哪里呢?
实际上,相比于两台宿主机之间的直接通信,基于 Flannel UDP 模式的容器通信多了一个额外的步骤,即 flanneld 的处理过程。而这个过程,由于使用到了 flannel0 这个 TUN 设备,仅在发出 IP 包的过程中,就需要经过三次用户态与内核态之间的数据拷贝
第一次,用户态的容器进程发出的 IP 包经过 docker0 网桥进入内核态;
第二次,IP 包根据路由表进入 TUN(flannel0)设备,从而回到用户态的 flanneld 进程;
第三次,flanneld 进行 UDP 封包之后重新进入内核态,将 UDP 包通过宿主机的 eth0 发出去。
可以看到,Flannel 进行 UDP 封装(Encapsulation)和解封装(Decapsulation)的过程,也都是在用户态完成的。在 Linux 操作系统中,上述这些上下文切换和用户态操作的代价其实是比较高的,这也正是造成 Flannel UDP 模式性能不好的主要原因。
在进行系统级编程的时候,有一个非常重要的优化原则,就是要减少用户态到内核态的切换次数,并且把核心的处理逻辑都放在内核态进行。这也是为什么,Flannel 后来支持的VXLAN 模式,逐渐成为了主流的容器网络方案的原因。
  • flannel UDP 模式通信
    • Flannel UDP 模式提供的其实是一个三层的 Overlay 网络,即:它首先对发出端的 IP 包进行 UDP 封装,然后在接收端进行解封装拿到原始的 IP 包,进而把这个 IP 包转发给目标容器。这就好比,Flannel 在不同宿主机上的两个容器之间打通了一条“隧道”,使得这两个容器可以直接使用 IP 地址进行通信,而无需关心容器和宿主机的分布情况。

在这里插入图片描述

  • TUN 设备工作原理
    • 相比于两台宿主机之间的直接通信,基于 Flannel UDP 模式的容器通信多了一个额外的步骤,即 flanneld 的处理过程。而这个过程,由于使用到了 flannel0 这个 TUN 设备,仅在发出 IP 包的过程中,就需要经过三次用户态与内核态之间的数据拷贝
    • 我们在进行系统级编程的时候,有一个非常重要的优化原则,就是要减少用户态到内核态的切换次数,并且把核心的处理逻辑都放在内核态进行。这也是为什么,Flannel 后来支持的VXLAN 模式,逐渐成为了主流的容器网络方案的原因。

在这里插入图片描述

vxlan 模式

首先简单了解
隧道通信就是交给隧道通信设备,自动完成了数据包的跨Node传输,类似覆盖一层“网桥”似的,连接两个Node
所以这个“覆盖的虚拟网桥”,也就是在虚拟的容器网络上覆盖一层网络,称之为 Overlay 网络
我们知道,容器的 IP 是“虚拟IP”,也就是只限本机上使用(同一 Node 上内的容器通信)
出了所在 Node 到真实物理网络中,所有Node 都不认识,也就是不能到其他网络
而在不同 Node 上“覆盖的虚拟网桥”,可将容器 IP 包,传输到不同 Node 上,实现了跨节点通信
flannel UDP 模式三层 Overlay传输的是 IP 包,也就是传给隧道设备的是 IP 包,关注 IP地址
flannel VXLAN 模式二层 Overlay传输的是 MAC 包,也就是传给隧道设备的是 MAC 包,关注 MAC 地址
Fannel VXLAN 模式引入原因Flannel 进行 UDP 封装(Encapsulation)和解封装(Decapsulation)的过程,也都是在用户态完成的。
在 Linux 操作系统中,上述这些上下文切换和用户态操作的代价其实是比较高的,这也正是造成 Flannel UDP 模式性能不好的主要原因
VXLAN 可以完全在内核态实现上述封装和解封装的工作,从而通过与前面相似的“隧道”机制,构建出覆盖网络(Overlay Network)。
VXLANVXLAN 的覆盖网络的设计思想是:在现有的三层网络之上,“覆盖”一层虚拟的、由内核 VXLAN 模块负责维护的二层网络,
使得连接在这个 VXLAN 二层网络上的“主机”(虚拟机或者容器都可以)之间,可以像在同一个局域网(LAN)里那样自由通信。当然,实际上,这些“主机”可能分布在不同的宿主机上,甚至是分布在不同的物理机房里。
为了能够在二层网络上打通“隧道”,VXLAN 会在宿主机上设置一个特殊的网络设备作为“隧道”的两端。这个设备就叫作 VTEP,即:VXLAN Tunnel End Point(虚拟隧道端点)。
VTEP 设备的作用,其实跟前面的 flanneld 进程非常相似。只不过,它进行封装和解封装的对象,是二层数据帧(Ethernet frame);而且这个工作的执行流程,全部是在内核里完成的(因为 VXLAN 本身就是 Linux 内核中的一个模块)。
宿主机上的 VTEP 设备都叫作 flannel.1
通信过程Container-1 向 container-2 发包【源container-1 ip,目的container-2 ip】
1. 首先容器 IP 包,会通过 veth 到达 host net namespace,之后根据路由表,交由给 flannel.1 VTEP 设备处理
【源container-1 ip,目的container-2 ip】
2. 之后 flannel.1 设备会根据容器的目的 ip,为其添加上目的 VTEP 设备的 MAC 地址(该信息由 fanneld 进程维护,是个 ARP 表)
每新增一个 Node VTEP 设备,Flannel 网络会将该 Node VTEP 对应的 ARP 记录下放到所有其他 Node 上
【目标 VTEP Mac地址,源 MAC 地址(是变动的)】【源container-1 ip,目的container-2 ip】
3. 再上面基础上,加上一个特殊的 VXLAN 头,用来表示这个“乘客”实际上是一个 VXLAN 要使用的数据帧。
而这个 VXLAN 头里有一个重要的标志叫作 VNI,它是 VTEP 设备识别某个数据帧是不是应该归自己处理的重要标识。而在 Flannel 中,VNI 的默认值是 1,这也是为何,宿主机上的 VTEP 设备都叫作 flannel.1 的原因,这里的“1”,其实就是 VNI 的值。
4. Linux 内核会把这个数据帧封装进一个 UDP 包里发出去。
那如何知道,对面 Node IP 地址呢?
答:FDB(Forwarding Database)的转发数据库,该数据库维护【 目标 VTEP 设备 MAC 地址 — 所在 Node IP】的对应关系。
不难想到,这个 flannel.1“网桥”对应的 FDB 信息,也是 flanneld 进程负责维护的。它的内容可以通过 bridge fdb 命令查看到
5. 对面 Node 收到包后,根据 VXLAN 头和 VNI 号,知道要转给自己的 flannel.1 设备,从解包后发到目标容器
  • flannel vxlan 通信模式

    在这里插入图片描述

  • 封帧

    在这里插入图片描述

calico-ipip

在了解了 BGP 之后,Calico 项目的架构就非常容易理解了。它由三个部分组成:

  1. Calico 的 CNI 插件。这是 Calico 与 Kubernetes 对接的部分。
  2. Felix。它是一个 DaemonSet,负责在宿主机上插入路由规则(即:写入 Linux 内核的 FIB 转发信息库),以及维护 Calico 所需的网络设备等工作。
  3. BIRD。它就是 BGP 的客户端,专门负责在集群里分发路由规则信息。
  • 除了对路由信息的维护方式之外,Calico 项目与 Flannel 的 host-gw 模式的另一个不同之处,就是它不会在宿主机上创建任何网桥设备。

  • 可以看出与 flannel vxlan 的差异

    • 没有网桥
    • 隧道设备不一致
      • flannel 隧道是 TUN 设备类型,是个(Mac 层 tunnel)设备
      • calico 隧道是 tunl0 设备类型,是一个 IP 隧道(IP 层 tunnel)设备
      • 这两个设备类型很相似,但是不同功能
    • 从封包差异可以看出来
      • flannel 需要封装 VTEP 设备 MAC 地址
      • calico 直接在容器 ip 外层,封装一层 Node ip 层,容器数据作为 Node ip 包的 Payload(负载),容器 ip 与 node ip 的映射关系由本地的 Felix 组件负责,不需要 UDP 封包
        • IP 包进入 IP 隧道设备之后,就会被 Linux 内核的 IPIP 驱动接管。IPIP 驱动会将这个 IP 包直接封装在一个宿主机网络的 IP 包中
        • 查本地路由表,可知 目的容器 ip 对应的目的 Node ip
        • 【目的 Node ip、源 tunl0 设备 ip】(【目的容器ip、源容器 ip】【数据】 此部分可视为 Payload)
        • 目的 Node 网络内核栈会使用 IPIP 驱动进行解包,从而拿到原始的 IP 包。然后,原始 IP 包就会经过路由规则和 Veth Pair 设备到达目的容器内部。
        • 在实际测试中,Calico IPIP 模式与 Flannel VXLAN 模式的性能大致相当。

在这里插入图片描述

  • 封包

在这里插入图片描述

host-gw

  • 必须二层连通
  • Pod 通信时相当于,把对方的宿主机当做网关
    • 本机上会有路由规则: 【对方 Pod IP 段】 —— 【对方主机 MAC 地址】
    • 这样本机 Pod 要发送给对方 Pod,就会直接发给对方主机,对方主机上当然会有自己所有 Pod 的路由信息,这样完成了通信
    • 同样,对方需要发回数据时,也是直接将数据发到本宿主机上,然后转发给对应的 Pod
    • 封装的数据包为 【对方主机mac地址】【Pod IP 地址】【端口】 【数据信息】
      • 因此这样要求必须二层连通,直接可以到达对方宿主机
      • 若是三层,中间的路由器不认识【Pod IP 地址】,也无法解析到【下一跳】,因此【不知道该发到哪】,所以只能二层连通
      • 不过 Calico BGP 解决了此问题,支持 BGP 的路由器中也会存储着 【Pod IP】—— 【宿主机MAC地址】的映射信息
        • 因此知道该如何转发
        • 这个信息的分发和维护,是BGP的内在机制 (好像是 Brid 组件)
flannel
  • flannel
    • 在这里插入图片描述
calico
  • calico
    • Calico 项目的架构就非常容易理解了。它由三个部分组成
      • Calico 的 CNI 插件。这是 Calico 与 Kubernetes 对接的部分。
      • Felix。它是一个 DaemonSet,负责在宿主机上插入路由规则(即:写入 Linux 内核的 FIB 转发信息库),以及维护 Calico 所需的网络设备等工作。
        • 这里最核心的“下一跳”路由规则,就是由 Calico 的 Felix 进程负责维护的
      • BIRD。它就是 BGP 的客户端,专门负责在集群里分发路由规则信息。
        • 两种模式 Node-to-Node Mesh 和 BGP Route Reflector
        • Calico 维护的网络在默认配置下,是一个被称为“Node-to-Node Mesh”的模式。
        • Node-to-Node Mesh 每台宿主机上的 BGP Client 都需要跟其他所有节点的 BGP Client 进行通信以便交换路由信息。但是,随着节点数量 N 的增加,这些连接的数量就会以 N²的规模快速增长,从而给集群本身的网络带来巨大的压力。就是每个 Node 都要连接其他 N-1 个 Node
        • Node-to-Node Mesh 模式一般推荐用在少于 100 个节点的集群里。而在更大规模的集群中,你需要用到的是一个叫作 Route Reflector 的模式。
        • 在这种模式下,Calico 会指定一个或者几个专门的节点,来负责跟所有节点建立 BGP 连接从而学习到全局的路由规则。而其他节点,只需要跟这几个专门的节点交换路由信息,就可以获得整个集群的路由规则信息了。
      • felix 和 bird 在部署时候,其实统一部署在一个组件内,叫做 calico-node
      • 除了对路由信息的维护方式之外,Calico 项目与 Flannel 的 host-gw 模式的另一个不同之处,就是它不会在宿主机上创建任何网桥设备。
    • 在这里插入图片描述

cni 插件

  • 在 k8s 中

    • Kubernetes 是通过一个叫作 CNI 的接口,维护了一个单独的网桥来代替 docker0。这个网桥的名字就叫作:CNI 网桥,它在宿主机上的设备名称默认是:cni0。
    • 以 Flannel 的 VXLAN 模式为例,在 Kubernetes 环境里,它的工作方式跟我们在上一篇文章中讲解的没有任何不同。只不过,docker0 网桥被替换成了 CNI 网桥而已
    • 在这里插入图片描述
  • 分类

设备创建类Main第一类,叫作 Main 插件,它是用来创建具体网络设备的二进制文件。比如,bridge(网桥设备)、ipvlan、loopback(lo 设备)、macvlan、ptp(Veth Pair 设备),以及 vlan。
ip 分配类IPAM第二类,叫作 IPAM(IP Address Management)插件,它是负责分配 IP 地址的二进制文件。
比如,dhcp,这个文件会向 DHCP 服务器发起请求;host-local,则会使用预先配置的 IP 地址段来进行分配。
网络管控类第三类,是由 CNI 社区维护的内置 CNI 插件。比如:flannel,就是专门为 Flannel 项目提供的 CNI 插件;
tuning,是一个通过 sysctl 调整网络设备参数的二进制文件;
portmap,是一个通过 iptables 配置端口映射的二进制文件;
bandwidth,是一个使用 Token Bucket Filter (TBF) 来进行限流的二进制文件。
从这些二进制文件中,我们可以看到,如果要实现一个给 Kubernetes 用的容器网络方案,其实需要做两部分工作,以 Flannel 项目为例:
基础网络构建首先,实现这个网络方案本身。这一部分需要编写的,其实就是 flanneld 进程里的主要逻辑。比如,创建和配置 flannel.1 设备、配置宿主机路由、配置 ARP 和 FDB 表里的信息等等。
容器网络构建然后,实现该网络方案对应的 CNI 插件。这一部分主要需要做的,就是配置 Infra 容器里面的网络栈,并把它连接在 CNI 网桥上。
cni插件放置由于 Flannel 项目对应的 CNI 插件已经被内置了,所以它无需再单独安装。
而对于 Weave、Calico 等其他项目来说,我们就必须在安装插件的时候,把对应的 CNI 插件的可执行文件放在 /opt/cni/bin/ 目录下。
cni插件配置文件flanneld 启动后会在每台宿主机上生成它对应的 CNI 配置文件(它其实是一个 ConfigMap),从而告诉 Kubernetes,这个集群要使用 Flannel 作为容器网络方案。路径 /etc/cni/net.d/
cni配置文件加载需要注意的是,在 Kubernetes 中,处理容器网络相关的逻辑并不会在 kubelet 主干代码里执行,
而是会在具体的 CRI(Container Runtime Interface,容器运行时接口)实现里完成。对于 Docker 项目来说,它的 CRI 实现叫作 dockershim,你可以在 kubelet 的代码里找到它。
所以,接下来 dockershim 会加载上述的 CNI 配置文件。
多个配置文件需要注意,Kubernetes 目前不支持多个 CNI 插件混用。如果你在 CNI 配置目录(/etc/cni/net.d)里放置了多个 CNI 配置文件的话,dockershim 只会加载按字母顺序排序的第一个 cni 配置文件。
多个配置插件另一方面,CNI 允许你在一个 CNI 配置文件里,通过 plugins 字段,定义多个插件进行协作
比如,在我们上面这个例子里,Flannel 项目就指定了 flannel 和 portmap 这两个插件。
这时候,dockershim 会把这个 CNI 配置文件加载起来,并且把列表里的第一个插件、也就是 flannel 插件,设置为默认插件。而在后面的执行过程中,flannel 和 portmap 插件会按照定义顺序被调用,从而依次完成“配置容器网络”和“配置端口映射”这两步操作。
CNI 插件的工作原理当 kubelet 组件需要创建 Pod 的时候,它第一个创建的一定是 Infra 容器。
所以在这一步,dockershim 就会先调用 Docker API 创建并启动 Infra 容器,紧接着执行一个叫作 SetUpPod 的方法。
这个方法的作用就是:为 CNI 插件准备参数,然后调用 CNI 插件为 Infra 容器配置网络。
这里要调用的 CNI 插件,就是 /opt/cni/bin/flannel;而调用它所需要的参数,分为两部分。
指定动作(创建or删除)第一部分,是由 dockershim 设置的一组 CNI 环境变量。其中,最重要的环境变量参数叫作:CNI_COMMAND。
它的取值只有两种:ADD 和 DEL。这个 ADD 和 DEL 操作,就是 CNI 插件唯一需要实现的两个方法。
其中 ADD 操作的含义是:把容器添加到 CNI 网络里;
DEL 操作的含义则是:把容器从 CNI 网络里移除掉。
而对于网桥类型的 CNI 插件来说,这两个操作意味着把容器以 Veth Pair 的方式“插”到 CNI 网桥上,或者从网桥上“拔”掉。
接下来,我以 ADD 操作为重点进行讲解。CNI 的 ADD 操作需要的参数包括:容器里网卡的名字 eth0(CNI_IFNAME)、Pod 的 Network Namespace 文件的路径(CNI_NETNS)、容器的 ID(CNI_CONTAINERID)等。这些参数都属于上述环境变量里的内容。其中,Pod(Infra 容器)的 Network Namespace 文件的路径,我在前面讲解容器基础的时候提到过,即:/proc/< 容器进程的 PID>/ns/net。
除此之外,在 CNI 环境变量里,还有一个叫作 CNI_ARGS 的参数。通过这个参数,CRI 实现(比如 dockershim)就可以以 Key-Value 的格式,传递自定义信息给网络插件。这是用户将来自定义 CNI 协议的一个重要方法。
补充配置文件(执行哪些cni插件)第二部分,则是 dockershim 从 CNI 配置文件里加载到的、默认插件的配置信息。
这个配置信息在 CNI 中被叫作 Network Configuration,它的完整定义你可以参考这个文档。dockershim 会把 Network Configuration 以 JSON 数据的格式,通过标准输入(stdin)的方式传递给 Flannel CNI 插件。
dockershim 对 Flannel CNI 插件的调用,其实就是走了个过场。Flannel CNI 插件唯一需要做的,就是对 dockershim 传来的 Network Configuration 进行补充。比如,将 Delegate 的 Type 字段设置为 bridge,将 Delegate 的 IPAM 字段设置为 host-local 等。
Delegate 字段的意思是,这个 CNI 插件并不会自己做事儿,而是会调用 Delegate 指定的某种 CNI 内置插件来完成。
  • cni 配置文件
$ cat /etc/cni/net.d/10-flannel.conflist 
{
  "name": "cbr0",
  "plugins": [
    {
      "type": "flannel",
      "delegate": {
        "hairpinMode": true,
        "isDefaultGateway": true
      }
    },
    {
      "type": "portmap",
      "capabilities": {
        "portMappings": true
      }
    }
  ]
}

k8s service

  • Service 是由 kube-proxy 组件,加上 iptables 来共同实现的。

  • Kube-proxy 通过监听 Service 对象的创建,创建出相应的 iptables 规则

    • 如创建一个 3副本的 deployment,并暴露该 deployment 为一个 k8s Service
    • kube-proxy 监听到该 Service 的创建,首先会创建一个 iptables,过滤 IP 包(目的 ip 是该 Service IP,目的端口是该 Service 端口),然后跳转到另一个 iptables 链 A
    • 该 iptables 链有一组 iptables 规则(共三条,对应3个副本),进行随机跳转(各1/3概率选中),选中一条规则,跳转到另一条 iptables链(B 或 C 或 D)
    • 假如上面选中了 iptables 链 B,该链对应了 Pod-1,包含一组操作,进行 DNAT,将上面的 Service IP + Port 替换为 Pod-1 IP + Pod-1 Port,实现真正的流量导向
  • 在 Kubernetes 中,Service 和 Pod 都会被分配对应的 DNS A 记录(从域名解析 IP 的记录)。

    • 对于 ClusterIP 模式的 Service 来说(比如我们上面的例子),它的 A 记录的格式是:…svc.cluster.local。当你访问这条 A 记录的时候,它解析到的就是该 Service 的 VIP 地址。
    • 而对于指定了 clusterIP=None 的 Headless Service 来说,它的 A 记录的格式也是:…svc.cluster.local。但是,当你访问这条 A 记录的时候,它返回的是所有被代理的 Pod 的 IP 地址的集合。当然,如果你的客户端没办法解析这个集合的话,它可能会只会拿到第一个 Pod 的 IP 地址。
    • 此外,对于 ClusterIP 模式的 Service 来说,它代理的 Pod 被自动分配的 A 记录的格式是:…pod.cluster.local。这条记录指向 Pod 的 IP 地址。
    • 而对 Headless Service 来说,它代理的 Pod 被自动分配的 A 记录的格式是:…svc.cluster.local。这条记录也指向 Pod 的 IP 地址。
    • 但如果你为 Pod 指定了 Headless Service,并且 Pod 本身声明了 hostname 和 subdomain 字段,那么这时候 Pod 的 A 记录就会变成:pod 的 hostname…svc.cluster.local

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1544267.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

睿考网:不是会计专业能考中级会计师吗?

不是会计专业也是可以考中级会计师的&#xff0c;中级会计师报名条件中并没有对专业做明确的限制&#xff0c;不同的学历对工作年限的要求不一样&#xff0c;如果考生满足报考条件就可以参加。 1.具备大学专科学历&#xff0c;从事会计工作满5年。 2.具备大学本科学历或学士学…

【Linux】进程的基本概念(进程控制块,ps命令,top命令查看进程)

目录 01.进程的基本概念 程序与进程 进程的属性 02.进程控制块&#xff08;PCB&#xff09; task_struct的内容分类 组织进程 03.查看进程 ps命令 top指令 在计算机科学领域&#xff0c;进程是一项关键概念&#xff0c;它是程序执行的一个实例&#xff0c;是操作系统的…

【Linux】线程预备知识{远程拷贝/重入函数与volatile关键字/认识SIGCHILD信号/普通信号/实时信号}

文章目录 0.远程拷贝1.重入函数与volatile关键字2.认识SIGCHILD信号3.普通信号/实时信号 0.远程拷贝 打包资源&#xff1a;tar czf code.tgz *远程传输&#xff1a;scp code.tgz usr服务器ip:/home/usr/路径解压&#xff1a;tar xzf code.tgz 1.重入函数与volatile关键字 先看…

【智能算法】秃鹰搜索算法(BES)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2020年&#xff0c; Alsattar等人受到秃鹰猎食自然行为启发&#xff0c;提出了秃鹰搜索算法&#xff08;Bald Eagle Search&#xff0c;BES&#xff09;。 2.算法原理 2.1算法思想 BES主要分为三…

龙智亮相2024国际集成电路展览会暨研讨会(IIC Shanghai),分享芯片研发及管理解决方案与技术实践

2024年3月28-29日&#xff08;周四-周五&#xff09;&#xff0c;上海张江科学会堂&#xff0c;2024国际集成电路展览会暨研讨会&#xff08;IIC Shanghai 2024&#xff09;即将盛大开幕。龙智携芯片研发及管理解决方案、最佳实践与案例&#xff0c;以及惊喜大奖在#1A14展位等着…

第十九章 linux部署scrapyd

文章目录 1. linux部署python环境1. 部署python源文件环境2. 下载python3. 解压安装包4. 安装5. 配置环境变量6. 检查是否安装成功7. 准备python使用的包8. 安装scrapyd9. 配置scrapyd10. 开放6800端口 2. 部署gerapy1. 本机下载包2. 初始化3. 进入gerapy同步数据库4. 创建用户…

堂哥让我给他做个真人动漫头像

背景 堂哥最喜欢的动漫是死神。他给了我一张死神主角一户的头像&#xff0c;以及自己的头像&#xff0c;希望我产出一张真人动漫头像。 一户的头像&#xff1a; 堂哥自拍照&#xff1a; 最近&#xff0c;有大佬部署了个stable diffusion&#xff0c;正好拿来一试身手。 stab…

优质视频素材库排行榜前十名有哪些?

在视频创作的世界中&#xff0c;每一帧画面、每一个音符都承载着无限的可能。为了帮助你更好地探索这些可能性&#xff0c;我继续为你精选了一系列素材网站。这些网站不仅能够提供高质量的视频、音效和图像素材&#xff0c;还能激发你的创意灵感&#xff0c;助你一臂之力。 1&…

利器 | 测试必会之 Linux 三剑客 ( grep / awk / sed )

Linux 给人的印象是黑乎乎的神秘窗口&#xff0c;文本操作和数据处理似乎没有 Windows 窗口界面直观方便。其实Linux 有自己的独特的法宝&#xff0c;称之为三剑客&#xff1a;grep&#xff0c;awk 和 sed。你可以用这三件法宝很方便的处理数据 &#xff1a;查找&#xff0c;分…

时间戳的转换-unix时间戳转换为utc时间(python实现)

import datetimetimestamp = 1711358882# 将时间戳转换为UTC时间 utc_time = datetime.datetime.utcfromtimestamp(timestamp)# 格式化并输出时间 formatted_time = utc_time.strftime(%Y-%m-%d %H:%M:%S) print(formatted_time)同样:UTC如何转换为unix时间戳 from datetime …

【考研数学】如何搭配好《660》+《880》组合?

如果1800题都做不明白&#xff0c;那就不要去做880题660题 做完1800题之后&#xff0c;还迷迷糊糊&#xff0c;解题水平极低&#xff0c;都是犯了一个错误&#xff1a; 那就是为了做题而做题&#xff01; 如果这个习惯不改掉&#xff0c;那不管是做660题还是880题都起不到任…

穿越地心:3D可视化技术带你领略地球内部奇观

在广袤无垠的宇宙中&#xff0c;地球是一颗充满生机与奥秘的蓝色星球。我们每天都生活在这颗星球上&#xff0c;感受着它的温暖与恩赐&#xff0c;却往往忽略了它深邃的内部世界。 想象一下&#xff0c;你能够穿越时空&#xff0c;深入地球的核心&#xff0c;亲眼目睹那些亿万年…

ssm005基于SSM框架的购物商城系统+jsp

购物商城系统的设计与实现 摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所以对于信息的宣传和管理就…

GL-15过流继电器 10A、5A 板前接线带附件 JOSEF约瑟

系列型号&#xff1a; GL-11过流继电器; GL-12过流继电器; GL-13过流继电器; GL-14过流继电器; GL-15过流继电器; GL-16过流继电器; GL-17过流继电器; 用途 GL-10系列过流继电器(以下简称继电器)具有反时限特性&#xff0c;应用于电机、变压器等主设备以及输配电系统的继电保…

SQLAlchemy操作数据库

数据库是一个网站的基础。 比如 MySQL 、 MongoDB 、 SQLite 、 PostgreSQL 等&#xff0c;这里我们以 MySQL为例进行讲解。 SQLAlchemy 是一个 ORM 框架 我们会以 MySQL SQLAlchemy 组合进行讲解。 在操作数据库操作之前&#xff0c;先确保你已经安装了以下两个插件&#…

spring 环境配置

1.安装idea 建议安装2020以上的版本 idea 旗舰版 下载路径 破解软件和激活码地址&#xff0c;破解软件相对麻烦&#xff0c;建议用激活码(可能不稳定)。 2.安装 JDK 版本选择1.8的 安装完以后记得配置环境变量&#xff0c;配置完以后输入java -version查看是否安装成功 参考…

Word邮件合并

Word邮件合并功能可以解决在Word中批量填写内容的需求&#xff0c;当需要大量格式相同&#xff0c;只修改少数相关内容时&#xff0c;例如利用Word制作工资条&#xff0c;通知函&#xff0c;奖状等等&#xff0c;同时操作也非常简单灵活。下面通过例子来说明邮件合并的使用方法…

技术与业务:项目成功的黄金关键

目录 前言1 明确业务需求2 技术选择与业务匹配3 解决方案设计与业务一致4 开发与实施5 持续监控与优化6 反馈循环与持续改进结语 前言 在当今数字化时代&#xff0c;技术与业务之间的紧密联系对于项目的成功至关重要。无论是开发新产品、提供服务还是改进现有流程&#xff0c;…

QT_day3:2024/3/22

作业1&#xff1a;设计界面 使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin…