这一篇我们来讲网易为支撑大规模公有云对于Kubernetes的定制化。

一、总体架构

网易的Kubernetes集群是基于网易云IaaS平台OpenStack上面进行部署的,在外面封装了一个容器平台的管理层,负责统一的账号,计费等。

Kubernetes集群当然是要高可用的,因而会有多个Master节点。

其中APIServer前端有负载均衡器haproxy,需要有一个VIP,在两台haproxy之间进行漂移,保证一台啊挂了,另外一台能够使用同一个VIP接上。

这种漂移使用的协议为VRRP。

Scheduler和Controller也是有多份的,但是只能有一个Leader,需要通过etcd进行选举。

另外网易自身实现的部分放在单独的进程里NeteaseController,用于处理和IaaS层联动的功能。

二、一个还是多个Kubernetes集群?

一般有IaaS平台的公有云或者私有云部署Kubernetes采用的是左面的样子。也即通过调用IaaS层的API,自动化部署多个Kubernetes平台,每一个Kubernetes平台仅仅属于一个租户。

这样的好处是不同的租户的Kubernetes之间是完全隔离的。

坏处也很多:

  • 当租户非常多的时候,Kubernetes集群非常多,非常难以维护

  • 每个Kubernetes集群的规模非常小,完全不能发挥容器平台的优势,容器平台相对于IaaS平台比较轻量级,按最佳实践是能够管理比IaaS更大的集群的,例如几万或者几十万个节点,然而这种方式会将Kubernetes集群限制在很小的规模。

  • 虽然很多云平台提供Kubernetes集群的自动化部署工具,但是仅仅自动化的是安装过程,一旦这个集群交给客户了,云平台就不管了,这样Kubernetes的升级,修复,运维全部要客户自己来,大大提升了运维成本。

  • Kubernetes集群规模需要提前规划阶段数目,添加新的节点数目需要手动进行。

网易采用的是右面的方式,整个IaaS层上面只有一个Kubernetes平台,Kubernetes平台的运维,升级,修复全部由云平台运维人员进行,运维成本较低,而且不需要用户自己操心。

对于用户来讲,看到的就只是容器,不用关心容器平台。当用户创建容器的时候,当Kubernetes集群资源不足的时候,Netease Controller会自动调用IaaS层API创建虚拟机,然后在虚拟机上部署容器,一切自动进行。

当然这种方式的一个缺点是一个Kubernetes的不同租户之间的隔离问题。

采取的方式是不同的租户不共享虚拟机,不同的租户不共享虚拟网络,这样租户之间就隔离了,容器的内核也隔离了,二层网络也隔离了。

当然这个方式的另一个问题是Kubernetes的集群数目非常大,这在下面会详细说这个事情。

还有一个问题是容器放在虚拟机里面,虚拟机的启动速度就成了很大的问题,如果启动速度很慢,则会拖慢容器的敏捷性。

三、APIServer认证模块接Keystone解决复杂的租户管理问题

Kubernetes有基于keystone的用户名和密码进行认证的默认机制,然而每次用用户名和密码进行认证是效率很低的。

网易通过定制化认证流程,使得apiserver也采用类似nova的认证方式。

APIServer在keystone里面注册一个service角色的账号,并从keystone获取临时管理员的Token。

客户请求到来的时候,通过用户名密码到Keystone进行认证,获取一个token,并且带着这个token到APIServer进行认证,APIServer带着这个token,连同自己的临时管理员的Token进行联合认证,如果验证通过则获取用户信息,并且缓存到etcd里面。

当客户通过获取的token来请求的时候,先从etcd里面读取这个token进行验证,为了使用本地缓存,加一个listwatch实时同步etcd里面的内容到本地缓存。

如果token过期,则从新到keystone里面revoke。

四、从APIServer看集群的规模问题

随着集群规模的扩大,apiserver的压力越来越大。

因为所有的其他组件,例如Controller,Scheduler,客户端,Kubelet等都需要监听apiserver,来查看etcd里面的变化,从而执行一定的操作。

很多人都将容器和微服务联系起来,从Kubernetes的设计可以看出,Kubernetes的模块设计时非常的微服务化的,每个进程都仅仅干自己的事情,而通过apiserver松耦合的关联起来。

而apiserver则很像微服务中的api网关,是一个无状态的服务,可以很好的弹性伸缩。

为了应对listwatch,apiserver用了watchcache来缓解压力,然而最终的瓶颈还是在etcd上。

最初用的是etcd2,这个时候listwatch每次只能接受一个事件,所以压力很大。为了继续使用etcd2,则需要使用多个etcd2的集群来解决这个问题,通过不同的租户分配到不同的etcd2集群来分担压力。

