Lazy loaded image
Kubernetes 网络基础
字数 11908阅读时长 30 分钟
2024-12-21
2024-12-20
type
status
date
slug
summary
tags
category
password

1:前情提要

前面的文章里面我们详细了解过 Flannel 和 Calico 的 CNI 了,但似乎发现,好多人没有网络的基础,所以,这篇文章相当于是补全一下前面两个 CNI 的网络基础
Kubernetes 网络基础






2:Wireshark - NC - TCPDump

其实我们了解 Kubernetes 的模型的话,就不需要去详细的参照 OSI 了,我们只需要了解到 IP / MAC 到 OSI 四层就可以了,在这个过程中我们会用到几个工具,比如 Wireshark,Tcpdump,NC 等,Wireshark 是在 Windows 平台的抓包工具,而其他两个则是在 Linux 平台的工具,我们都要准备好
我们就简单使用 NC 来看一下 TCP / IP 的一个案例
notion image
我们通过 Wireshark 过滤出来我们需要的流量,我们发数据肯定是通过 PSH 发送,所以你可以在 PSH 的包内看到我们的原始数据
notion image
然后我们发送数据的这个包上面的三个包是什么,这个毋庸置疑,肯定是 TCP 的三次握手了,这也是一个非常的简单的 TCP 三次握手然后数据传输的一个包,下面是监听 UDP 的方法
notion image
UDP 的特性我们也都知道,它只负责把数据丢出去,具体收没收到,它不管,而且也没有确认的机制,所以我们就只能看到一个数据被通过 UDP 发出去了,如果你想确认对方收到了没,你需要去对方的服务器去抓一个包来看看,下面是我抓到的目标机器的包
notion image
可以看到,数据是收到了,但是它也不会给任何回复的,这也是 UDP 的特点,而且 UDP 这个建立连接也是双向的,服务端也可以向客户端发送消息的。下面我们开始真正的 IP / MAC 的讲解

3:VETH PAIR 原理

说起来 veth pair,从这个名字就不难看出,它应该是成对出现的,而它对应的是一对虚拟的以太网设备,一对 veth 通过一个虚拟链路连接在一起,它们通常用于创建类似网桥或隧道的网络拓扑,其中一个设备可以被看做虚拟机或容器的网络接口,而另一个接口则是连接到主机的网络栈,它和 eth 最大的区别就是它是虚拟的,而 eth 是物理的接口
下面我们将使用 contaiberlab 来模拟一下 veth pair 的环境
  • 关于 Contaiberlab 的学习,各位可以去官网了解下:containerlab
  • 我们这里使用的 Kind 是 Linux Container,所以依赖 Docker,前提就是要先安装 Docker 环境
