广告

干货PPT | Kubernetes网络更进一步

  • 浏览(834)
  • 评论(0)
  • 译者:k8s

干货视频:https://v.qq.com/x/page/n05077v5xw1.html

2017年11月4日,CNCF Meetup——K8S GeekGathering 深圳站圆满落幕,本次活动由K8S技术社区、腾讯云、EasyStack、灵雀云联合主办,特邀vivo共同参与,由IT大咖说、开源云中文社区提供技术支持与推广。当前日趋火热的Kubernetes技术主题以及干货十足的实践分享吸引深圳地区近150+容器技术关注者到场参与!

灵雀云架构师刘梦馨

灵雀云架构师刘梦馨分享了技术主题 :Kubernetes网络更进一步 以下是他的演讲内容整理:


(获取深圳站全套PPT打包,文末添加K8S技术社区小助手!)

首先自我介绍一下,我叫刘梦馨,是2014年在北大研究生毕业,去阿里待了一年,2015年加入灵雀云,一开始做镜像仓库, Mesos服务生命周期管理等,之后做了一段K8S的服务生命周期的管理,然后做网络这块。包括K8S的网络和负载均衡器这块,最近做一些平台稳定性等相关的内容。


今天的议题主要是分几方面:一是K8S的网络模型,之前嘉宾介绍过K8S的网络,这块介绍简单一点,就是K8S基本的网络模型。二是我们认为的缺陷,并不主要是缺陷,主要是我们认为它的理念和我们的需求有些不一致的地方,我会介绍一下在我们看来它的网络模型上的缺陷。三是如果要改进这个缺陷,肯定会用K8S的网络接口CNI,我会介绍CNI,这个大家可能听得比较少,因为这个项目做的人相对少一些。四是CNI的一些实践。

第一部分,K8S的网络模型,K8S的网络模型,如果我们从底层网络来看分为三个层面,一个Pod之间的多个容器的网络互通,我们知道K8S的POD可以由多个容器组成,这个层面网络互通是比较简单的,因为所有的容器都是共享的,他们之间共享一个网卡,可以直接通信,这个没有问题。第二个问题,一台虚拟机上多个容器之间他们的网络是如何通信的,这块其实也是比较简单,Docker已经解决了,会搭一个网桥,让上面所有的容器网卡接到网桥上,他们之间的网络就可以互通过。Docker是Docker0的网桥,其他主流的像calico、flannel,他们的模式是类似的,现在主流的是通过这种方式实现的。第三种是比较难的,Docker一开始没有做好,大家有很多工作在这块做,是跨主机的Pod之间的网络通信。对于K8S来说,这个网卡如何分配其实K8S是没有定义的,相当于这块是没有实现的。然后不同Pod跨主机网络之间如何通信、如何打通网络,它也是不管,也是交给第三方实现的,这块也是有很多工作可以做的。

    

现在我们再想一个问题,传统运维或者之前的虚拟机时代的运维可能关心一个事情,你的服务IP是什么?有些公司运维可能会对IP有些强的管控。容器时代,Pod需不需要有固定的IP,是不是希望Pod固定之后,IP还是一样的,其实K8S没有规定,而且大部分主流的实现是容器IP是可以变的。这个做法到底合不合理我们需要考虑一下?既然你的IP是变的,就会带来很直接的问题,我想访问这个服务怎么访问?之前两位同事讲过很多,我不做很细的介绍。你的底层Pod IP不断变,但是我会给你提供固定的域名或者DNS的方式或者NodePort固定的主机IP加端口,用Service的方式,不管Pod方式如何变,总会给你固定的方式,通过固定的方式可以访问到一直变化的IP。它的的实现是通过Kube-proxy、iptables、Kube-dns实现的。大家不要太迷信K8S这套东西,因为我们实际测的时候一开始发现K8S服务发现的功能比较少,我们用得越来越多,量越来越大,会发现它的性能有很多问题。再往后不光是性能问题,还有它的稳定性也有很严重的问题,而且它的稳定性缺陷是它从设计很难避免,我们最近考虑如何改进这块。这次的演讲不太涉及Service这块的东西,主要是Pod  IP这块。