将来会迁移到etcd3有了事件的批量推送,但是从etcd2到etcd3需要一定的迁移工作。

五、通过优化Scheduler解决并行调度的问题

对于大的资源池的调度是一个很大的问题,因为同样一个资源只能被一个任务使用,如果并行调度,则存在两个并行的调度器同时认为某个资源空闲,于是同时将两个任务调度到同一台机器,结果出现竞争的情况。

当OpenStack遇到这种问题,采取的方法是重新调度的方式进行。

而Mesos则采取了更为聪明的两层调度的算法。

详情见文章号称了解mesos双层调度的你,先来回答下面这五个问题!

Mesos首先通过第一层的调度Allocator,将不同的节点分给不同的Framework,则不同的Framework就能看到不同的节点了,不同Framework里面的调度器是第二层调度,是能够并行调度的,并且即便并行调度,不同的Framework也是不会调度到冲突的节点的。

Mesos的双层调度策略,使得Mesos能够管理大规模的集群,例如tweeter宣称的几十万的节点,因为对于某一个Framework来讲,不会同时在几十万个节点中选择运行任务的节点,而是仅仅在其中mesos分配给他的一部分中进行调度,不同的framework可以并行调度。

还记得前面我们提到的,为了租户隔离,不同的租户是不共享虚拟机的,这样不同的租户是可以参考Mesos的机制进行并行调度的。因为不同的租户即便进行并行调度,也不会出现冲突的现象,每个租户不是在几万个节点中进行调度,而仅仅在属于这个租户的有限的节点中进行调度,大大提高了调度策略。

并且通过预过滤无空闲资源的Node,调整predicate算法进行预过滤,进一步减少调度规模。

六、通过优化Controller加快新任务的调度速度

Kubernetes采用的是微服务常使用的基于事件的编程模型。

当有增量事件产生的时候,则controller根据事件进行添加,删除,更新等操作。

但是基于事件的模型的一个缺点是,总是通过delta进行事件触发,过了一段时间,就不知道是否同步了,因而需要周期性的Resync一下,保证全量的同步之后,然后再进行增量的事件处理。

然而问题来了,当Resync的时候,正好遇到一个新容器的创建,则所有的事件在一个队列里面,拖慢了新创建容器的速度。

通过保持多个队列,并且队列的优先级ADD优于Update优于Delete优于Sync,保证相应的实时性。

七、通过优化虚拟机启动速度加速容器启动速度

前面说了,为了保证安全性,容器是启动在虚拟机里面的,然而如果虚拟机的启动速度慢了,容器的启动速度就会被拖慢。

那么虚拟机的启动速度为什么会慢呢?

比较慢的一个是网卡的初始化速度比较慢,在OpenStack里面,往往需要通过访问DHCP Sever获取IP地址和路由信息,把IP静态化可以解决这个问题。

另外一个比较慢的是Cloud-init,这个是在虚拟机启动之后做初始化的一个工具,是为了能够在虚拟机启动后做灵活的配置,比如配置key,或者执行一些脚本。

在AWS里面,cloudformation编排工具在虚拟机启动后的一些编排工作是通过cloud-init来做的,弹性伸缩机制通过虚拟机镜像复制多份,复制后做的少量的配置工作也是cloud-init来做的。

OpenStack继承了AWS的这个机制,是通过Metadata Server来对虚拟机进行灵活的配置,包括OpenStack编排机制Heat也是通过Cloud-init进行配置。

对于Metadata Server的机制,可以看这篇文章当发现你的OpenStack虚拟机网络有问题,不妨先试一下这16个步骤

然而在虚拟机里面跑容器的方式,是不需要cloud-init的,因为灵活定制化的事情由里面的容器来做,用户使用的也是里面的容器,而不是虚拟机,因而虚拟机可以做的十分的精简,将不需要的服务全部删除。

八、通过使用IaaS层的高性能网络提供给容器高速互联能力

上一节我们讲过,使用Flannel和Calico都仅仅适用于裸机容器,而且仅仅用于容器之间的互通。

一旦有IaaS层,就会存在网络二次虚拟化的问题。

虚拟机之间的互联是需要通过一个虚拟网络的,例如vxlan的实现,而使用Flannel或者Calico相当于在虚拟机网络虚拟化的上面再做一次虚拟化,使得网络性能大幅度降低。

而且如果使用Flannel或者Calico,那容器内的应用和虚拟机上的应用相互通信的时候,则需要出容器平台,多使用node port,通过NAT的方式访问,或者通过外部负载均衡器的方式进行访问。在现实应用中,不可能一下子将所有的应用全部容器化,部分应用容器化,部分应用部署在虚拟机里面是常有的现象。然而通过NAT或者外部负载均衡器的方式,对应用的相互调用有侵入,是的应用不能像原来一样相互调用,尤其是当应用之间使用Dubbo或者SpringCloud这种服务发现机制的时候尤其如此。