可以看到我们手动添加的一个网卡 net0,那么我们怎么确定谁和谁是 pair (一对) 的呢?我们可以借助 ethtool 来做
可以看到我们查询到了 net0 网卡的对端索引的 id 是 27,另一个容器的是 28,我们也可以从他的网卡名看出一些端倪,也就是 net0@if27,net0@if28,也就是说,目前的情况就是这两个容器的 net0 网卡互为对端的 pair 接口,也就形成了 veth-pair 的场景了,然后我们就可以互相去 Ping 对方去看看网络,Veth Pair 的基础就是双方都是互通的
可以看到,双方 Ping 对方都是互通的,那么我们要知道一个点,就是容器它其实就是使用的 Linux 的内核隔离机制,也就是各种的 Namespace,而我们基础的这个网络就是 NetNamespace 的隔离,你可以在宿主机使用 ip netns ls 看到我们的两个容器的 netns
可以看到对应的两个容器的 netns,和 docker 操作一样,你可以在这个 netns 内启动一个 bash 命令来操作这个 netns
你会发现这个时候和你登录到容器内的查看到的网卡信息是一样的,这其实就是 docker exec 的原理,直接在指定的 namespace 启动一个 bash 或者 sh 的进程,然后你可以看到它自带了一个 eth0 的网卡,它的 pair的索引是 if26,其实这个接口不在别的地方,就在你的容器的宿主机上,你可以退出这个容器的 namespace 然后在宿主机上找到这个接口
可以看到最下面这个网卡的索引 id 就是我们那个容器的 eth0 的 pair 的另一端,它连接在了宿主机上(root namespace),也就是说,现在那个容器和 root namespace 是互通的
当数据包到达 root namespace 之后你就可以做一些操作了,比如 routing,overlay,underlay 等操作,比如基于 overlay 的 vxlan,ipip 等,但是我们要知道如果是基于 routing,那么是不存在 SNAT 的,而是直接查找路由表转发(这依赖你的 Linux 开启内核转发),其实到目前为止主流的 K8S 的 CNI 从容器的 namespace 到 root namespace 的方案采用的大多都是 veth pair 的方案。
我们上面使用的是 containerlab 配合 docker 实现的一个案例,但是可能对于有些同学还是不太直观,所以下面我们将手工实现一个 veth pair 的案例
我们在前面也说了,容器本质上就是基于 Linux 的内核的各种 Namespace 隔离实现的,也就是说,我们手工去实现 veth pair 也是需要使用到 namespace 的
这样设置完之后,也就是说宿主机的一对 veth-pair 设备就被放到了不同的 namespace 内了,现在你再去宿主机上就看不到那两张网卡了,然后可以去任何一个 namespace 去测试对方
这个时候你会发现,这就实现了我们上面用 contaiberlab 实现 veth pair 的案例了,从这里我们不难看出,其实 pair 的作用就是将流量从一个 namespace 引入到另一个 namespace
另外还有一个问题,你会发现你创建出来的 namespace 是无法 ping 通自己的,原因也很简单,是因为你的回环接口没有开启,不过你要想知道具体的原因,需要更深入的理解 lo 网卡
在 Calico 中,它的 veth pair 就是一端在 Pod 的 namespace 内,另一端在宿主机上,然后同节点主机通信走的是 SNAT 进行通信
在 flannel 中,它的 veth pair 稍微做了一些修改,它引入了一个 bridge 的概念,它的 host 端的那个接口被连接在了一个叫做 cni0 的 bridge 设备上,而这个 cni0 我们就可以把它看作是一个交换机,而这个网络架构下,同节点的 Pod 通信就靠这个二层的网络交换机进行通信了,下面我们将要讲的就是这个网桥
在此之前,我们需要说明,我们在 linux 操作网桥的话,需要用到一个 brctl 的命令,而这个命令在 bridge-utils 的工具包中
安装完成之后我们来看一下怎么使用这个命令
可以看到,这里面为什么会有一个 docker0 的网桥呢?其实也不用奇怪,因为这是 docker 默认的,它是用来支持 docker 的四种网络模式中的 bridge 模式的网桥,你可以用 docker 命令看到它
而如果你是 flannel 的 CNI,那么这个 brctl show就可以看到一个 cni0 的网桥了,而你就可以基于 cni0 插入 N 个 Pod 的 namespace 的接口了,下面我们也可以做一下这个案例
完成之后我们再次使用 brctl show 来看看
可以看到,这个时候我们的 veth pair就接入到了 bridge 设备上了,然后我们可以尝试通信一下
可以看到,这两个依旧是可以通信,相对于 Calico 的那个 veth pair,多了一个 bridge 设备,然后你的网卡不再直接接入到 root namespace 了,而是通过 cni0 才接入 root namespace 中了
notion image
这就是两个 CNI 的最基本的区别,下面是一个案例,我使用了 Sealos 来完成这个操作
下面是 Flannel 的集群的案例
我们上面实现了 veth pair 和 bridge 的案例,各位也可以去手动实现一下试一试

4:HOST-GW 案例

