ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Kubernetes-网络

2021-12-01 09:02:26  阅读:156  来源: 互联网

标签:容器 插件 Kubernetes 网络 Pod CNI


前言

本篇是Kubernetes第十一篇,大家一定要把环境搭建起来,看是解决不了问题的,必须实战,此篇文章概念比较多,后续我会继续出一些网络相关实战以及原理探索篇。

Kubernetes系列文章:
  1. Kubernetes介绍
  2. Kubernetes环境搭建
  3. Kubernetes-kubectl介绍
  4. Kubernetes-Pod介绍(-)
  5. Kubernetes-Pod介绍(二)-生命周期
  6. Kubernetes-Pod介绍(三)-Pod调度
  7. Kubernetes-Pod介绍(四)-Deployment
  8. Kubernetes-Service介绍(一)-基本概念
  9. Kubernetes-Service介绍(二)-服务发现
  10. Kubernetes-Service介绍(三)-Ingress(含最新版安装踩坑实践)

Kubernetes网络设计

在实际生产中,我们面临多种多样的业务场景,导致业务之间的调用关系更加复杂化,从而对网络提出更高的要求,对于Kubernetes来说主要解决以下四个问题:

  1. Pod中容器与容器之间的通信问题;

  2. Pod与Pod之间的网络通信问题;

  3. Pod与Service之间的通信问题;

  4. 集群内部与外部的通信问题;

第三和第四点我们在前面的章节已经讲过,大家可以在Service章节具体回忆下,重点介绍下第一、二点;

容器与容器之间的通信问题

介绍Pod时候我们说过Pod内部的容器共享Pod的命名空间的,因此在同一个Pod内的容器之间对于网络的各类操作,就和它们在同一台机器上一样,可以用localhost地址访问彼此的端口。

img
img

Pod与Pod之间的网络通信问题

每个Pod都有自己单独的IP,两个Pod既有可能运行在同一个Node上,也有可能运行在不同的Node上,因此对于Pod之间的通信可以分为两类:

同一个Node内的Pod之间的通信

对于在同一台机器上的两个Pod来说,都是连接到同一个docker0网桥上,它们的IP地址IP1、IP2都是从docker0网段上动态获取的,它们和网桥本身的IP3是同一个网段的,Pod1和Pod2处于同一局域网内,它们之间可以通过docker0作为路由进行通信。

img
img
不同Node上的Pod之间的通信

在Kubernetes的网络世界中,Pod之间假设是通过访问对方的Pod IP进行通信的,而不同Node之间的通信只能通过Node的物理网卡进行,Pod的IP地址是由各Node上的docker0网桥动态分配的。我们想要实现跨Node的Pod之间的通信,至少需要满足下面两个条件:

  1. Kubernetes集群中对Pod的IP分配不能有冲突;
  2. Pod IP 和Node IP之间的映射关系,通过Node IP转发到Pod IP;

根据条件1的要求,Kubernetes会再部署的时候对docker0的IP地址进行规划,保证每个Node上的docker0地址都没有冲突,此外Kubernetes会记录所有正在运行的Pod的IP分配信息,并将这些信息保存到etcd中,这样我们就可以知道Pod IP和Node IP之间的映射关系。

根据条件2要求,Pod中的数据在发送出去的时候,需要一个机制能够知道对方Pod的IP地址挂载到那个具体的Node上,这样就可以将数据发送到对应的宿主机上,宿主机将响应的数据转发到具体的docker0上,当数据到达docker0以后,就会将对应的数据转发到对应的容器上了。

img
img

CNI

Kubernetes本身并不负责网络通信,Kubernetes提供了容器网络接口CNI,具体的网络通信交给CNI插件来负责,开源的CNI插件非常多,像Flannel、Calico等,各大云厂商也都自己定制的CNI。

img
img

为什么会有CNI

CNI是Container Network Interface的缩写,简答说就是容器解决网络问题,提供的一个标准的,通用的接口。现在有各种各样的容器平台:docker,kubernetes,mesos,我们也有各种各样的容器网络解决方案:flannel,calico,weave,并且还有各种新的解决方案在不断涌现。如果每出现一个新的解决方案,我们都需要对两者进行适配,那么由此带来的工作量必然是巨大的,而且也是重复和不必要的。事实上,我们只要提供一个标准的接口,更准确的说是一种协议,就能完美地解决上述问题。一旦有新的网络方案出现,只要它能满足这个标准的协议,那么它就能为同样满足该协议的所有容器平台提供网络功能,而CNI正是这个标准接口协议。

什么是CNI

CNI是一个接口协议,用于连接容器管理系统和网络插件。前者提供一个容器所在的network namespace(从网络的角度来看,network namespace和容器是完全等价的),后者负责将network interface插入该network namespace中(比如veth的一端),并且在宿主机做一些必要的配置(例如将veth的另一端加入bridge中),最后对namespace中的interface进行IP和路由的配置。那么CNI的工作其实主要是从容器管理系统处获取运行时信息,包括network namespace的路径,容器ID以及network interface name,再从容器网络的配置文件中加载网络配置信息,再将这些信息传递给对应的插件,由插件进行具体的网络配置工作,并将配置的结果再返回到容器管理系统中。