Pod IP网络模型的问题,其实也是刚才说的,你的IP是变的,然后这个事情到底是不是合理的?两年前的时候,我们公司没有太多人,所以我们研发需要去见客户,我们向客户推销Docker,他们很多运维团队都会质疑我们一件事,说你的容器IP是一直变的,怎么管?我们可能要和他们进行技术布道,说容器就是这样的,容器生命周期很短,不断创建、不断消失,IP肯定不断变。容器的好处是,你可以在这台机器上挂,在另外一台机器也可以,IP这样不好飘,这都还是技术层面的难度,这个事情不好做。如果对方再不同意,我们可能会洗脑,你的理念是不对的,容器这个时代已经不需要关注你的IP了,固定IP可能限制你的思维,现在都是云计算、大数据、快速迭代等等,不应该再关心这件事。如果洗脑不成我们就采取攻击性的方法,就说Kubernetes给你提供这么好的服务发展方案,为什么你还抱着就的一套不放?你固定的就是保守的,就是不思进取的。再往后是能打架的就不讲道理。很多情况就是这样子,很多用户不接受你的IP飘来飘去。我们做乙方,用户是谁给钱是谁爸爸,固定IP的理由是什么?

主要运维方面是这样,首先对于运维来说,网络方面是很重要的资源,不是服务可以来回飘的东西,IP很重要,它要对IP进行强管控,IP来回飘,会让他的安全感下降很多。第二他们有很多基于IP的东西,有流量和突发的监控,如果你服务的IP一直变化,通过这个IP它很难定位到这个服务,相当于IP的监控就没有意义,因为根本不知道IP流量上去了是哪个服务的,很难找到负责人。第三个是对于IP安全策略没有办法做,如果以前IP是固定的,iptables或者网络底层防火墙,这样的东西都是很好做的,可以很好的进行服务之间的安全访问限制。如果其他IP都是变的,这个事情就变得没有办法做了。再往后是定位分析和数据处理。我们见到的客户把网络所有的流量镜像一份,就说你正常在跑,把镜像的流量再复制一份,每天对流量进行分析,看你有没有违规操作或者有什么恶意攻击,或者哪些行为不正常,这样他们通过IP再定位服务,如果IP是变的,相当于把他们很多能做的事情去掉了。还有一些特殊的,我们会碰到一些很奇怪的软件,他们的license是根据网卡来的,就是说他的License是根据网卡的IP加上Mac计算出来的,大家有见过这种软件吗?这种情况下相当于IP、Mac变,license失效,软件跑不起来。还有你的IP不断变化,实际中也有问题,有很多服务和软件就是基于IP部署的,基于IP相互发现的,不是不管就可以,最典型的是Etcd这样的,大家如果配就知道没有很麻烦,后面和IP认可就可以,如果你是用K8S或者其他的容器,IP是变的,这个东西怎么填都是很难的事情。


K8S有它的解决方案,statefulset 和headless service可以做这个事情,但是这个事情在我看来有两个问题,它引入两个不好理解的概念,如果大家对K8S比较关心,第一次看,我觉得你看好半天才能明白它干什么,它为什么这么设计。它的核心理想是的你的Pod IP是变的,然后给Pod一个顺序,给每个Pod一个标志符,Etcd1、2、3,给他们三个人每个人分配一个域名,你在里面不用填IP,填对应的三个域名就可以。这个很难配,做这个ppt前我找了一下,大概要140多行statefulset 的yaml,还要一个 headless service yaml合在一起才能部署一个东西。其实到最后是基于域名做的,域名肯定是有问题的,因为域名有cache缓存的问题,底层Pod IP失效,域名的缓存没有失效就会造成不一致,我觉得它的statefulset做这件事情也是有问题的,并不能完美的解决这个问题。 

      

刚才说了非固定IP的影响,做容器之前大家可能没有想这个事,可能从一开始就是不固定的,我们想一下固定的IP是什么影响。先看一下 K8S自己的服务发现其实好像还可以用,并且可能变得更简单。比如Cluster IP或者DNS他们的影射可能变得简单,这件事情变得更好做。如果容器的IP固定,其实也是可以做的,因为对他来说没有影响,还是一样的,对他们的接受程度也会更高一点。我们很多服务发现的方式,可能之前通过K8S的Sevrice来进行服务发现,既然IP固定,我们可以跳过,直接用IP服务发现就可以,没有必要让你的运维理解很复杂,大家会问什么是Cluster IP,什么是Nodeport,这些还是有理解成本,如果提供和原来一样的方式也是不错的。