网易开发了自己的NeteaseController,在监听到有新的Pod创建的时候,调用IaaS的API创建IaaS层的虚拟网卡,然后在虚拟机内部,通过调用Netease CNI插件将虚拟网卡添加到容器里面。添加的技术用的就是上一节提到的setns命令。

通过这个图我们可以看出,容器的网卡是直接连接到虚拟私有网络的OVS上的,和虚拟机是一个平的二层网络,在OVS来看,容器和虚拟机是在同一个网络里面的。

这样一方面没有了二次虚拟化,只有OVS一层虚拟化。另外容器和虚拟机网络打平的好处是,当部分应用部署容器,部分应用部署虚拟机的时候,对应用没有侵入,应用原来如何相互访问,现在还是如何访问,有利于应用逐步容器化。

容器还可以有一个网卡直接连接到公网,这一点能够保持公网IP在容器内部可见,容易使用,而且可以保证在容器的生命周期内,公网IP可以保持。

另外这个网卡在负载均衡可以使用,下面我们详细说。

使用OVS的二层网络,可以很好的实现多租户,高性能互联,QoS,安全过滤,放ARP和IP欺骗等。

九、通过优化kube-proxy优化内部相互访问

默认的容器之间的相互访问通过服务进行。

一旦创建一个服务,就会创建一个Endpoint,kube-proxy能够在api-server监听到这个服务的创建,则需要监听服务的端口,并且设置iptables将对这个服务对应的VIP的访问转发到kube-proxy的这个端口上。

当一个客户端要访问这个服务的时候,首先通过DNS,将服务名转化为VIP,然后VIP通过iptables规则转发到kube-proxy的监听端口,kube-proxy将这个包随机转发给后端的一个Pod。

当Pod无论IP如何变,如何弹性伸缩,只要有服务名,都能够访问到。

仅仅通过DNS,是能够做的服务名和IP的对应,也是可以基于DNS进行负载均衡的,这就是基本的基于DNS的服务发现。然而这种方式的缺点是不能够流控,所以最好中间有一个proxy,这就是kube-proxy。

就像Mesos中原来的服务发现是通过Mesos-DNS进行,后来改用了minuteman做这件事情,minuteman的实现机制和kube-proxy很像很像。

然而这种方式的问题是,当集群规模很大的时候,服务创建的很多的时候,kube-proxy会牵扯到大量的iptables和监听端口。

然而在我们的设计中,租户之间的容器网络应该是完全隔离的,在某个租户的虚拟机上的Kube-proxy是无需包含另一个租户的转发规则的。

所以这里做的一个优化是只监听本租户的service,并且创建转发规则就好,因为每个租户的节点数目有限,转发规则也不会很多。

十、通过LVS和haproxy进行外部负载均衡器优化

Kubernetes默认的外部负载均衡是用ingress做的,性能不是很高。

一般公有云要求负载均衡能够承载的吞吐量非常的大,不能用纯软的方式。

在网易的方案中,最外层有两个LVS,部署在物理机上,通过多个万兆上行口进行转发,可以承载非常大的吞吐量。

对于不同的租户,可以创建不同的软负载均衡,通过创建多个haproxy,构成一个集群,由于haproxy是基于虚拟机的,可以弹性伸缩,使得他也不会成为瓶颈。

haproxy是后端和容器进行二层互联,是通过虚拟网络进行的,然而haproxy连接LVS是需要通过物理网络的,这就需要haproxy通过上面的机制,通过两张网卡,一张卡连接到物理网络,作为前端,一张卡连接到虚拟网络,作为后端连接容器。

最后给一张优化总图。

