关于kubernetes最复杂部分网络相关的系统性抽丝剥茧,瞬间打开你的脑仁,云原生能力提升10倍+

2023-08-17
14分钟阅读时长

k8s的网络部分相关可以说是云原生今天得以大规模在pass平台,sass平台得以迅速蹿红,得以被广泛使用的基础。而网络方面知识的复杂要求你有很深的积淀,记得有本书就http基础原理这本书600多页,全书都在讲http的原理,人家600多页正式出版的图书也才讲了http这一个点,所以你期待能有一篇文章把这些东西讲透说透?你信了就是你傻!虽然这些东西不能一次说透,但是能把这些知识串起来,你能对kubernetes网络相关的部分有个概括性的认识,出了问题知道该怎么定位问题,再依着自己的兴趣挑着狠狠加强,死死干住,那云原生领域就基本没有什么能难得倒你的问题了。

要说kubernetes的网络,那就逃不掉可能涉及到的以下这些概念,IP地址划分、路由转发、服务发现、MAC地址学习、网络通信等等等等。因为Kubernetes针对于网络的强化提供了CNI的接口,基于这个极其灵活的扩展点,基于此十分丰富的网络模型和策略出现了,丰富了kubernetes网络强化这个生态。

首先来聊一个概念就是网络模型,传统的服务器编译部署方式,在部署成网络集群的时候,思考一下,我们是怎么解决集群内机器间相互通信的?大概梳理一下思路,比如说用nginx搭建集服务集群,亦或是用HAProxy来搭建服务集群,都要指定一台master的机器?然后呢?然后就是让其他作为worker的机器能够知道哪一台是master,目的就是知道该服务于谁转发过来的流量,同时master机器上基于lua语言之流,在部署的keepalive的基础之上,开发相应的脚本,可以对于worker节点的在线离线存活状态进行检测,从而可以监控整体集群的运行状态,以备把集群的异常及时捕获,通过通知系统,让相应运维服务及时知道异常发生,及时解决所出现的异常。

这个传统的部署模型想必有点架构经验的人都十分谙熟,它应用的网络模型之所以有效,我们看下它解决了什么问题。master和worker之间的ip地址和端口彼此时透明的,同时nginx可以针对于流量的处理有行之有效的策略,比如说ip地址白名单,比如说GeoIP,比如说rateLimit控制,总之,得以管控流量的基本就是服务器之间的连接透明。而Kubernetes网络模型遵循的核心原则也是每个Pod都拥有一个唯一且独立的IP地址,无论Pod在同个集群里,亦或是Pod在不同的集群里,都可以通过IP地址的方式直接对其访问,而不需要借助于其他手段,达到的效果就是无论是集群内的Pod,还是不同集群的Pod,它们整体形成了一个扁平的可互相通信的网络组织。但是这种灵活性之所以能够实现,肯定就要求有一种机制可以让Pod可以像虚拟机或者是物理实体机那样执行端口分配、服务命名、服务发现、负载均衡、应用配置和迁徙等动作,而在Kubernetes这样庞大一个体系内,能支撑这些特征得以实现的核心模型,被命名成了“IP-Per-Pod”模型。

IP-Per-Pod通过我上面的描述,你头脑中应该有大概这样一个概念,就是在Pod内部或者外部,该Pod的IP地址、端口等信息都保持一致,因此,Pod内部和外部之间、Pod和Pod之间、Node和Pod之间,不同Node的Pod之间本身就能自成连接体系,压根就不需要NAT进行掺和什么事了。而没有NAT掺和进来的好处又显而易见,没有NAT之后,集群整体性能更好,源地址伪装的情况也就不复存在,因此也就具备了源地址溯源的能力,这对于集群维护和排除障碍也就非常有帮助。同时这个模型的推出又对于应用架构有很好的兼容性,怎么理解这句话?就是说你只要自研出部署方式在本地虚拟机集群把部署成功落地,那在Kubernetes集群上你就可以成功把这套拷贝过去,降低成本和风险的前提下成功秒级上云。同时这个模型还有另外一个好处,就是复用网络命名空间,这些容器之间可以通过同一个IP地址对外发送消息,通过同一个IP地址接收来自Pod之外的消息。形成的效果就是Pod彼此之间可以通过localhost加端口的形式直接访问,在整个集群范围内,每个Node都有一个与其他Node节点无交集的IP地址段,这个IP地址段内的IP地址会拿来分配该节点上的POD来使用。