可能想到一个问题,既然固定IP还是有好处的,并不是完全没有用的,为什么不管是Docker还是K8S都没有做这个事情呢?我觉得一开始Docker没有想好这个事情怎么做,如果大家一开始跟Docker,Docker就是一个单机的工具,没有想做得很复杂,最早Docker的网络和存储都是很弱的,如果大家了解的话,它根本没有往这方面想。其次在我理解就是理念之争,到底服务应该做成有状态的还是无状态的,有Docker之后大家认为容器应该是跑有状态的东西,而不是无状态的东西,但是网络这块是有状态的。我们之前说有状态想到的是存储,认为存储才是有状态的服务,其实网络也是状态的一部分。大家可以想一下,如果Pod里面的服务访问外面,给外部留下的信息是某个IP访问我,所以对外的状态对你来说,IP其实也是你的一个状态,唯一的网络标识,所以说网络其实也是状态的一部分,如果要做有状态这个事情就变得很难。Docker这个网络和K8S的网络,我认为还不是很好用的状态,能用,但是没有那么好的程度,所以有状态是很难的事。但是能不能做呢?可以做,我们做了一些尝试,做的方式是我们自定义CNI插件。


    

CNI,这个概念大家平时听的少一点。它的全称是Container network interface,它注重给你的东西提供一套标准的容器网络的接口。现在包括K8S,mesos,rancher等都是通过CNI这种方式实现的,说实话,其他的实现对我们根本没有影响,我们只关心K8S。这是项目的网络截图,是它的一个截图,如果你对比其他项目,CNI应该是里面最简单的。如果你有对这个项目有兴趣,从这里开始是比较好的,但是可能几百行或者上千行的代码都到头了。一个是CNI的标准,包括API接口标准和库函数,怎么快速实现CNI,还有CNI提供的网络插件。


    

接下来讲一下Kubernetes和CNI之间是如何交互的,给大家讲完之后,大家可以比较容易上手,自己实现自己的网络。这是Kubernetes的基本参数,大家可以看到。红色的标起来的是两个选项,CNI在我看来是有点奇怪的实现,一般的时候一个程序和另一个程序交互,大概是HTTPrestful或者是RPC或者TCP的通信,大概是通过这种方式来的,但是CNI和Kubernetes的交互方式是通过二进制文件的方式,它会调用二进制文件传一个参数,二进制文件做这样的事情。第二章是CNI实现的组件,他们都是以二进制的形式放在目录下面。左下角是CNI的配置,是最简单的,参数很少,还有一些其他比较复杂的。其实比较重要的是type,然后ipam,它是如何分配IP的,它是通过DHCP方式分配IP。


大概讲一下它交互的流程,它的交互流程是通过创建Pod和销毁Pod两个事件来触发的,创建Pod的时候,它会去调CNI,它可能根据这个文建会先调用macvlan,macvlan通过macvlan的方式创建一个网卡,然后再次调二进制文件,都是调里面

的Dhcp和macvlan二进制文件,创建网卡,构建IP,把这个网卡放到Pod network namespace,相当于完成Pod网卡的创建。还有Pod删除的时候,可能调用二进制文件释放掉,然后删除网卡,完成网卡的销毁。大概的交互比较简单,就这两个,实现的时候也是通过这两个就可以。

   

最下面是main函数,其实有一个库,可以方便实现,照着这个写就可以,需要实现的是下面的函数就可以。函数其他的都不太用着重关注,都是做错误处理。最主要关注上面的,它是在Network namespace里面创建的一块link,删除的时候再把这个 link删除,这是最简单的设备创建。如果大家对网络比较熟,或者对自己的网络有特殊的要求或者定制化的需求,其实在里面讲讲自己的逻辑就可以,整体来说它的逻辑还是比较简单的。而且还有一个功能是多个命令是可以串联的,比如我刚才举的例子,macvlan和DHCP是串联的,macvlan先调网卡,然后再调DHCP分配IP,他们之间有一个result的返回,通过result进行数据结构的传输。我们看一下result就可以知道网络还可以做什么别的事情。

    

这是官方定义的API标准,其实我们也是可以在里面扩充的。上面是interfaces,Kubernetes这个网络做得实在太简单,包括容器中的很多东西都是太简单了,可能一个pod里面有一个网卡设一个IP就完了,其实一个pod里面有多个网卡,虚拟经常会有这样的需求,有多个网卡的需求,一个数据流,一个控制流,这种是可以做的。在它的interfaces里面可以看到有内置的网卡和mac地址,因为我们碰到有些客户,你的mac是可信域才可以通过安全策略,这需要你要自定义的mac。再往下,IP,一块网卡是可以有多个ip,而不是仅仅是常用一个容器的一个ip。再往下可以定义这个容器的路由表,包括路由的顺序等等都是可以定义的。再往下是DNS、server,容器里面的DNS都可以自定义,容器通信网络这块有很多可以做的事情,如果大家想做这方面,我觉得机会还是很大的。现在的网络说实在的,尽管实现很多,但是都还是蛮弱的。

    

