Ocean起源于2015年年底,当时小米的第一代运维基础平台已经成熟,拥有包括监控、发布、域名、服务器流转等一系列核心组件。但是我们不仅仅满足于工具型的平台,还希望平台拥有PaaS 的能力,进而可以演进成为DCOS,甚至是DCBrain。
SCOPE
Ocean SCOPE 图
图中绿色的部分表示建设完成,橙黄色是正在建设,灰蓝色则是还没有建设或者未完成。
左侧部分为所依赖的基础架构的组件,右侧是希望获得的功能,中间是主要的基础架构。
Ocean相比其他的PaaS平台有两点不同,首先Ocean很注重与基础设施的联合设计,保障基础设施的整体性。其次不同于其他将无状态作为主要目标的PaaS平台,Ocean更重视有状态服务的PaaS与在此之上建设的SaaS系统与其所带来的能力。
收益
前四项是所有的PaaS平台都具备的能力,后两项则需要和基础设施配合共同联合设计才能完成的功能。
PaaS
服务树
服务树是非常重要核心的基础组件,主要定义组件和服务之间的关系。数据结构很简单,就是为服务器打TAG,再通过定义这些TAG的顺序来展现整个树的结构。
服务是服务树内以8个TAG一组定义的全局唯一的服务标识,作为整个运维基础设施所有组件的统一串联的粒度。Ocean每启一个容器都会在容器内植入docker init进程,把本容器的IP通过打TAG的方式注册进服务树,然后通过注册的动作联动其它基础设施组件产生效果。
免密安全登录
免密安全登录基于服务树节点授权,同时每次登录都需要进行双因素的认证。Ocean在启用容器后,同时也会在容器内植入免密安全登录的服务端,这样当任意用户的账号拥有了某一个服务树节点的权限后,就能在登录时完成认证和授权,从而使得物理机和容器的登录效果一致。
监控——全Push采集
我们的监控系统叫做Open Falcon,目前已被开源。而全Push采集是Falcon比较重要的设计,所有的监控数据都是通过Falcon-agent推到serever端。这有两方面的优点,一方面和弹性环境更加亲和, 因为Agent会从部署的位置自动采集数据然后上报。另一方面使设备具有策略自发现能力。
自动扩缩
自动扩缩通过与Open Falcon对接完成。Falcon会自动采集CUP IDLE、MEM FREE、PROC QPS、PROC DELAY这四个基础指标,以此来提供自动扩缩的能力。
当某个用户要基于某个指标进行扩缩,就会自动的为该条指标添加一条集群监控策略。当监控策略满足预值要求时会自动通过HooK方式回调Marathon API完成自动扩缩。目前我们最短5s触发伸缩。
日志查询
云原生环境与物理机运行不同,在物理机无论出现什么问题都可以在原先的位置查看日志,而在弹性环境中容器挂掉后,要从整个资源池找回已经挂掉的容器的日志是比较麻烦的,即便找到了也很难暴露给用户查看。
因此我们采用了ELK的解决方案,并将其中的L改成更轻量的客户端FileBeat。如果FileBeat运行在容器上,一旦容器挂掉后,FileBeat的一些日志就会来不及传输,所以我们将FileBeat运行在物理机上,同时在容器退出后延迟清除容器。
我们还制定了用户日志目录规范,通过修改FileBeat让它与目录的规范相配合,自动为日志添加标签数据。
动态环境引入新问题
服务发现
云原生如果没有服务发现整个弹性环境就无法动态起来,对于服务发现,不同类型的服务得到的最佳实践也不同。一般业务的程序会使用比较成熟的RPC框架,而对于第三方开源组件每个都会有不同的最佳实践。
动态安全
很多时候有些业务的数据或接口有很强的敏感性,在物理环境下我们会使用IP白名单的方式进行认证授权以及保障安全。但是这种方法在动态环境下并不适用,所以要提供一种在动态环境下的动态安全的解决方案。
假设在模型中客户端被部署在Ocean平台内,Docker init会把这些运行在Ocean平台的Job对应的IP和Job信息注册进集群 ,这时服务端就仅需嵌入白名单SDK和配置客服端的JobName,还可以通过IP加JobName共同防御ZK故障。
MySQL方面也存在动态安全问题,通常情况下我们会对库和IP进行授权,而动态环境下则要考虑如何进行动态IP授权。 与之前不同,数据库并不需要用户去植入SDK,但是要新增数据库实例授权的过程。我们这里是将Docker init和AppA Proc作为认证信任源,Docker init会向MySQL Auth宣告自己所属的Job,接着MySQL Auth会到Marathon内查询来源IP与JobName匹配情况,匹配成功认证通过。
DCOS
ELB(负载均衡)
创建ELB时需要绑定Ocean的中一个Job,当Job部署到Ocean后无论实例IP发生任何变化,我们都要做到LVS相应的RS都要跟随变更。
因此我们每创建一个ELB其实都会同时创建一个域名,并且按照运营商自动划分线路,这样就能让用户在使用时不感知的得到最佳实践,同时节省带宽资源。另外docker-init和ELB服务都会动态更新LVS配置,这主要是为了让ELB服务的可用性依赖下降。
DBaas
在弹性环境下无状态服务都相对简单,改造也非常容易。但是有状态服务就存在很多麻烦的地方,例如数据状态需要迁移、服务发现的最佳实践也要植入。因此我们将这些有状态的服务抽象成服务化组件的形态,让用户可以方便运行一个服务集群。
当用户通过提交参数创建MySQL集群时,会由Manger模块提供所要创建的数据库原信息数据给Marathon,然后在Marathon内创建DB APP Group,这个Group中会有DB Proxy 和DB 两种App。
在启动时候DB APP内会通过抢锁的方式产生三种角色,这些角色再经由所提供的配置运行起来。
DB Proxy APP在运行的时候会自动感知到抢锁得到的角色,并接收流量和配置。最后通过Mesos-Dns将 DB Proxy的域名暴露给用户。
整个流程中会使用Zookeeper自动恢复数据包括主库切换等一系列的事。
缓存服务
缓存服务一般使用分片方式,但是每个分片保存一个实例的话,当前实例挂了就会造成缓存失效,还会穿透到数据库,对业务产生影响。
理想的解决方案是每分片多副本。而我们提供了Memcached和Redis两种缓存服务,由于Memcached本身不支持每分片多副本,所以要在此之上引入Memcached Router。Redis则可以直接使用Redis cluster。
故障自愈
故障自愈用到了开源框架StackStorm,它是事件触发自动化处理的框架。
整个过程中由Sensors收集信息源,Rules完成需要统计计算或者判断触发的逻辑定义,当触发时随之启动一个Workflows,每个Workflows对应一组Actions。另外中心还有着可以贯穿所有模块的Audit模块,能够知道整个生命周期内所发生的情况。
在实际的建设时我们会将内部能够产生信息的基础设施作为输入对接到StackStorm中,StackStorm内的触发组件则对接到我们内部的控制系统。