所属技术领域:
云原生
|名词定义|
我们知道的是,在K8S上的网络通信包含以下几类:
• 容器间的通信:同一个Pod内的多个容器间的通信,它们之间通过lo网卡进行通信。
• Pod之间的通信:通过Pod IP地址进行通信。
• Pod和Service之间的通信:Pod IP地址和Service IP进行通信,两者并不属于同一网络,实现方式是通过IPVS或iptables规则转发。
• Service和集群外部客户端的通信,实现方式:Ingress、NodePort、Loadbalance
K8S网络的实现不是集群内部自己实现,而是依赖于第三方网络插件----CNI(Container Network Interface)
flannel、calico、canel等是目前比较流行的第三方网络插件。
这三种的网络插件需要实现Pod网络方案的方式通常有以下几种:
虚拟网桥、多路复用(MacVLAN)、硬件交换(SR-IOV)
无论是上面的哪种方式在容器当中实现,都需要大量的操作步骤,而K8S支持CNI插件进行编排网络,以实现Pod和集群网络管理功能的自动化。每次Pod被初始化或删除,kubelet都会调用默认的CNI插件去创建一个虚拟设备接口附加到相关的底层网络,为Pod去配置IP地址、路由信息并映射到Pod对象的网络名称空间。
在配置Pod网络时,kubelet会在默认的/etc/cni/net.d/目录中去查找CNI JSON配置文件,然后通过type属性到/opt/cni/bin中查找相关的插件二进制文件,如下面的"portmap"。然后CNI插件调用IPAM插件(IP地址管理插件)来配置每个接口的IP地址:
CNI主要是定义容器网络模型规范,链接容器管理系统和网络插件,两者主要通过上面的JSON格式文件进行通信,实现容器的网络功能。CNI的主要核心是:在创建容器时,先创建好网络名称空间(netns),然后调用CNI插件为这个netns配置网络,最后在启动容器内的进程。
常见的CNI网络插件包含以下几种:
• Flannel:为Kubernetes提供叠加网络的网络插件,基于TUN/TAP隧道技术,使用UDP封装IP报文进行创建叠 加网络,借助etcd维护网络的分配情况,缺点:无法支持网络策略访问控制。
• Calico:基于BGP的三层网络插件,也支持网络策略进而实现网络的访问控制;它在每台主机上都运行一个虚拟路由,利用Linux内核转发网络数据包,并借助iptables实现防火墙功能。实际上Calico最后的实现就是将每台主机都变成了一台路由器,将各个网络进行连接起来,实现跨主机通信的功能。
• Canal:由Flannel和Calico联合发布的一个统一网络插件,提供CNI网络插件,并支持网络策略实现。
• 其他的还包括Weave Net、Contiv、OpenContrail、Romana、NSX-T、kube-router等等。而Flannel和Calico是目前最流行的选择方案。
|发展历程|
|相关词|
Docker网络模型
了解Docker的友友们都应该清楚,Docker容器的原生网络模型主要有3种:Bridge(桥接)、Host(主机)、none。
Bridge:借助虚拟网桥设备为容器建立网络连接。
Host:设置容器直接共享当前节点主机的网络名称空间。
none:多个容器共享同一个网络名称空间。
从上可以看到容器内有一个网卡eth0@if39,实际上eth0@if39和veth3f1b114是一对veth pair。veth pair是一种成对出现的特殊网络设备,可以想象它们由一根虚拟的网线进行连接的一对网卡,eth0@if39在容器中,veth3f1b114挂在网桥docker0上,最终的效果就是eth0@if39也挂在了docker0上。
桥接式网络是目前较为流行和默认的解决方案。但是这种方案的弊端是无法跨主机通信的,仅能在宿主机本地进行,而解决该问题的方法就是NAT。所有接入到该桥接设备上的容器都会被NAT隐藏,它们发往Docker主机外部的所有流量都会经过源地址转换后发出,并且默认是无法直接接受节点之外的其他主机发来的请求。当需要接入Docker主机外部流量,就需要进行目标地址转换甚至端口转换将其暴露在外部网络当中。如下图:
容器内的属于私有地址,需要在左侧的主机上的eth0上进行源地址转换,而右侧的地址需要被访问,就需要将eth0的地址进行NAT转换。SNAT---->DNAT
这样的通信方式会比较麻烦,从而需要借助第三方的网络插件实现这样的跨主机通信的网络策略。
Flannel网络插件
在各节点上的Docker主机在docker0上默认使用同一个子网,不同节点的容器都有可能会获取到相同的地址,那么在跨节点通信时就会出现地址冲突的问题。并且在多个节点上的docker0使用不同的子网,也会因为没有准确的路由信息导致无法准确送达报文。
而为了解决这一问题,Flannel的解决办法是,预留一个使用网络,如10.244.0.0/16,然后自动为每个节点的Docker容器引擎分配一个子网,如10.244.1.0/24和10.244.2.0/24,并将分配信息保存在etcd持久存储。
第二个问题的解决,Flannel是采用不同类型的后端网络模型进行处理。其后端的类型有以下几种:
VxLAN:使用内核中的VxLAN模块进行封装报文。也是flannel推荐的方式,其报文格式如下:
host-gw:即Host GateWay,通过在节点上创建目标容器地址的路由直接完成报文转发,要求各节点必须在同一个2层网络,对报文转发性能要求较高的场景使用。
UDP:使用普通的UDP报文封装完成隧道转发。
Pod 内部 docker 容器之间网络通信
Kubernetes 使用了一种 “IP-per-pod” 网络模型:为每一个 Pod 分配了一个IP地址,Pod 内部的 docker 容器共享Pod的网络空间,即它们共享 Pod 的网卡和 IP。其原理是根据 docker 的“container 网络”模型而来。
Pod 所在的网络之间通信
Kubernetes 把各 node 主机上的 docker的 bridge 网络“外包”给了 flannel,然后通过 etcd 将各 node 主机上的 bridge 网络信息收集起来,因此每个 node 之间的网络使用的是同网络的不同 IP,保证了网络通讯的可靠性。其原理是根据 docker 的“bridge 网络”模型而来。
Pod 和 Service 之间网络通信
在 Kubernetes 体系中Pod是不稳定的,Pod 的 IP 地址会发生变化,所以 Kubernetes 引进了 Service 的概念。Service 是一个抽象的实体,Kubernetes 在创建 Service 实体时,为其分配了一个虚拟的 IP,当外界需要访问 Pod 里的容器提供的功能时,不直接使用 Pod 的 IP 地址和端口,而是访问 Service 的这个虚拟 IP 和端口,由 Service 把请求转发给它背后的 Pod。
Kubernetes 在创建 Service 时,根据 Service 的标签选择器(Label Selector)来查找 Pod,据此创建与 Service 同名的 EndPoints 对象。当Pod的地址发生变化时,EndPoints 也随之变化。Service 接受到请求时,就能通过 EndPoints 找到对应的 Pod。再深入探究,Service 只是一个虚拟的概念,真正完成请求转发的是运行在 node 节点上的 kube-proxy。Service的虚拟IP就是由kube-proxy实现的。
kube-proxy 有两种请求转发模式:userspace 模式和 iptables 模式。在 Kubernetes v1.1版本之前默认是userspace 模式,v1.2 版本后默认是 iptables 模式。
资料来源:
- 名词定义:https://www.cnblogs.com/tylerzhou/p/10995797.html
- 相关词:https://www.cnblogs.com/tylerzhou/p/10995797.html
延伸阅读:
简书:Kubernetes 网络模型解析https://www.jianshu.com/p/478c56287c5c