已有的插件,第三方实现的比较知名的有flannel、calico、weave这样一些。下面两项其实是它官方已经实现的,看起来分两大类:一是网卡生成的方式,比如bridge、ipvlan、macvlan、loopback、ptp、vlan。第二大块是IPAM,我不知道大家是否理解IPAM,IPAM的意思是IP该怎么分配。官方实现的有两种,一种是dhcp,一种是host-local。回到之前说的我们要做固定IP,大家可以很容易联想IPAM这块做一些东西,因为这个IPAM是针对IP的,如果要做的话先看一下现有的两种有没有问题或者现有的两种怎么实现,dhcp大家比较熟悉,就是自动分配ip,它的问题是没有办法精细的管控IP,因为这些和系统脱离,相当于网络的机器或者设备的进行IP分配,这样就需要通过主机发再发dhcp的广播再获得ip,相当于容器ip和出口机的IP混在一起,很难精确分配到某个pod是某个IP,因为你不知道这些信息。DHCP实际生产环境用得很少,因为IP管控要求很严格,不可能自己随机分IP,只有我们家里的wifi或者办公才会用到,生产环境很少会提供 DHCP 服务。

   

host-local,每台机器上有这个文件,这个文件上规定每台机器能生成一些IP,可以看一下配置文件的格式,其实这两个参数比较重要,一个是rangeEnd和ReangeStart,就是每台机器分配的范围是多少。这种分配方式有一个很严重的问题,flannel和calico都用,但是每台机器都是固定的,这给每台机器划分了一个网关,相当于之前你的容器是10.1的网关,到每台机器上10.1.1.0、10.1.2.0。相当于每台机器上容器可用的IP是固定的,如果你想实现Pod固定IP,相当于你Pod是在机器上的,因为IP是很不灵活,很难实现IP的迁移。而且分配IP比较困难,新增机器要重新定义,这台机器用多少IP,要考虑IP段释放下来,很不灵活,而且也没有办法实现固定IP的事情。


为什么这个事情感觉这么难?我觉得也是K8S设计理念的问题,我们可以看到K8S管了很多东西,管了Pod、configmap、Service、volume等,你会发现它没有管你的IP。理论上来说,IP对你的服务或者对你的集群来说是很重要的资源,但是K8S里面IP不是它的一等公民,甚至你根本找不到一个跟容器 IP相关的资源,所以使得你的IPAM变得很难。你要么通过K8S完全无关的东西来实现,要么通过锁死的方式实现,这其实都是因为你没有把IP资源看得特别重,你只是当做可以随机分配的,所以他设置的理念就是你的IP我不关心,该是什么就是什么,所以导致这样的结果。


最后讲一下我们做的,我们做的事情很简单,就是把IP提出来,把IP当做很重要的资源,进行单独的管理。我们会专门实现IPAM的组件,这个组件的功能并不复杂,一个是网段的添加、删除,可以在K8S管理网段,给某个业务或者某几个用户分配一个网段,然后对IP进行网关设置,路由设置,和DNS设置,我们之后也会做mac的设置,我们现在碰到需求现在还没有做这样的事情。有了网段之后,有IP的添加删除,IP就变成了很重要的资源,该用哪些IP,哪些IP是可以用的,都是可以用管理员指定的,而不是像K8S随机画一个网段,还有权限、配额,如果IP提成一等公民,我们可以在IP上做权限的管理。之后创建服务,流程就变成另一个样子,我们现在做的是在外面包一层,创建K8S的deployment的时候需要申明用哪几个IP,如果IP信息传输到IPAM的组件,这个IPAM就是一个数据库,这个数据库就会显示哪些IP可以使用,哪些应该被哪个服务使用,把这个记录下来。


