盘点Kubernetes网络问题的4种解决方案
Posted 分布式实验室
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了盘点Kubernetes网络问题的4种解决方案相关的知识,希望对你有一定的参考价值。
由于在企业中部署私有云的场景会更普遍,所以在私有云中运行Kubernetes + Docker集群之前,就需要自己搭建符合Kubernetes要求的网络环境。现在的开源世界里,有很多开源组件可以帮助我们打通Docker容器和容器之间的网络,实现Kubernetes要求的网络模型。当然每种方案都有自己适合的场景,我们要根据自己的实际需要进行选择。
Kubernetes的网络模型假定了所有Pod都在一个可以直接连通的扁平的网络空间中,这在GCE(Google Compute Engine)里面是现成的网络模型,Kubernetes假定这个网络已经存在。而在私有云里搭建Kubernetes集群,就不能假定这个网络已经存在了。我们需要自己实现这个网络假设,将不同节点上的Docker容器之间的互相访问先打通,然后运行Kubernetes。
Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址。而且它还能在这些IP地址之间建立一个覆盖网络(Overlay Network),通过这个覆盖网络,将数据包原封不动地传递到目标容器内。
可以看到,Flannel首先创建了一个名为flannel0的网桥,而且这个网桥的一端连接docker0的网桥,另一端连接一个名为flanneld的服务进程。
Flanneld进程并不简单,它首先上连etcd,利用etcd来管理可分配的IP地址段资源,同时监控etcd中每个Pod的实际地址,并在内存中建立了一个Pod节点路由表;然后下连docker0和物理网络,使用内存中的Pod节点路由表,将docker0发给它的数据包包装起来,利用物理网络的连接将数据包投递到目标flanneld上,从而完成pod到pod之间的直接的地址通信。
Flannel之间的底层通信协议的可选余地有很多,比如UDP、VXlan、AWS VPC等等。只要能通到对端的Flannel就可以了。源Flannel封包,目标Flannel解包,最终docker0看到的就是原始的数据,非常透明,根本感觉不到中间Flannel的存在。
Flannel的安装配置网上讲的很多,在这里就不在赘述了。在这里注意一点,就是flannel使用etcd作为数据库,所以需要预先安装好etcd。
1. 同一Pod内的网络通信。在同一个Pod内的容器共享同一个网络命名空间,共享同一个Linux协议栈。所以对于网络的各类操作,就和它们在同一台机器上一样,它们可以用localhost地址直接访问彼此的端口。其实这和传统的一组普通程序运行的环境是完全一样的,传统的程序不需要针对网络做特别的修改就可以移植了。这样做的结果是简单、安全和高效,也能减少将已经存在的程序从物理机或者虚拟机移植到容器下运行的难度。
2. Pod1到Pod2的网络,分两种情况。Pod1与Pod2不在同一台主机与Pod1与Pod2在同一台主机。
3. Pod到Service的网络。创建一个Service时,相应会创建一个指向这个Service的域名,域名规则为{服务名}.{namespace}.svc.{集群名称}。之前Service IP的转发由iptables和kube-proxy负责,目前基于性能考虑,全部为iptables维护和转发。iptables则由kubelet维护。Service仅支持UDP和TCP协议,所以像ping的ICMP协议是用不了的,所以无法ping通Service IP。
4. Pod到外网。Pod向外网发送请求,查找路由表, 转发数据包到宿主机的网卡,宿主网卡完成路由选择后,iptables执行Masquerade,把源IP更改为宿主网卡的IP,然后向外网服务器发送请求。
由于Pod和Service是Kubernetes集群范围内的虚拟概念,所以集群外的客户端系统无法通过Pod的IP地址或者Service的虚拟IP地址和虚拟端口号访问到它们。为了让外部客户端可以访问这些服务,可以将Pod或Service的端口号映射到宿主机,以使得客户端应用能够通过物理机访问容器应用。
总结:Flannel实现了对Kubernetes网络的支持,但是它引入了多个网络组件,在网络通信时需要转到flannel0网络接口,再转到用户态的flanneld程序,到对端后还需要走这个过程的反过程,所以也会引入一些网络的时延损耗。另外Flannel默认的底层通信协议是UDP。UDP本身是非可靠协议,虽然两端的TCP实现了可靠传输,但在大流量、高并发应用场景下还需要反复调试,确保不会出现传输质量的问题。特别是对网络依赖重的应用,需要评估对业务的影响。
二、基于Docker Libnetwork的网络定制
容器跨主机的网络通信,主要实现思路有两种:二层VLAN网络和Overlay网络。
Libnetwork是Docker团队将Docker的网络功能从Docker核心代码中分离出去,形成一个单独的库。 Libnetwork通过插件的形式为Docker提供网络功能。 使得用户可以根据自己的需求实现自己的Driver来提供不同的网络功能。
Libnetwork所要实现的网络模型基本是这样的: 用户可以创建一个或多个网络(一个网络就是一个网桥或者一个VLAN ),一个容器可以加入一个或多个网络。 同一个网络中容器可以通信,不同网络中的容器隔离。这才是将网络从docker分离出去的真正含义,即在创建容器之前,我们可以先创建网络(即创建容器与创建网络是分开的),然后决定让容器加入哪个网络。
bridge:Docker默认的容器网络驱动,Container通过一对veth pair链接到docker0网桥上,由Docker为容器动态分配IP及配置路由、防火墙等。
host:容器与主机共享同一Network Namespace。
null:容器内网络配置为空,需要用户手动为容器配置网络接口及路由。
remote:Docker网络插件的实现,Remote driver使得Libnetwork可以通过HTTP Resful API 对接第三方的网络方案,类似于SocketPlane的SDN方案只要实现了约定的HTTP URL处理函数以及底层的网络接口配置方法,就可以替代Docker原生的网络实现。
overlay:Docker原生的跨主机多子网网络方案。
Docker自身的网络功能比较简单,不能满足很多复杂的应用场景。因此,有很多开源项目用来改善Docker的网络功能,如Pipework、Weave、SocketPlane等。
Pipework是一个简单易用的Docker容器网络配置工具。由200多行shell脚本实现。通过使用IP、brctl、ovs-vsctl等命令来为Docker容器配置自定义的网桥、网卡、路由等。有如下功能:
Pipework简化了在复杂场景下对容器连接的操作命令,为我们配置复杂的网络拓扑提供了一个强有力的工具。对于一个基本应用而言,Docker的网络模型已经很不错了。然而,随着云计算和微服务的兴起,我们不能永远停留在使用基本应用的级别上,我们需要性能更好且更灵活的网络功能。Pipework是个很好的网络配置工具,但Pipework并不是一套解决方案,我们可以利用它提供的强大功能,根据自己的需求添加额外的功能,帮助我们构建自己的解决方案。
OVS的优势是,作为开源虚拟交换机软件,它相对成熟和稳定,而且支持各类网络隧道协议,经过了OpenStack等项目的考验。这个网上很多,就不再赘述了。
Calico是一个纯3层的数据中心网络方案,而且无缝集成像OpenStack这种IaaS云架构,能够提供可控的VM、容器、裸机之间的IP通信。
通过将整个互联网的可扩展IP网络原则压缩到数据中心级别,Calico在每一个计算节点利用Linux Kernel实现了一个高效的vRouter来负责数据转发,而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息像整个Calico网络内传播——小规模部署可以直接互联,大规模下可通过指定的BGP route reflector来完成。这样保证最终所有的workload之间的数据流量都是通过IP路由的方式完成互联的。
Calico节点组网可以直接利用数据中心的网络结构(无论是L2或者L3),不需要额外的NAT,隧道或者Overlay Network。
Calico基于iptables还提供了丰富而灵活的网络Policy,保证通过各个节点上的ACLs来提供Workload的多租户隔离、安全组以及其他可达性限制等功能。
Calico有两种布署方案,一般集群都配有SSL证书和非证书的情况。
总结:目前Kubernetes网络最快的第一就是Calico,第二种稍慢Flannel,根据自己的网络环境条件来定。 Calico作为一款针对企业级数据中心的虚拟网络工具,借助BGP、路由表和iptables,实现了一个无需解包封包的三层网络,并且有调试简单的特点。虽然目前还有些小缺陷,比如stable版本还无法支持私有网络,但希望在后面的版本中会更加强大。
Docker 1.9开始支持Contiv Netplugin,Contiv带来的方便是用户可以根据实例IP直接进行访问。
Docker 1.10版本支持指定IP启动容器,并且由于部分数据库应用对实例IP固定有需求,有必要研究容器IP固定方案的设计。
在默认的Kubernetes + Contiv的网络环境下,容器Pod的IP网络连接是由Contiv Network Plugin来完成的,Contiv Master只实现了简单的IP地址分配和回收,每次部署应用时,并不能保证Pod IP不变。所以可以考虑引入新的Pod层面的IPAM(IP地址管理插件),以保证同一个应用多次发生部署时,Pod IP始终是不变的。
作为Pod层面的IPAM,可以把这一功能直接集成在Kubernetes里。Pod作为Kubernetes的最小调度单元,原有的Kubernetes Pod Registry(主要负责处理所有与Pod以及Pod subresource相关的请求:Pod的增删改查,Pod的绑定及状态更新,exec/attach/log等操作)并不支持在创建Pod时为Pod分配IP,Pod IP是通过获取Pod Infra Container的IP来获取的,而Pod Infra Container的IP即为Contiv动态分配得来的。
在原有Kubernetes代码基础上,修改Pod结构(在PodSpec中加入PodIP)并重写了Pod Registry同时引入了两个新的资源对象:
这里对kubelet也需要进行改造,主要包括根据Pod Spec中指定IP进行相关的容器创建(docker run加入IP指定)以及Pod删除时释放IP操作。
另外为了防止IP固定方案中可能出现的问题,在Kubernetes中加入了额外的REST API:包括对已分配IP的查询,手动分配/释放IP。
容器IP固定方案已测试评估中,运行基本上没问题,但稳定性有待提升。主要表现在有时不能在预期时间内停止旧Pod,从而无法释放IP造成无法复用(初步原因是由于Docker偶尔的卡顿造成无法在规定时间内停止容器),可以手动去修复。但从长期考虑,IP固定方案还需要加强稳定性并根据具体需求进行优化。
总结:目前已有多种支持Kubernetes的网络方案,比如Flannel、Calico、华为的Canal、Weave Net等。因为它们都实现了CNI规范,用户无论选择哪种方案,得到的网络模型都一样,即每个Pod都有独立的 IP,可以直接通信。区别在于不同方案的底层实现不同,有的采用基于VXLAN的Overlay实现,有的则是Underlay,性能上有区别,再有就是是否支持Network Policy了。
本次培训内容包括:Docker基础、容器技术、Docker镜像、数据共享与持久化、Docker三驾马车、Docker实践、Kubernetes基础、Pod基础与进阶、常用对象操作、服务发现、Helm、Kubernetes核心组件原理分析、Kubernetes服务质量保证、调度详解与应用场景、网络、基于Kubernetes的CI/CD、基于Kubernetes的配置管理等, 。
以上是关于盘点Kubernetes网络问题的4种解决方案的主要内容,如果未能解决你的问题,请参考以下文章
#yyds干货盘点# Kubernetes 搞定网络原来可以如此简单?(25)
白话Kubernetes网络
网络攻防:盘点黑客最常用隐藏踪迹的六种方式
Kubernetes — Flannel
#yyds干货盘点#最小化K8s环境部署之Minikube
Kubernetes与HPC:(1)RDMA网络