img
img

CNI仅关注在创建容器时分配网络资源,和在销毁容器时删除网络资源,这使得CNI规范非常轻巧、易于实现,得到了广泛的支持。在CNI模型中只涉及两个概念:容器和网络。

容器(Container):是拥有独立Linux网络命名空间的环境,例如使用Docker或rkt创建的容器。容器需要拥有自己的Linux网络命名空间,这是加入网络的必要条件。

网络(Network):表示可以互连的一组实体,这些实体拥有各自独立、唯一的IP地址,可以是容器、物理机或者其他网络设备(比如路由器)等。

对容器网络的设置和操作都通过插件(Plugin)进行具体实现,CNI插件包括两种类型:CNI Plugin和IPAM(IP Address Management)Plugin。CNI Plugin负责为容器配置网络资源,IPAM Plugin负责对容器的IP地址进行分配和管理。IPAM Plugin作为CNI Plugin的一部分,与CNIPlugin协同工作。

插件介绍

CNI Plugin插件

CNI Plugin包括3个基本接口的定义:添加(ADD)、删除(DELETE)、检查(CHECK)和版本查询(VERSION)。这些接口的具体实现要求插件提供一个可执行的程序,在容器网络添加或删除时进行调用,以完成具体的操作。

添加:将容器添加到某个网络。主要过程为在Container Runtime创建容器时,先创建好容器内的网络命名空间(Network Namespace),然后调用CNI插件为该netns进行网络配置,最后启动容器内的进程。添加接口的参数如下:

  • Version:CNI版本号;

  • ContainerID:容器ID;

  • Network Namespace path:容器的网络命名空间路径,例如/proc/[pid]/ns/net;

  • Network configuration:网络配置JSON文档,用于描述容器待加入的网络;

  • Extra arguments:其他参数,提供基于容器的CNI插件简单配置机制;

  • Name of the interface inside the container:容器内的网卡名,返回的信息如下:

  • Interfaces list:网卡列表,根据Plugin的实现,可能包括Sandbox Interface名称、主机Interface名称、每个Interface的地址等信息;

  • IPs assigned to the interface:IPv4或者IPv6地址、网关地址、路由信息等;

  • DNS information:DNS相关的信息;

删除:容器销毁时将容器从某个网络中删除。删除接口的参数如下:

  • Version:CNI版本号;

  • ContainerID:容器ID;

  • Network Namespace path:容器的网络命名空间路径,例如/proc/[pid]/ns/net;

  • Network configuration:网络配置JSON文档,用于描述容器待加入的网络;

  • Extra arguments:其他参数,提供基于容器的CNI插件简单配置机制;

  • Name of the interface inside the container:容器内的网卡名;

检查:检查容器网络是否正确设置。检查接口的参数如下:

  • Version:CNI版本号;

  • ContainerID:容器ID;

  • Network Namespace path:容器的网络命名空间路径,例如/proc/[pid]/ns/net;

  • Network configuration:网络配置JSON文档,用于描述容器待加入的网络;

  • Extra arguments:其他参数,提供基于容器的CNI插件简单配置机制;

  • Name of the interface inside the container:容器内的网卡名;

版本查询:查询网络插件支持的CNI规范版本号。无参数,返回值为网络插件支持的CNI规范版本号。

IPAM Plugin插件

为了减轻CNI Plugin对IP地址管理的负担,在CNI规范中设置了一个新的插件专门用于管理容器的IP地址(还包括网关、路由等信息),被称为IPAM Plugin。通常由CNI Plugin在运行时自动调用IPAM Plugin完成容器IP地址的分配。

IPAM Plugin负责为容器分配IP地址、网关、路由和DNS,典型的实现包括host-local和dhcp。与CNI Plugin类似,IPAM插件也通过可执行程序完成IP地址分配的具体操作。IPAM可执行程序也处理传递给CNI插件的环境变量和通过标准输入(stdin)传入的网络配置参数。

如果成功完成了容器IP地址的分配,则IPAM插件应该通过标准输出(stdout)返回JSON报文。包括ips、routes和dns三段内容:

  • ips段:分配给容器的IP地址(也可能包括网关);

  • routes段:路由规则记录;

  • dns段:DNS相关的信息;

Kubernetes网络插件

Kubernetes管理的是集群,Kubernetes中的网络要解决的核心问题就是每台主机的IP地址网段划分,以及单个容器的IP地址分配。需要做到以下几点:

  1. 保证每个Pod拥有一个集群内唯一的IP地址;

  2. 保证不同节点的IP地址划分不会重复;

  3. 保证跨节点的Pod可以互相通信;

  4. 保证不同节点的Pod可以与跨节点的主机互相通信;

Kubernetes目前支持两种网络插件的实现。

CNI插件:根据CNI规范实现其接口,以与插件提供者进行对接。

kubenet插件:使用bridge和host-local CNI插件实现一个基本的cbr0。

