在3月21日由OpenStack中国用户组主办的OpenStack Meetup活动上,UnitedStack运维团队负责人,同时也是OpenStack社区核心开发者的余兴超分享了多年运维OpenStack服务的经验和体会。本文根据余兴超演讲的部分内容整理而成,主要包含OpenStack在实际服务运维工作中所遇到的具体挑战,以及统一运维的具体策略。
持续集成(CI)和持续交付(CD)是OpenStack运维工程师们所面临的两大课题。其中,持续集成是保证整个研发团队的开发进度保持同步,其目的是消除由于集成问题引起的项目延期;持续集成的最后一公里是交付,所谓交付,也就是将代码最终部署到线上环境,转变成生产环境中提供服务的软件。
六大挑战困扰OpenStack持续运维
要实现持续集成和持续交付的目标对于UnitedStack的运维团队是一项异常艰巨的任务。具体说来,运维的挑战来自以下六个方面。
项目和服务众多的问题。这其中包含了Nova(计算)、Glance(镜像)、KeyStone(识别)、Neutron(网络)等常规的OpenStack的服务组件,也有UnitedStack内部开发的一系列服务,例如Placebo(面板)、Kiki(消息通知)、Ticket(计费)、Gringotts(API中间件 )等等。另外,还需要管理一系列的基础服务,例如消息队列、数据库、负载均衡、高可用软件等。
服务软件包的依赖复杂度。比方说,计算服务Nova的软件包的线上运营需要安装13个相关的Nova包、163个相关依赖包,同时还要升级9个相关的依赖包。大多数依赖包都有非常严格的版本要求。
配置文件和选择繁多。还是以Nova为例,仅Nova.conf就有835个配置选项,算上注释,大约有1700多行。
OpenStack灵活的架构带来的运维挑战。OpenStack可以将某些功能和后端驱动抽象为独立的Filter和Plugin。比方说,你可以选择用Nova-Network还是Neutron来构建SDN,可以选择用Ceph还是Sheepdog作为Cinder backend,还可以选择KVM还是Xen作为Nova-compute的Hypervisor。
私有Patch太多。事实上,UnitedStack的服务运维团队对于私有Patch的态度是非常谨慎的。我们会尽量把Patch提交到社区,即便未提交的社区,也会尽可能地不去破坏Patch的代码逻辑,即便不得不进行修改,也会尽可能地保持代码的可维护性。但即便如何,运维的难度依然很大,目前UnitedStack团队运维的很多服务的私有Patch都超过了100个,例如Keystone、Ceph和Neutron。
这些坑都趟过了,等着你的还有OpenStack各个项目版本频繁变更带来的运维陷阱。这也是由社区和我们自己的研发结构所决定的。大家都知道,每隔6个月,OpenStack社区的各个项目都会发布新的版本。UnitedStack的服务版本更新则穿插其间,过去的半年时间,我们每个月平均上线2.6个新项目。回顾UnitedStack过去32周的线上环境软件包版本的变更次数,我们发现,版本变更始在过去的半年多的时间里保持了相当高的变更频率,其中由两周的变更次数超过了70次。
“四个统一”实现运维自动化
越是复杂和多变的系统,就越需要统一的运维规范和框架。而这里说的统一是指统一的框架、统一的工具、统一的处理流程,以及统一的接口。
统一的框架
在UOS 1.0版本开发时,UnitedStack活力四射的工程师们开发了很多项目,编程语言也是多种多样,Java、Python、Ruby都有,持久化后端有的用SQL,有的用NoSQL,消息队列有的用RabbitMQ,有的用ZeroMQ。我们的运维团队很快就Hold不住这些大神们了。我们也曾经尝试过制定相关的开发规定,但是无法起到实际的约束作用。最后,还是由运维团队牵头,制定了名为BoneDragon的统一的开发框架。这一框架是用Python语言编写的,可以一键生成项目的基础开发框架,包含标准化的API模块、数据库模块和测试用例。BoneDragon框架已经开源,并且发布到GitHub上。
统一的工具
UnitedStack已经建立了一套由统一的工具构成的持续交付系统工作流程。统一的工具组由PSRForge(包管理系统)、Puppet(配置管理系统)、Ansible (任务编排系统)和Jenkins(自动构建系统)组成。它们覆盖的软件打包、任务编排上线、任务部署、部署验证任务的完整流程。
其中,包管理系统PSRForge是我们自行开发的,因为当时我们没有找到合适的开源项目。我们的团队目前维护着大概230个软件包。包管理系统共分为三个子系统,分别是Spec管理系统、软件包自动构建系统和软件仓库管理系统。
配置管理系统是OpenStack服务持续交付工具链的核心组件。在谨慎的调研和考量后,我们选择了Puppet作为配置管理工具。在此我想强调的是,没有任何一个工具是万能的,既然选择使用一个工具,运维团队必须清晰地明确它的能力和局限。拿Puppet来说,它非常适合做软件包的安装、配置文件的管理、服务状态的管理、命令的执行等;但它也有一些天然的短板,比方说不太适合做源代码的管理、依赖包的管理,也不太适合做服务的初始化操作、服务状态的监控和恢复,以及节点间的依赖管理。
因为Puppet缺少任务编排能力,因此我们一直在寻找一个工具,可以达到我们的期望。任务编排系统我们最终选择使用的是Ansible。在此之前,我们陆续使用过Dispatcher、ClusterShell和Mcollective 。其中,Dispatcher是我们基于SSH+ini配置文件自行编写的,后来我们发现开源项目ClusterShell同样是基于SSH,并且功能十分完善。后来我们转向Mcollective,这是Puppet Lab专门收购的一款配置管理工具,后来放弃Mcollective的主要原因是它的架构过重,同时是用Ruby语言编写的,而统一一直是我们追求的目标。Ansible目前在UnitedStack的运维效果我们是比较满意的,它的优势体现在无代理、基于yaml的配置文件,并且可用于集群的任务编排。
Jenkins是目前业内运用最为广泛的自动构建系统。目前,UnitedStack所有重复性的工作,比如执行单元测试、集成测试、构建软件包等工作必须以Jenkins的job形式出现,这样使得打包和测试工作自助化,也是我们实现自动化运维的前提。目前,UOS的各项目单元测试、UOS各项目打包、Doctor集成测试、UOS环境构建和清理已经全部在Jenkins平台完成。
统一的流程
在高速运转的持续交付流水线中,流程的统一举足轻重,这也就意味着流程的制定是非常关键的,要既合理,又尽量简单。目前,我们使用的流程包括软件包管理、线上服务变更、软件发布周期管理、部署逻辑代码提交、公共库变更等等。
我个人觉得非常值得分享的是我们的持续打磨的OpenStack跨大版本升级流程。我们是从2011年的Diablo版本开始接触OpenStack,期间经历了数次的大版本升级,至今已经总结出了相对成熟的大版本升级的具体流程。
在研发端,研发团队需要确认项目的upstream Base,也就是确认版本的合并点;然后,完成私有patch的合并工作;第三,给出依赖库的版本变更列表,放入requirements项目中;第四,给出配置选项的变更列表;第五,给出数据库schema的变更版本,以方便部署是的检查。
在部署端,我们首先需要更新SPEC、SOURCES文件,制作新版本软件包;然后更新puppet-xxx module,合并私有patch;接下来在开发环境上线进行调试,并且打上预发布版本号,在测试环境上线,同时需要通过集成测试。
线上的变更是需要特别谨慎的,稍有不慎就会有意外事件的发生。在版本最终上线前,开发团队需要给出线上业务变更单,说明业务变更内容,可能造成的影响,执行流程,回滚流程等;涉及公共库变更的,需要所有相关人员确认;业务的变更流程已预先制定完成,则必须借助工具自动执行。你只能与命令行工具做交互,输入Yes or No,但不能输入任何命令。
统一的接口
在UnitedStack,我们的自研项目和OpenStack项目都提供了统一的API,我们也有自己的命令行工具(UOS CLI)对一些资源操作进行封装和简化,这些前提使得我们的自动化测试工作变成可能。
以此为基础,我们构建起名为Doctor的健康检查服务。Doctor服务主要的功能包括,诊断UOS所有的服务是否正常;恢复UOS所有的服务至正常状态;收集UOS服务的错误日志和相关的系统信息。
下图是创建volume snapshot操作失败后的反馈,Doctor服务会描述操作的执行时间、执行过程、故障发生的步骤、服务的错误日志等,都会详细地展示并说明。
本文转载自infoQ