手记

基于Kubernetes打造SAE容器云

作为国内第一个公有云计算平台,SAE从2009年已经走过了6个年头,积累了近百万开发者,而一直以来SAE一直以自有技术提供超轻量级的租户隔离,这种隔离技术实际是从用户态和内核态hook核心函数来实现HTTP层的进程内用户隔离:

基于HTTP请求的进程内隔离

如图所示,这种方式的好处是:

- 精准的实现租户间CPU、IO、Memory隔离

- 可以实现进程多租户复用,从而达到超低成本

- 完全对等部署,管理方便

另外,这种模式的最大好处可以实现完全的无缝扩容,SAE自动根据HTTP等待队列长度进行跨集群调度,用户从1000PV到10亿PV业务暴增,可以不做任何变更,早在2013年,SAE就利用这种机制成功的帮助抢票软件完成12306无法完成的任务,12306抢票插件拖垮美国代码托管站Github

但是这种模式也有很大的弊端,最主要的弊端就是:

- namespace独立性不足

- 本地读写支持度不好

- 容易产生用户lock-in

针对于此,SAE决定基于Kubernetes技术推出以Docker容器为运行环境的容器云,下面我们就以下三个方面展开讨论:

1,Kubernetes的好处是什么

2,Kubernetes的不足有哪些

3,针对不足,怎么改进它

一,Kubernetes的好处

选择一个技术,对于大型业务平台来讲,最重要的就是它的易维护性,Kubernetes由Go语言编写,各个逻辑模块功能比较清晰,可以很快定位到功能点进行修改,另外,k8s可以非常方便的部署在CentOS上,这点对我们来讲也非常重要。

k8s提出一个Pod的概念,Pod可以说是逻辑上的容器组,它包含运行在同一个节点上的多个容器,这些容器一般是业务相关的,他们可以共享存储和快速网络通信。这种在容器层上的逻辑分组非常适合实际的业务管理,这样用户可以按照业务模块组成不同的Pod,比如,以一个电商业务为例:可以把PC端网站作为一个Pod,移动端API作为另一个Pod,H5端网站再作为一个Pod,这样每个业务都可以根据访问量使用适当数量的Pod,并且可以根据自己的需求进行扩容和容灾。

相同的Pod可以由Replication Controller来控制,这样的设计方便Pod的扩容、缩容,特别当有Pod处于不健康的状态时,可以快速切换至新的Pod,保证总Pod数不变,而不影响服务。这种模式保证了实际业务的稳定性。

二,Kubernetes的不足

对于目前的Kubernetes来讲,无缝扩容是一个比较致命的问题,不过好在社区有大量的人力已经投入力量在开发了,截止到我写稿的时间,基于CPU的扩容代码已经出来,也就是用户可以设定一个平均CPU利用率,一旦数值高于某个阈值,就触发扩容。但当我们仔细思考这个模式时,就会发现不合理的地方:CPU利用率并不能真正反映业务的繁忙程度,也不能反映是否需要扩容。比如某些业务需要大量跟API或者后端数据库交互,这种情况下,即使CPU利用率不高,但此时用户的请求已经变得很慢,从而需要扩容。

再有,良好的监控一直是一个系统稳定运行的前提,但k8s显然目前做的不够,先不说k8s自身的监控,就是对于Pod的监控,默认也只是简单的TCP Connect,显然这对于业务层是远远不够的,举个最简单的例子,假如某个业务因为短时间大并发访问导致504,而此时TCP协议层的链接是可以建立的,但显然业务需要扩容。

还有一些其他的功能,不能算是不足,但在某些方面并不适用于SAE,比如Kube-Proxy,主要是通过VIP做三层NAT打通k8s内部所有网络通信,以此来实现容器漂IP,这个理念很先进,但有一些问题,首先是NAT性能问题,其次是所有网络走VIP NAT,但是k8s是需要和外部环境通信的,SAE容器云需要和SAE原有PaaS服务打通网络,举个例子,用户利用容器云起了一组Redis的Pod,然后他在SAE上的应用需要访问这个Pod,那么如果访问Pod只能通过VIP的话,将会和原有SAE的网络访问产生冲突,这块需要额外的技巧才能解决。所以我们觉得Kube-Proxy不太适合。

三,如何改进Kubernetes

针对k8s的不足,我们需要进行改进,首先需要改造的就是日志系统,我们希望容器产生的日志可以直接推送进SAE原有日志系统。

容器日志推送

如上图所示,我们将容器的stdout、stderr通过log format模块重定向分发到SAE的日志中心,由日志中心汇总后进行分析、统计、计费,并最终展现在用户面板,用户可以清晰的看到自己业务的访问日志、debug日志、容器启动日志以及容器的操作日志。

用户看到的日志

其次,既然我们不使用Kube-Proxy的VIP模式,那么我们需要将Pod对接到SAE的L7负载均衡服务下面,以实现动态扩容和容灾。

负载均衡同步