支撑大规模公有云的Kubernetes改进与优化 (3)的更多相关文章

  1. 支撑大规模公有云的Kubernetes改进与优化 (1)

    Kubernetes是设计用来实施私有容器云的,然而容器作为公有云,同样需要一个管理平台,在Swarm,Mesos,Kubernetes中,基于Kubernetes已经逐渐成为容器编排的最热最主流的平 ...

  2. 支撑大规模公有云的Kubernetes改进与优化 (2)

    接下来我们按照kubernetes创建容器的详细过程,以及可能存在的问题. 一.API Server的认证,鉴权,Quota 当客户需要创建一个pod的时候,需要先请求API Server. Kube ...

  3. Azure China (1) Azure公有云落地中国

    <Windows Azure Platform 系列文章目录> 微软公有云Microsoft Azure已经落地中国,官方网址:http://www.windowsazure.cn/. 在 ...

  4. 微软公有云事件中心(Azure Event Hubs)在开放物联网大会(OIOT)啼声初试

     发布于 2014-12-29 作者 刘 天栋 2014年12月18日,InfoQ在京召开开放物联网大会(Open IOT Conference),微软开放技术(中国)资深项目经理陈岭在大会中针对 ...

  5. Windows Azure公有云服务相关方案

    http://www.cnblogs.com/sennly/p/4139675.html 1.公有云平台服务简介 Windows Azure 是一个灵活而开放的云平台,通过该平台,您可以在数据中心快速 ...

  6. 在Windows Azure公有云环境部署企业应用

    作者 王枫 发布于 2014年4月5日 企业内部应用转换为在线服务 Windows Azure已经成为众多IT服务提供商们热议的话题,其中,有的认为只有提供互连网用户服务的应用才适合放在公有云环境内运 ...

  7. [转帖]中国公有云2018H1市场占有率

    IDC:阿里云中国第一 市场份额为2到9名总和   https://news.cnblogs.com/n/617838/ 1 月 21 日,市场研究机构 IDC 日前公布 2018 年上半年中国公有云 ...

  8. 微软智能云Azure – 中国首家官方支持CoreOS的公有云

    北京2016年6月24日, 在由中国开源软件推进联盟(COPU)主办, 开源社协办,微软赞助的“第十一届开源中国开源世界高峰论坛”上,微软亚太研发集团云计算高级总监梁戈碧女士正式对外宣布一个令人振奋的 ...

  9. 当公有云Azure拥抱Docker容器技术

    本文转载至 http://3387405.blog.51cto.com/3377405/1598977 预见未来看似是一件不太可能的事情,然而现在企业科技高速发展的态势完全超乎想象. 就在几周前Inf ...

随机推荐

  1. beta版1.1.1

    先期发布的alpha版1.0.0版本通过张硕组的测评,我小组跟进修改了出现的问题. 1.首先解决了互测版本中无法正常退出界面的问题,并有退出提示,(确定,取消). 2.就之前提到的关于前期部分功能的割 ...

  2. 16、DecimalFormat类

    DecimalFormat类概述 在一些金融或者银行的业务里面,会出现这样千分位格式的数字,¥123,456.00,表示人民币壹拾贰万叁仟肆佰伍拾陆元整,java.text包下提供了一个Decimal ...

  3. _csv.Error: line contains NULL byte

    原因是表格保存时扩展名为 xls,而我们将其改为csv文件通常是重命名: 解决方法只需把它另存为 csv 文件.

  4. 大规模实时流处理平台架构-zz

    随着不同网络质量下接入终端设备种类的增多,服务端转码已经成为视频点播和直播产品中必备的能力之一.直播产品讲究时效性,希望在一定的时间内让所有终端看到不同尺寸甚至是不同质量的视频,因此对转码的实时性要求 ...

  5. Linux下实现多播(组播)

    单播只能发送给一个接收方,但是当给多个接收者发送时,不仅仅耗费流量,而且耗费时间,总流量=每个接收者的流量*接受者. 广播方式是发送给所有的主机,广播的坏处是会造成信息污染,大量的信息会占用网络带宽. ...

  6. 关于 JVM 内存的 N 个问题(转)

    JVM的内存区域是怎么划分的? JVM的内存划分中,有部分区域是线程私有的,有部分是属于整个JVM进程:有些区域会抛出OOM异常,有些则不会,了解JVM的内存区域划分以及特征,是定位线上内存问题的基础 ...

  7. 如何成为技术大牛——阿里CodeLife

    天天写业务代码的程序员,怎么成为技术大牛,开始写技术代码? 几个误区 跟着大牛,就可以成为大牛.首先,大牛时间很宝贵,不可能花很多时间去指导你:其次,简单的模仿大牛,只能学到表面知识,不可能成为大牛: ...

  8. 转:localStorage 还能这么用

    地址:https://iammapping.com/the-other-ways-to-use-localstorage/ localStorage 还能这么用 HTML5中 Web Storage ...

  9. PHP性能调优---PHP调试工具Xdebug安装配置教程

    说到PHP代码调试,对于有经验的PHPer,通过echo.print_r.var_dump函数,或PHP开发工具zend studio.editplus可解决大部分问题,但是对于PHP入门学习的童鞋来 ...

  10. jQuery类名添加click方法

    通过$("").jQuery为元素添加点击事件,在使用类的情况下,可以使用$(e.target).attr('title');获得被点击元素的属性值. 示例代码如下 $(" ...