Container Network Interface(CNI)

kubernetes的初衷是Google开源出来的容器编排的工具,如果讲容器编排就不得不再提一下Docker,因为它曾经是依仗自己的客群庞大及简单易用而与Google提出的行业标准分庭抗礼,但是最终还是败下阵来,但是从这次交锋也可以看得出,实际上容器编排,也就是产生虚拟环境这种技术不是什么新鲜玩意,Cgroups(Control Groups)的出现就是搞这事的,对Cgroups做下总结,它就是在Linux环境之下用于对一个或一组进程资源控制和监控的机制,它可以对于CPU使用时间、内存、磁盘I/O等进程所需资源进行限制,同时它对不同资源的具体管理工作由相应的Cgroup子系统(Subsystem)来实现,针对于不同类型的资源限制,不需要内核层面的代码重写和逻辑开发,只需要把限制策略在不同的子系统上进行关联即可,同时Cgroups在不同的系统资源管理子系统中以层树级(Hierarchy)的方式来组织管理,并且相互之间是相互渗透的,即每个Cgroup都可以包含其他子Cgroup,这就导致Cgroup能使用的资源除了受本Cgroups配置的资源参数限制,还受到父Cgroup设置的资源所限制。而它的存在,就潜在形成了一个行业标准,即:

  • Open Container Initiative(OCI) 轻量级开放式管理组织(项目)
  • OCI主要定义两个规范
    • Runtime Specification 文件系统包如何解压至硬盘,供运行时运行
    • Image Specification 如何通过构建系统打包,生成镜像清单(Manifest)、文件系统序列化文件、镜像配置

这个行业标准的出现就要求容器编排厂商都在以下几方面下功夫:

安全性、隔离性、便携性、可配额

也正因为最终Google成功干趴下Docker成为现行行业标准,成为云原生领域默认的技术选型,也导致它在容器编排方向有所强化和不断优化,导致这方面功力特别强,但是容器编排工具的灵活强大,导致弱项也暴露出来,就是网络,k8s公有云方案在GCE、AWS、Azure平台上大杀四方,但是私有云部署需求也与日俱增,基于这两方面重要的原因,所以网络就成了很大的瓶颈,不解决就要幻灭。Kubernetes最初解决这个问题的方案是引入了Kubenet,kubenet是一个非常简单,十分基础的网络插件,它本身并不支持任何跨节点之间的网络通信和网络策略等高级功能,而且只适用于linux系统,所以kubernetes亟需一种可以替代kubenet的更优秀方案,最终CoreOs公司和Docker公司都看到了kubernetes这个短板,因此相继推出了CNI(Container Network Interface)和CNM(Container Network Model)规范,最终CNI理念成功杀出,Kubernetes果断闪出身位迅速摘桃,基于此,Kubernetes也将CNI作为自己首选的网络插件接口的开发规范。

CNI的基本思想是在容器运行时环境中创建容器时,先创建好网络命名空间(netns),然后调用CNI插件为这个网络命名空间配置网络,之后再启动容器内进程。那CNI的工作机制是什么呢?它通过Json Schema结构定义了容器运行环境和网络插件之间的接口声明,描述当前容器网络的配置和规范,尝试通过一种普遍适用的方式来实现容器网络的标准化。并且它聚集只在于创建容器时分配网络资源(IP、网卡、网段等)和容器被回收时如何删除网络资源两个方面的能力。同时它作为Kubernetes和底层网络之间衔接的载体,它屏蔽了底层网络实现的细节,实现了Kubernetes和具体网络实现方案的解决,继而为Kubernetes提供了一个可以支撑其运行的网络组织结构,同时又克服了Kubernetes原先不具备的无法实现跨主机容器进行相互通信的短板。目前来看,Kubernetes选择CNI作为网络扩展是成功的,它同时也被rkt、Apache Mesos所采纳,社区扩展方案包括但不限于Flannel、Calio、Weave等也都是基于它的规范实现的,可见CNI规范的认可度何其之高。

目前官方提供的CNI网络插件包括如下三类:

