编者按:
《微博混合云架构》专栏是 InfoQ 向新浪微博技术团队的系列约稿,本专栏包含 8 篇内容,详细阐述以 DCP 设计理念为指导思想的混合云架构实践。本文是该系列的第五篇,主要介绍容器编排的设计与实现。
《微博混合云架构》专栏主要包括以下 8 篇内容:
- 混合云架构挑战与概述
- DCP 的不可变基础设施
- DCP 的弹性调度揭秘
- DCP 的镜像分发实战
- DCP 的容器编排设计与实践
- DCP 的服务发现
- DCP 的容量决策评估
- DCP 的监控体系
概述
最近由于个人原因,与 InfoQ 约稿的专栏《微博混合云架构》很久没更新了,在此深表歉意。今天的主题内容主要写容器编排设计与实践。在开篇之前,我觉得有必要回顾一下前面内容。目前已经发表了 4 篇。
- 概述篇:主要分享了微博部署架构、业务场景、存在的挑战与痛点及微博混合云系统 DCP 的主体架构设计思想
- 基础设施篇:主要分享了微博的不可变基础设施进化之路,环境标准化,配置管理等内容
- 容器调度篇:主要分享了微博应用 Docker 的实践之路及容器调度演进
- 镜像分发篇:主要分享了大规模下 Docker 镜像分发与优化实践,多版本共存等疑难问题解决方案
再看本篇前,可以回去看看 InfoQ 官网上这些篇的内容,有助于更好的理解接下来的内容。
关于编排
什么是容器编排?
编排是 Orchestration 在国内的常见译法,刚开始接触这个词时,我也很迷惑,为什么这么翻译,等理解了才明白一二,它其实是一种“设计”方法,在很多领域可见,在 Container 技术大火后,才真正进入我的视线。举个不恰当的例子:编舞师要想创作一个好的舞蹈作品,必须精心的编排,这包括灵感及创意、挑选演员,人数安排,舞美设计,人物动作表情,排练及突发情况下的应对等等,是一个复杂的过程。
对标到 Container 的场景,我们知道原生的 Docker,其实是个单机版的,所以 Docker 官方才会出了一系列的工具,比如最早的时候单机版的编排工具 Fig(团队被收购),远程下的编排工具 Swarm,甚至发布了 Docker Datacenter,其中的 UCP 就嵌入了 Swarm,以实现对 Docker 的环境管理与编排。
因此,对于容器编排,可以从以下两个方面理解:
- 容器编排是跨主机去管理多个集群 Container 的一种行为,随着 Docker 的发展,生态圈越来越完善,比较常见的 Kubernetes,Mesos + Mathon,甚至 DCOS 等都属于此类范畴。
- 容量编排是为了将资源利用率最大化,同时均衡系统因容错需要不断变化的需求。可以看下图
我们可以看到,早期的应用场景,经典的三层架构中,不管物理机或者 VM,一般一个机器一般只跑一个服务,而在 Container 时代,不同的服务可能跑在同一个机器节点上,这种服务的组合是不固定,动态的调配,对工程师是透明的。这种动态的调整能力可以称得上是容器的编排。
从这个图中我们可以抽象出,容器编排需要解决哪些方面
- 服务定义:一般以 IP + port 唯一标识一个服务,这里端口的分配与管理会成为重点。
- 资源管理:一个服务要运行,需要相应的资源,一般是 CPU/MEM/DISK/NET 等,怎么获取到这些资源,并合理分配是资源管理需要关注的部分,一般采用池化处理(资源池)。这也是编排的核心,Mesos 在这块做的比较好,通用且稳定。
- 容器调度:有了资源,怎么合理的选择资源节点,采取什么策略,怎么做容错处理等等,这些是容器调度需要关注的。
- 服务检测:服务在起来后,要对外提供,需要验证其正确性,这里一般会做端口及业务检测
- 服务发现:验证通过的服务,如果真正对外提供服务,需要引入流量,也就是自动挂到 LB 上,这也是一种 WEB 类的服务发现。
以上 5 种我觉得是容器编排里最核心的内容,实际上,生产环境的编排单元远远比这里多很多。
注: 这里插播一个,我经常看到很多同学把容器编排和容器调度等同,其实吧,无所谓对错了,这可能主要的原因是大家的理解不一样,表达的方式也就有差异,不用纠结,只要把你的业务问题很好解决了,就是棒棒哒。
分层的编排?
随着行业的发展,我们看到互联网技术领域的一些趋势:
- 可编程的基础架构的崛起,比如云计算,配置管理,Contianer 技术
- 应用架构的变迁,单体应用 ->SOA-> 微服务
- 新流程及新方法论的出现:如精益,敏捷和 DevOps
在这样的趋势下,互联网公司多多少少都会根据自己的业务场景做出一些改变,比如升级应用架构,业务上云等等,这其实对运维来说,复杂性在过渡阶段是增加的。就拿我们的业务来说,建设私有云的同时,也推业务上云,我们的基础架构很难用标准化的方式去满足需求,这也推动我们去重新建设运维平台,也就有了混合云系统 DCP 的诞生。我们在设计之初的时候,遇到了一个很明显的问题,我们很难用单一的 IaaS,PaaS 或 CaaS 去定义我们的场景,于是我们选择了混合云的模式,系统采用分层设计的方法去适应业务场景。
在这个过程中,我对编排的理解又有了一些变化。我觉得不同的层是存在不同的编排方法的。简单来说,IaaS 的编排核心重点在计算资源,PaaS 的编排核心在于应用,CaaS 的编排核心在于容器即服务。而对于我们的混合云 DCP,我把他分为两大方面:
- 服务的编排:重在弹性,比如扩容,缩容,容器迁移,容错处理,服务发现等
- 资源的编排:重在资源,对于私有云主要是物理机的管理与分配;对于公有云主要是标准化的 VM,我们用到了阿里云的 ECS
对于资源的编排,混合云模式下,专线的落地是最重要的,决定着整个设计及业务上云的规模,如下图,我们与阿里云之间就通过 VPC 技术拉通了常备的专线,打通内网。
在分层设计之上,我们在工具选型上就明朗多了,主要选用了自研的 Dispatch 和 Swarm。
微博混合云 DCP 架构设计
微博目前开发的 DCP,主要包含 3 层,资源管理层,容器调度层及业务编排层。底层的资源管理分为两个部分:内网主机和阿里云 ECS,我们的目标是对上层业务提供统一、不可变的基础环境 ; 中间的容器调度层,主要是根据资源去调度容器,并启动容器,提供各种原子型的操作,比如基于任务模式的容器起、停、删、重启、服务注册、服务反注册、服务检测等等;最上层的业务编排层,则是基于调度层的 API,去串起整个业务的常见操作,比如服务部署、扩容、缩容、容器迁移等等。根据上面对于编排的理解,我觉得把资源层算作资源编排,而调度层与业务编排层,统一称服务编排。我们看下图:
这里需要说明的是,分层设计的指导思想的核心:
- API 化:层与层之间皆是 REST 型的 API 相互通讯,底层对上层提供 API。
- 操作幂等:核心的操作是可重复的且可逆的。
- 容错处理:对异常及失败情况下的容错处理。
细化出来,DCP 的功能模块是很多的,可见下图:
其中,资源管理层的模块主要是调度运算资源。目前设计了共享池、Buffer 资源池,配额管理,及多租户管理机制,借此实现弹性调度资源,这也是 DCP 的核心之一,可以看做是一个定制的 IaaS 吧。调度层后面会细说,基于任务机制的容器调度。
这里重点说下业务编排层:最上层的是对业务场景的抽象,根据目前的梳理,微博的业务,前后端各种语言都有,加上大数据体系的服务,在这种情况下,我们很难抽象出用一种非常通用的模式,直接支持各种语言的服务,这也受限于不同服务的 Docker 化程序。于是我们做了如下设计:
- 服务设计:我们设计了集群,服务池,容器节点这样的三级维度去描述服务
- 业务级隔离:产品线对应集群,集群与集群之间在业务层上是产品线之间的隔离,各家自己的服务互不影响。
- 开放业务编排层:微博后端几乎是 Java 类的服务,前端是 PHP 类,同时大数据体系又有离线计算和实时计算的,还有一些小语言的,每一类的服务,我们做成是通用的模式,比如 Java 类的就独立设计其编排模式,并且把这个设计开放到公司的范畴,别的部门也可以来一起参与设计并实现。在开放的过程中,我们的原则:底层的资源,调度,服务服务一定是全公司内统一的。
从这些架构设计角度,可以看出,我们的 DCP 的核心设计理念包括 4 个:弹性,自动化,业务定制及 all in one。相对 XaaS 类的服务,我们更注重业务需求的落地,解决实际问题。
ps:综合来看,我觉得有一个很重要的点,虽然 Docker 很火,但好多公司都很难将自己的业务 Docker 化的比较彻底,这其实也在影响着你的架构设计。比如与物理机还有一些依赖的东西,比如程序部署的逻辑关系,比如日志及围绕日志的周边工具,但是业界的一些开源编排方案,schedule/scale/rolling update 等这些操作,其实对业务的标准化要求很高,包括试用的一些云服务,要想把业务以最小成本的迁移部署,有一定难度的,所以有些公司内搞 Docker,定制化的需要还是很多的。所以如果你想大规模用,其实可以考虑牺牲一些通用性的原则的,我觉得微服务看来是一个解决方案,由于历史原因,我们很早就是服务化了的,要改造成微服务化,成本蛮高,因此从 14 年业务上云之后,虽然相对来说,走在了前面,但是一直还在路上摸索着。
服务设计
这一节,我们再来看看 DCP 对服务的设计,我们的核心需求是弹性,设计了集群,服务池,节点这三个维度,而弹性是建立在服务池这个维度的,以 IP + port 唯一标示一个服务。如下图:
众筹池与 Buffer 池
这里有个两个易混淆的概念,众筹池是所有集群的冗余设备;Buffer 池是集群内的冗余设备。这么设计的主要考虑是,某个业务在集群内的服务之间,是很容易自己去弹性调整的,集群内容量不足了,则会去私有云内调度,私有云内也没有的,会去公有云调度。保证服务可用性,同时为了保证每个集群(产品线)不乱用,给集群设置了配额的管理。从业务运维的角度可以看到如下的流程:
除此之外,值得一提的就是 DCP 的用户视角,我们设计了三类角色:
- 超级管理员:负责管控私有云及公有云的资源
- 集群管理员:负责管控自己产品线内的资源
- 服务池管理员:基本上业务运维,他们负责线上各种具体的操作
业务编排
有了服务设计以及原子型的调度 API,去实现业务编排就简单很多了,大体可以分为 2 个部分:首先,根据某类业务场景,设计较为通用的 Docker 化方案;其次是服务部署及弹性扩缩容。
弹性扩缩容
在概述篇中,我们已经讲到,服务的弹性扩缩容其实是一些很重的操作,在 DCP 中,做了 3 个流程的设计,来串起这些复杂的操作,这 3 个流程是:资源申请、设备初始化及服务上线。弹性扩容任务所需要的设备来源是内部的集群以及外部的阿里云。而申请到足够设备后,也必须对设备进行初始化、部署环境及配置管理。最后一步则是将服务上线,开始执行 Container 调度以及弹性扩容的任务。
第一步,则是资源申请,这在服务的设计已经详细说了,私有云的设备来源,主要来自离线集群、低负载集群以及错峰时间空出的多余设备。具体来说:离线集群并不是时时刻刻都在执行运算,即使稍微减少计算资源,也不会对业务产生重大影响;而工作负载较低的集群,如果有多余的资源也可以进行调度。此外,微博有上百个业务线,每个业务线峰值出现的时间点都不一样,而在此种状况下,各业务也可以互相支援,共享多余的计算资源。私有云的设备不足,会去公有云上自动创建,整个操作流是自动化的。
第二步,则是设备初始化,我们已开发了工具系统:可以达到操作系统升级自动化、系统操作 API 化,而服务器所依赖的基础环境、需要的软体等环境配置等需要标准化。如下图
私有云内通过配置管理工具 Puppet,将需要的配置写成模块,并使用 RPM 机制打包,进行安装。而公有云则是通过 Ansible 来做此类工作。这块业界中的一些做法也可以免去初始化的流程。例如导入为 Container 而生的容器操作系统,像 CoreOS、RancherOS 或 Red Hat Atomic。不过,虽然这样可以,但是此种做法的可维护度高,但是缺点在于迁移设备的成本较高。
当然这个操作也是耗时操作,主要的时间取决于申请资源的时间,实际初始化也就只需要 1 分钟而已。
(点击放大图像)
第三步,则是最为复杂的弹性扩容操作,前一线的运维人员,只要在系统页面上输入服务池名称、服务类型、Container 类型、需要Container 数量以及镜像地址等参数,即可在5 分钟内完成扩容,扩容完成后,系统也会产出完整的报告,列出扩容程序中,执行的步骤,以及每件任务的成功、失败状况。我们先来看下扩容流程:
我们再来看看耗时分析:可以看到大部分的弹性扩容任务都是分钟级的,总体上,基本能完成10 分钟扩容上千Container 的能力。
(点击放大图像)
任务系统设计
由上面可以看到,这些每一个流程能够很好的串起来,以及容错机制,这背后是有一套任务引擎在工作的,这个就是任务系统。其主要的思路是改造原有自研的 jpool 系统为任务引擎,来串起这些操作。
- 任务定义:详细的任务参数设计,模板引擎,回滚等
- 任务控制:并发执行,并发数控制,比例及步长控制,超时控制等
- 容错处理:异常及失败处理,容器迁移等
详细信息,可以看我在 Qcon 2015 上有个 Jpool 的分享,这个就不细说了。
无人值守的弹性扩缩容
再次回到概述篇,我们建立这一套系统,核心要实现的是服务具有弹性,能根据容量情况进行自动的弹性伸缩,以此来解决明显的早晚高峰及热点事件的峰值问题。截止到上面讲的,我们的系统已经完备了,但是操作的触发是需要人的参与,而且也会有几个操作步骤,人本身是懒惰的且是易犯错的,且还会存在人力成本,这还没达到我们的目标,离无人值守还差一段距离,于是,我们又开发了两个工具:
- 容量决策系统:可以每周在线压测服务,评估出每个服务的容量数据,以供决策;
- 调度框架:在任务之上,采用基于时间段的调度策略,在业务访问低峰时执行缩容策略, 高峰来临前执行扩容策略。
经过分析,我们的调度框架需要有以下几个特性
- 支持各种调度策略,初期可考虑实现基于时间的调度方式,类似 crontab 触发机制,Chronos、 Quartz 提供可借鉴的任务调度实现机制。
- 支持主备模式,如 Mesos 和 Swarm 多提供了多主的实现,其中 Swarm 采用 consul、etcd、 zk 等协调服务,各 master 间通过竞争一个分布式锁的方式来获取 leader 权限,获得 leader 权限的进程对外提供服务,未获得 leader 权限的进程处在等待状态,可参考 Swarm 的多主实现方式。
- 提供 Http API 运维配置,Consul 提供了非常优秀的 RestFul 协议和 UI,可参考。
- 支持服务的依赖,A 服务依赖 B,B 在自动弹性扩容时,需扩容好服务 B。
- 所有参数,可配置化。
最后形成的架构如下,并用 Go 做了实现:
可以看到,在更高层面的调度框架具有以下特点:
- 定时触发:以天为周期,自动执行扩缩容任务,任务结束后发送邮件提醒;
- 依赖控制:如 V4-Feed 依赖 RPC-User,严格控制上下线顺序与数量比;
- 并行化:即使有依赖也只在关键流程做同步控制,不同业务完全并行;
- 容错机制:重试、超时、回滚 (如扩容中失败的机器立即释放) 等;
- 可重入与幂等性:进程重启后从退出点继续运行,同一个时间任务执行多次均不受影响;
- 多 master 机制:确保 Scheduler 本身的 HA。
这个调度框架组件目前已经很稳定,每天都会定时的在晚高峰进行自动弹性扩缩容。有了它,我们私有云的核心服务的冗余,从之前的冗余 150% 减少冗余 120%,这样就可以下线调一大批机器,以节省成本,真正实现基于公有云的弹性。
除此之外,基于这个框架 API,做了个可配置的简单页面,定义服务以来及弹性扩容参数,非常的方便,见下图:
(点击放大图像)
ps: 此任务非上面任务系统中的任务。
总结
基于容器的业务编排在整个混合云的设计当中,是非常核心的内容,为新浪微博元旦,春晚及日常晚高峰的弹性扩容提供了强有力的支持。我们当前还在不断的完善系统的建设,同时,也正在纳入更多的业务场景,还是那句话,基于 Docker 的云应用,我们一直在路上。希望我们的方案对大家有一定的参考意义。
感谢魏星对本文的策划和审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们。
评论