那么下面我们要学习的一个网络就是 HOST-GATEWAY 的网络,它比起 Overlay 要简单的多,根据它的名字,顾名思义,它就是一个网关,通过路由转发实现的一个方式,也就是全程查询路由表,而不走其他的任何东西,它也不涉及到任何的封装之类的东西,但是它虽然不需要封装任何东西,但是你需要将自己的路由暴露出去,也就是说,你需要借助一个第三方的设备(路由器)去学习到路由,然后进行路由寻址这个操作,所以下面我们依旧会借助 Containerlab 来做一个案例,我们这里的 Containerlab 案例中不直接通过主机做网关,而是用到了一个虚拟的路由系统,大概是下面的图
notion image
下面是我们这次试验的网络架构图
notion image
下面开始启动我们的 containerlab 架构
notion image
首先可以确定源 IP/MAC 都是 server1 这个容器的,根据路由的规则,下一条的目的 MAC 肯定不应该是目标主机,而是路由接口的 MAC,我们可以去看一下
根据最上面的拓扑图,我们可以看到确实是 eth1 的 MAC,那么这个时候,其实 server1 的流量就已经到达了 gw0 了,那么这个时候 gw0 因为有静态路由的原因,它会直接找去往 10.1.8.0 的静态路由,找到了,它就会把流量转给 172.12.1.11 这个 gw1 的接口,然后 gw0 再查询自己本地的路由就可以看到,自己的 eth1 接口就是 10.1.8.0 的网络,然后就会把流量从 eth1 接口转到下面连接的主机或者交换机,然后下面的主机收到包之后进行回包,而回包的 IP/MAC 就是相反的在上面的抓包中也可以看到
notion image
那么这就是我们这个拓扑的一个路由的过程,这也是 HOST-GW 模式的一个基础,下面我们也将通过手动的方式来演示以下如何实现 HOST-GW 模式
按照这个做完之后,我们也就实现了 10.0.0.11 和 10.0.0.12 两个主机作为网关实现的 HOST-GW 了
这个拓扑其实也是一样的,只是把路由功能放到了 Linux 主机上,然后根据 Linux 内核提供的路由功能进行流量转发,仅此而已,各位也可以抓包看看效果

5:CNI 网络模型

6:CNI 工作原理

首先我们推荐大家去看一个网站:https://cni.dev
它里面推荐了目前被社区接受的大多数 CNI,比如目前市面上比较常用的:Calico,Cilium,Terway,Kube-OVN,Multus-Cni 等等等等的 CNI,当然这不是我们要看的重点,我们主要要看的重点是它里面的一个 plugins,然后从里面你可以看到一个 IPAM,它分为三种模式,分别是 DHCP,HOST-LOCAL,STATIC IP,其次就是一个 CNI 所支持的 Main 和 Meta 了,看着是不是非常的熟悉,其中有一些我们上面已经实战过了,而 CNI 的核心其实就是节点上的 /opt/cni/bin 下面的二进制文件,它其实有很多二进制文件,而 CNI 也给到了这些二进制文件的下载地址
可以看到,这里面这么多的二进制文件,每一个二进制文件对应的都是 CNI 的一种模式,可以看出,CNI 到底给我们提供了多少种模式,市面上的 CNI 其实功能也都是没那么的全面,比如你装了 flannel,calico,cilium 之类的,它们也会在这里出现,包括但不限于还有其他的一些东西,比如 Bird 之类的,总之这些都是负责干活的工具,那么说到干活了,肯定得有说这个活谁干,怎么干,那么这个时候我们就又得看一个目录了
这个目录里面呢会存在一个 CNI 的配置,而这里面的 CNI 的配置对应的一些功能都可以在 cni.dev 这个网站找到,当然了,有些配置你可能找不到,那是因为可能是 CNI 自己实现的,所以你找不到,比如 Calico 的 ipam 功能,它用的就是自己实现的,它是 calico 自身实现的一个 ip 管理工具,而 CNI 插件里面其实也提供了 dhcp,host-local,static ip 等,当然了,不同的 CNI 提供的字段也是不一样的,比如你去拿 Calico 和 Flannel 的配置去对比,那差距就很大,因为 Calico 设计了更多复杂的功能,而 flannel 只是保持了一个能用且够用的功能而已,其次就也可以看到其他的都是去找 /opt/cni/bin 的文件,然后用这个插件去干什么,这就是 CNI 在做的事儿,总之还是总结一句话,配置在告诉你怎么做,然后 /opt/cni/bin 下面的东西就是找这些文件让它们去做
notion image
上一篇
镜像加速下线通知
下一篇
Flannel 集成 Kube-Network-Policies