Main:interface-creating
  • bridget: 创建一个桥接网络,并将宿主机和容器加入到这个桥接网络中
  • ipvlan: 在容器中加入一个ipvlan接口
  • lookback: 设置环回接口的状态的up状态
  • macvlan: 创建一个新的mac地址,并将所有到该地址的流量转发到容器
  • ptp: 创建一个新的veth对
  • vlan: 分配一个vlan设备
  • host-device:将宿主机现有的网络接口移到容器内
IPAM:IP address allocation
  • dhcp: 在宿主机上运行一个daemon进程并代表容器发起DHCP请求
  • host-local:维护一个已分配IP的本地数据库
  • static:向容器分配一个静态的IPV4/IPV6地址,这个地址仅用于调试的目的
Meta:other plugins
  • flannel:根据flannel配置文件生成一个网络接口
  • tuning:调整一个已有网络的sysctl参数
  • portmap:一个基于iptables的端口映射插件,将宿主机地址空间的端口映射到容器中
  • bandwidth:通过流量控制工具tbf来实现带宽限制
  • sbr:为接口配置基于源IP地址的路由
  • firewall:一个借助iptables或firewalld来添加规则来限制出入容器流量的防火墙插件

针对这三种类型的插件,官方都提供了一些内置的实现方案可供用户直接使用。Main插件也称为“网络插件(NetPlugin)”,它是一个由容器编排系统调用的可执行文件,实现某种特定的网络功能,负责创建/删除网络、向容器的网络空间插入一个网络接口以及向网络添加/删除容器,专注于连通pod与pod之间及pod与宿主机之间通信。

开发出的CNI插件的重要职责就是分配网络接口以及维护IP地址,以及配置与该接口相关的路由信息,这也导致出现另外一个问题,就是它这个接口承担的角色过多,它压力很大,比如说为用户提供期望的IP管理功能,如DHCP、HOST-LOCAL等。好多基于CNI的插件都有相同的代码结构,为了减轻CNI插件的负担,也为了使IP管理策略和网络插件的职责和功能相互独立,于是就出现一种新的插件类型IPAM(IP Address Management)。为什么做这种拆分呢?因为IPAM不提供网络功能,仅负责创建和删除IP地址池以及分配及回收容器的IP地址,Main作为IPAM的调用方,并向Main插件提供接口的IP、子网、网关、路由等信息,这些动作都依赖于Main插件具备的能力然后实现对这些拓展功能的支持。由于这种独立,就可以让各网络插件可以基于自己的实现需要和期望来选择适合自己的IPAM策略,提供了各类基于CNI的插件更大的灵活度和更弹性的扩展性。

IPAM也是一个与Main插件一样的可执行文件,对于可执行文件稍做扩展,如果你已经阅读过我之前分享过的kubernetes插件扩展的6大方向中,你应该不会陌生我针对于CSI插件开发举的例子,由于要对接persistent volume的小米商城评论帖子里的图片资源 ,因此就有了flexvolume方式基于shell脚本的可执行文件的非主流的“out-of-tree”的CSI插件的开发,那个插件放到对应目录下的可执行shell文件,这是可执行的一种插件存在形态。还有一个我也有举过例子,就是docker模式下的yml文件转成k8s上直接可用的kompose可执行二进制文件,虽然不好用,但是它也是一种可执行文件,mac上的几乎所有软件可以在客户端点击就打开,都缘于被编译成的可执行文件封装了加载的流程,协调了所有相关资源,最终你打开就是个可视化的应用,windows平台上的exe后缀打包文件一个原理,还有一些不可明状的配置方式,比如说某trojan-go端,实际上对它支持的客户端不太多,而且很多还要把v2ray的核心编译可执行文件也指定进来,还要把针对它做支持的插件扩展也引入进来,总之就是林林总总的可执行文件存在的形态基本都是放到环境变量执行目录,IPAM这也可执行文件也是一样,并通过CNI_PATH常量指定IPAM二进制文件所在位置,并与Main插件共享相同的环境变量,并且通过stdin和stdout接收网络配置和返回结果输出。既然可文件,就肯定有成功失败状态的响应,IPAM可执行文件的成功状态就是返回个0蛋,这点跟ffmpeg很类似,并把成功的执行结果类型输出到stdout上。