etcd watcher监控etcd里pod路径下的文件变更事件,得到事件取配置文件处理,判断配置文件里状态更新,将容器对应关系的变化同步到SAE Load Balance,Load Balance会在共享内存中cache这些关系,并且根据实际的用户请求的HTTP Header将请求forward到相应的Pod的对外端口上。当用户手工增加Pod时,Watcher会在100毫秒内将新增的Pod的映射关系同步到Load Balance,这样请求就会分配到新增的Pod上了。

当然,对于云计算平台来讲,最重要的还是网络和存储,但很不幸,Kubernetes在这两方面都表现的不够好。

网络

首先,我们来看对于网络这块PaaS和IaaS的需求,无论是IaaS还是PaaS,租户间隔离都是最基本的需求,两个租户间的网络不能互通,对于PaaS来讲,一般做到L3基本就可以了,因为用户无法生成L2的代码,这个可以利用CAP_NET_RAW来控制;而对于IaaS来讲,就要做到L2隔离,否则用户可以看到别人的mac地址,然后很容易就可以构造二层数据帧来攻击别人。对于PaaS来讲,还需要做L4和L7的隔离处理,比如PaaS的网络入口和出口一般都是共享的,比如对于出口而言,IaaS服务商遇到问题,可以简单粗暴的将用户出口IP引入黑洞即可,但对于PaaS而言,这样势必会影响其他用户,所以PaaS需要针对不同的应用层协议做配额控制,比如不能让某些用户的抓取电商行为导致所有用户不能访问电商网站。

目前主流的Docker平台的网络方案主要由两种,Bridge和NAT,Bridge实际将容器置于物理网络中,容器拿到的是实际的物理内网IP,直接的通信和传统的IDC间通信没有什么区别。而NAT实际是将容器内的网络IP:Port映射为物理实际网络上的IP:Port,优点是节约内网IP,缺点是因为做NAT映射,速度比较慢。

基于SAE的特点,我们采用优化后的NAT方案。

根据我们的需求,第一步就说要将内外网流量分开,进行统计和控制。

Docker网络

如图所示,在容器中通过eth0和eth1分布pipe宿主机的docker0外网和docker1内网bridge,将容器的内外网流量分开,这样我们才能对内外网区分对待,内网流量免费,而外网流量需要计费统计,同时内外网流量都需要QoS。

 第二步就是要实现多租户网络隔离,我们借鉴IaaS在vxlan&gre的做法,通过对用户的数据包打tag,从而标识用户,然后在网路传输中,只允许相同在同一租户之间网络包传输。

多租户网络

当网络包从容器出来后,先经过我们自己写的TagQueue进程,TagQueue负责将网络包加上租户ID,然后网络包会被Docker默认的iptables规则进行SNAT,之后这个网络包就变成了一个可以在物理网络中传输的真实网络包,目标地址为目标宿主机IP,然后当到达目标时,宿主机网络协议栈会先将该网络包交给运行在宿主机上的TagQueue进程,TagQueue负责把网络包解出租户ID,然后进行判断,是否合法,如果不合法直接丢弃,否则继续进行Docker默认的DNAT,之后进入容器目标地址。

除去Pod间的多租户网络,对外网络部分,SAE容器云直接对接SAE标准的流量控制系统、DDOS防攻击系统、应用防火墙系统和流量加速系统,保证业务的对外流量正常

存储

 对于业务来讲,对存储的敏感度甚至超过了网络,因为几乎所有业务都希望在容器之上有一套安全可靠高速的存储方案,对于用户的不同需求,容器云对接了SAE原有PaaS服务的Memcache、MySQL、Storage、KVDB服务,以满足缓存、关系型数据库、对象存储、键值存储的需求。

为了保证Node.js等应用在容器云上的完美运行,容器云还势必引入一个类似EBS的弹性共享存储,以保证用户在多容器间的文件共享。针对这种需求,k8s并没有提供解决方案,于是SAE基于GlusterFS改进了一套分布式共享文件存储SharedStorage来满足用户。

SharedStorage

如图所示,以4个节点(brick)为例,两两一组组成distributed-replicated volume提供服务,用户可以根据需求创建不同大小的SharedStorage,并选择挂载在用户指定的文件目录,mount之后,就可以像本地文件系统一样使用。我们针对GlusterFS的改进主要针对三个方面:1,增加了统计,通过编写自己的translator模块加入了文件读写的实时统计;2,增加了针对整个集群的监控,能够实时查看各个brick、volume的状态;3,通过改写syscall table来hook IO操作,并执行容器端的IO Quota,这样防止某个容器内的应用程序恶意执行IO操作而导致其他用户受影响。

通过SharedStorage服务,用户可以非常方便的就实现容器热迁移,当物理机宕机后,保留在SharedStorage数据不会丢失,k8s的replication controller可以快速在另外一个物理节点上将容器重新运行起来,而这个业务不受影响。

总结

Kubernetes是一个非常优秀的Docker运行框架,相信随着社区的发展,kubernetes会越来越完善。当然,因为SAE之前有比较完备的技术储备,所以我们有能力针对k8s目前的不足做大量的改进



作者:conglei_kobe
链接:https://www.jianshu.com/p/303e07a4fd0d


0人推荐
随时随地看视频
慕课网APP