为了在Kubernetes集群中使用网络插件,需要在kubelet服务的启动参数上设置下面两个参数:

  • --network-plugin-dir:kubelet启动时扫描网络插件的目录。
  • --network-plugin:网络插件名称,对于CNI插件,设置为cni即可,无须关注--network-plugin-dir的路径。对于kubenet插件,设置为kubenet,目前仅实现了一个简单的cbr0 Linux网桥。

在设置--network-plugin="cni"时,kubelet还需设置下面两个参数。

  • --cni-conf-dir:CNI插件的配置文件目录,默认为/etc/cni/net.d。该目录下配置文件的内容需要符合CNI规范。
  • --cni-bin-dir:CNI插件的可执行文件目录,默认为/opt/cni/bin。

开源容器网络方案

Kubernetes的网络模型假定了所有Pod都在一个可以直接连通的扁平网络空间中。若需要实现这个网络假设,需要实现不同节点上的Docker容器之间的互相访问,然后运行Kubernetes。目前已经有多个开源组件支持容器网络模型。如Flannel、Open vSwitch、直接路由和Calico。

Flannel

Flannel是一种基于overlay网络的跨主机容器网络解决方案,即将TCP数据包封装在另一种网络包里面进行路由转发和通信,Flannel是CoreOS开发,Flannel之所以可以搭建Kubernetes依赖的底层网络,是因为它能实现以下两点:

  1. 它能协助Kubernetes,给每一个Node上的Docker容器都分配互相不冲突的IP地址;
  2. 它能在这些IP地址之间建立一个Overlay Network,通过这个网络将数据包原封不动地传递到目标容器内
image.png
image.png

Flannel首先创建了一个名为flannel0的网桥,而且这个网桥的一端连接docker0网桥,另一端连接一个叫作flanneld的服务进程。flanneld进程上连etcd,利用etcd来管理可分配的IP地址段资源,同时监控etcd中每个Pod的实际地址,并在内存中建立了一个Pod节点路由表;flanneld进程下连docker0和物理网络,使用内存中的Pod节点路由表,将docker0发给它的数据包包装起来,利用物理网络的连接将数据包投递到目标flanneld上,从而完成Pod到Pod之间的直接地址通信。

Flannel之间的底层通信协议的可选技术包括UDP、VxLan、AWS VPC等多种方式。通过源flanneld封包、目标flanneld解包,最终docker0收到的就是原始的数据,对容器应用来说是透明的,感觉不到中间Flannel的存在。

Flannel每次分配的地址段都在同一个公共区域获取,存储在集中的etcd上,从而实现不同Node上的Pod分配的IP不产生冲突。Flannel通过修改Docker的启动参数将分配给它的地址段传递进去。

通过如上方式,Flannel就控制了每个Node上的docker0地址段的地址,从而保障了所有Pod的IP地址在同一个水平网络中且不产生冲突。Flannel完美地实现了对Kubernetes网络的支持,但是它引入了多个网络组件,在网络通信时需要转到flannel0网络接口,再转到用户态的flanneld程序,到对端后还需要走这个过程的反过程,所以也会引入一些网络的时延损耗。另外,Flannel模型默认采用了UDP作为底层传输协议,UDP本身是非可靠协议,虽然两端的TCP实现了可靠传输,但在大流量、高并发的应用场景下还建议多次测试。

Calico

Calco组件简介

Calico是一个基于BGP的纯三层的网络方案,与OpenStack、Kubernetes、AWS、GCE等云平台都能够良好地集成。Calico在每个计算节点都利用Linux Kernel实现了一个高效的vRouter来负责数据转发。每个vRouter都通过BGP1协议把在本节点上运行的容器的路由信息向整个Calico网络广播,并自动设置到达其他节点的路由转发规则。

Calico保证所有容器之间的数据流量都是通过IP路由的方式完成互联互通的。Calico节点组网时可以直接利用数据中心的网络结构(L2或者L3),不需要额外的NAT、隧道或者Overlay Network,没有额外的封包解包,能够节约CPU运算,提高网络效率。

img
img

Calico在小规模集群中可以直接互联,在大规模集群中可以通过额外的BGP route reflector来完成。Calico基于iptables还提供了丰富的网络策略,实现了Kubernetes的Network Policy策略,提供容器间网络可达性限制的功能。

Calico架构
image.png
image.png

Calico的主要组件:

Felix:Calico Agent,运行在每个Node上,负责为容器设置网络资源(IP地址、路由规则、iptables规则等),保证跨主机容器网络互通;

etcd:Calico使用的后端存储;

BGP Client:负责把Felix在各Node上设置的路由信息通过BGP协议广播到Calico网络;

Route Reflector:通过一个或者多个BGP Route Reflector来完成大规模集群的分级路由分发;

CalicoCtl:Calico命令行管理工具;

本文主要参考《Kubernetes权威指南实战》

结束

欢迎大家点点关注,点点赞!

标签:容器,插件,Kubernetes,网络,Pod,CNI
来源: https://www.cnblogs.com/wtzbk/p/15627403.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有