在K8S启动Pod,CNI里面再实现一套逻辑,把IPAMI的逻辑实现了,那套做的东西会进入IPAM的数据库里面找,如果用就占用这个,别人不能再用,就可以实现每个POD有自己的IP,这个IP是你之前想要的。如果在删除的时候,CNI会把IP释放掉,说明这个IP不会再被这个服务使用,别的服务可以使用这个IP。我们如果想创建ETCD的服务,就不用再写一个东西,你只要做你想要的IP就可以,很大的简化你的工作量,而且实现我之前说的传统的运维,IP的监控、管理的东西。

  

实现这套东西碰到的坑,刚才说了CNI的触发机制,POD创建和删除会触发,可以理解为CNI触发是事件驱动。我们碰到的CNI丢,或者CNI执行失败,或者kubelet挂了,机器挂了,很多情况会导致CNI的操作是没有成功执行的,带来的问题是你的IP泄露,相当于你的删除没有执行,IP被占用,会有IP泄露的问题,CNI方式决定有这个问题。我们之前出现IP泄露的问题,一开始以为是我们代码问题,后来发现这种架构有问题。我们之后在很多地方都发现这种问题,flannel 和 calico都会有IP泄露,但是好的一点是对于它来说,IP不是很高级的资源,是一个网段,除非整个网段的 IP 都被占用了,不然你根本不能发现这个问题,等你真正发现有问题的时候,整个一段的IP都泄露了,都用不了,如果机器不稳定就会出现这种情况,我们之前发现过这种情况。


还有一种情况是相对少见一点,理论上会出现的,还是刚才的问题,这个问题对于我们很明显,因为IP对我们是唯一的资源,除非没有释放,被占用,这个IP别人用不了,所以比较容易出现。还有一个IP冲突的问题,这种情况出现几率比较低,但是我们碰到过,你的一台nod节点和你的APIserver通信出现问题,两者失去通信,我们会把IP回收掉,分配到另一个 pod。如果网络恢复把这些节点再加进来,这时候我们会有两个IP是重的现象,这个比较少,所以我们的操作是手动的把其中一个pod强制删除掉来解决的。我想说如果你想实现自己的网络机制,要不断的检测你的网络实际的占用和应该占用的是否一致,需要对IP进行回收。

   

未来我们做的事情,刚才提了一点,我们会有固定mac的需求,有写客户不光IP固定,mac也是要固定的。刚才给大家看了cni可以做很多事情,现在做得比较少,。还有要做的事情是和现有的系统做解耦。我们现在做的方式是比较重的方式,K8S的平台上面再加一层,这层会分析K8S,相当于我们自己的API结构,把IP信息抽取出来,和IPAM做相关的设置,这么做的问题是K8S没有IP的资源,所以我们要这么做,但是有了CRD的概念,我们可能会把IP相关的概念集成到K8S里面,不会在外面再做一层东西,整体和K8S的兼容性看起来的感觉会好一些。我们可能打算支持更多的网络模式,现在只是实现了IPAM,像外面的都是自己实现的IPAM,而且他们的方式,如果是用我们固定IP的方式,可能还要和网络通信之间,路由表,还有转发表要进行更多的设置,macvlan和hvlan和用户实际的物理网打通,他们对IP很关心,所以我们做了这套东西。如果有这套东西,就可以推到其他的网络方式,我们可以做进一步的工作的。

    

今天我就讲这些内容。谢谢大家!

K8S技术社区粉丝:固定IP的方式,我想一下这种场景,Deploment现在有4个Deployment,想缩容到5个,缩容之后再扩容,扩容到10个,现在10个IP和之前的10个IP是不是一样的?

刘梦馨:这个问题问得很好,我们做的事情比较绕,我们做的方式是在更上层的API做的事情,会在IPlan做扩容的操作里面,会自动分一栏。我们实现两种模式,一种是随机分配,一种是固定分配。ETCD这种固定分配,可能对扩容的需求不是那么大,可能是更新或者这样的,要扩容还是无状态,分固定分配和随机分配,随机分配会再多申请一个。

K8S技术社区粉丝Deploment更新的时候,它是不是先创建一两个,然后再删除购得,它会有一个时间段Pod数量会多于期望的副本值,这时候你有12个IP,12个IP会存在IP预留的问题是这样吗?

刘梦馨:我们更多的是先减一个再加一个。

K8S技术社区粉丝你们改了流程?

刘梦馨:对,如果这种对IP强需求都是先减再加,这和传统运维一样,机器固定的,肯定先从一个上面拿掉服务,然后再上去。


添加K8S技术社区小助手,进群获取

深圳站全套PPT打包资料!


  • 分享到:
  • icon
  • icon
  • icon
  • icon
箭头