基于IPAM插件的架构思想,Meta插件存在的特点是它不实现任何的网络功能,不参与IP地址分配和回收,它调用其他网络工具或者插件完成一些管理或者测试功能。

举例的这三个插件,肯定最重要的主是Main插件了,因为它负责创建虚拟网络、为Pod生成网络接口设备、并将pod接入到网络内这些核心任务都靠Main插件来实现。当然,大量的第三方插件也不断涌现,这些插件的网络架构分成两大类:

  • Overlay网络

它是一个建立在现有物理网络之上的虚拟的、逻辑的网络。Overlay网络是建立在已有物理网络上的虚拟网络,具有独立的控制平面和转发平面,对于连接到Overlay的终端设备来说,物理网络是透明的,从而可以实现承载网络(物理网络)和业务网络(逻辑网络)的分离。

  • Underlay网络

它就是传统IT基础设施网络架构,由交换机、路由器、网关等设备组成,借助以太网协议、路由协议和VLAN协议等诸多协议完成网络通信和维护。此外,它还是Overlay网络的支撑网络,为Overlay网络提供数据通信服务。在容器技术中,Underlay网络特指借助驱动程序将宿主机底层网络接口直接暴露给给容器使用的一种网络构建技术,常用的实现方案包括MacVLAN、IP VLAN和直接路由等。

Overlay是如何来构建虚拟网络呢?我们前面提到的Main插件中,很重要的一个概念是VLAN,我们看这几个概念有啥通性,你没有看错,确实后缀都是VLAN,VLAN概念是一个分配一个vlan设备,而ipvlan和macvlan中,前者代表在容器中加入一个ipvlan接口,后者创建一个新的mac地址,将经由该地址的流量转发到容器内,共同特征稍加用心就能察觉出来,就是都是对于流转的数据包进行的接洽处理,而xvlan和vlan之间的区别,就在于对于这个流转数据包的处理方式,前者做的事情虽然修改了原始的Ethernet Header,但是整个网络的包仍然是原来的那个数据包,而后者是将原始的Ethernet Frame隐藏在UDP数据里面,经过VTEP封装之后,在网络线路上看起来只有VTEP之间的UDP数据传递,原始的网络数据包被掩盖了。

而Overlay构建网络的技巧,就跟这个XVLAN有很大关系,它是Overlay用于构建虚拟网络的脚手架,但是工具又岂只这一种就够的呢?其它的隧道协议如UDP、IPIP、GRE都是可借以来建立通信隧道,再通过这些隧道协议封装设备之间的通信报文,这里要好好总结一下,如果你在构建k8s镜像的时候,如果遇到过不同的pod之间通过flannel,到mac地址到docker bridge网络,到eth0这个pod内的网络,到宿主机网络之间怎么进行通信的,就需要你对二层的以太网或者三层的IP数据包封包经由UDP将传输协议,在报文的头信息中封装了信息传输的实际地址等信息,解包出来做实体数据转发,获取结果之后再封包回环的路径有清晰的认识,也就是隧道转发数据的实质就是将通信设备的报文封装成各自边缘设备之间的报文,通过建立在边缘设备之间的网络隧道完成数据的传输。这种方案的好处就是只需要相互通信的边缘设备之间支持隧道协议即可,对于底层网络的结构无任何特殊要求。Overlay网络的组成也比较清晰,就两层,数据平面和控制平面。以这两个词是不是特别熟悉,如果你配置过calico的sidecar,对于sidecar的概念有所了解的话,那么控制平面存在的意义你也一定不陌生,控制平台的职责就这三个: 当你遇到编程问题时,以下步骤可能会对你有所帮助:

  1. 理解问题:首先要当你遇到编程问题时,以下步骤可能会对你有所帮助:

  2. 理解问题:首先要 1. 服务发现

扫码关注公众号,可领取以下赠品:
《夯实基础的go语言体系建设》645页涵盖golang各大厂全部面试题,针对云原生领域更是面面俱到;
扫码加微信,可领取以下赠品:
【完整版】本人所著,原价1299元的《爱情困惑者必学的七堂课》;
100个搞定正妹完整聊天记录列表详情点这里
【完整版】时长7小时,原价699元《中国各阶层男性脱单上娶指南》;