猪八戒网的DevOps进化论


写在前面

猪八戒网的系统架构演变史

2015年前,猪八戒网80%的项目都是PHP语言开发的,剩余少部分系统使用Node.js和Java。2015年一个关键的里程碑,开启了猪八戒网SOA服务转变,这就是腾云7号行动。

腾云7号可谓意义深远,它使用Java语言将核心业务代码进行了重构,建立了以Dubbo为核心的SOA服务框架,使用ZooKeeper + Swoole为核心的业务调用提供机制。
1.jpg

图1 猪八戒网架构演变过程

满足新业务使用Java语言编写、老业务仍然使用PHP编写,同时支持两种语言调用Dubbo服务的能力。
2.jpg

图2 SOA项目系统架构

开发语言变迁

在SOA架构的基础上,2016年开始全面推行前后端分离,于是出现了三足鼎立的局面:
  1. Node.js:负责前端
  2. Java:负责后端及老PHP项目迁移
  3. PHP:负责老项目维护


剩余部分小系统或者边缘化的工具使用其他语言开发,或者在此三种语言基础上的一些变种:
3.jpg

图3 开发语言演变过程

疯狂增长的背后

系统架构以及语言体系的变化,随之而来的是项目工程的指数级增长:
4.jpg

图4 项目增长走势图

项目工程的增长,给软件研发过程管理带来了较大压力,这时候公司开始推行敏捷。
5.jpg

图5 敏捷项目管理与发布

区别于业界流行的敏捷开发模式,猪八戒网根据公司实际情况做了一点小小的变化,即增加了deploy的概念,整个层级变成:deploy->story→task。

deploy是story的集合,作为一次上线发布的内容汇总,它主要负责从开发到测试到运维的交付件说明,以及开发-测试-性能-预发布-灰度-线上各环境代码发布的准入准出标准控制,deploy这部分将在后面DevOps中做详细介绍。

业务扩张对运维又带来了压力,大量的项目需要进行发布,所以虚拟机的数量也不断增长,管理难度随之加大,运维人数最多增加到三十多人:
6.jpg

图6 服务器数量

为了降低维护难度,我们开始做CMDB,指定各种规范,同时进行多数据中心建设,业务上做异地双活。
7.jpg

图7 多数据中心建设与异地双活

Nginx加载Upstream进行灰度和生产环境流量控制,DNS负责数据中心切换,能达到在某个数据中心挂掉的情况下快速切换到另外一个数据中心。

敏捷开发、快速增长的项目工程、不同语言的编译构建、不同数据中心的部署和代码发布、不同数据中心和不同环境之间的服务监控以及反馈链路,如何满足这些需求并且将它们连起来,这是猪八戒网需要解决的重点问题。

DevOps进化论

为了满足业务快速扩张的需求,2016年末开始组建DevOps团队,集合了运维、配置管理、Java技术人员等。团队专门负责DevOps方法论以及技术的落地,全公司使用统一的标准进行软件开发,并使用统一的工具进行项目管理。一张图看猪八戒网的DevOps:
8.jpg

图8 猪八戒网DevOps全景图

上图中的DevOps是一个平台,它集成了从开发到测试到上线的整个过程,基于这个图重点介绍:

新建Git工程

在2016年开始,公司搭建了GitLab,后来发现GitLab和SVN大家都在用,那么整个发布系统需要支持两种版本库(那个时候的发布系统并不是Jenkins,而是公司自己开发的syn2,基于Django框架的Python前端,调用后端shell实现编译构建和发布),虽然当时都支持了,但为了统一版本库,降低维护成本,我们关闭了SVN,将所有SVN项目迁移到GitLab中。

同时我们提供了Java的Dubbo和API工程模版,Node.js的两个框架工程模版,用户在DevOps平台可以直接选择工程模版,然后自动创建一个Git工程并返回给用户Git地址。

构建

针对开发语言的不同,我们提供了12种编译方式,分别为:Java、PHP、Node.js、Utopia、Scala、GNode、Jello、FIS、HTML、TPL、Thrift、BLG。

针对不同的编译方式,我们提供了不同的Jenkins构建环境,当然,我们把它集成在了一起,Jenkins采用Master/Slave的架构,支持任何语言的编译,Jenkins将在后续介绍。

发布组件

Java的组件,构建后发布到Nexus组件仓库,原来我们的Nexus组件仓库不受控制,开发人员可以随意上传组件,不管是snapshots还是release,所以导致很多release版本问题,后来我们做了权限控制,发布也统一起来,开发人员可以在本地将snapshots上传到Nexus仓库,但是release的必须使用DevOps提供的能力上传,这极大的保护了release版本的稳定性。
9.jpg

图9 Java组件化统一发布标准

发布API

Java的API接口实现,这里有三个功能:发布组件到Nexus仓库、自动生成API接口文档、将代码转换为PHP和Node.js生成物(这里没有历史,只有今生)。
10.jpg

图10 API服务统一标准一键发布

这三个功能用户可以一键触发,所以任何部门的API接口,只要一发布,必然有最新的接口文档,避免了接口文档认为更新不及时的问题。

发布流水线

流水线的演变是基于测试环境的变化而变化的,曾经我们的测试环境比较单一,流水线也相对简单,但随着业务的快速发展,单一的环境凸显大量的问题,所以我们开始在环境和流水线上进行优化改造。

曾经猪八戒网的测试环境都是由DevOps团队统一管理和维护的,随着环境和流水线的不断优化,后来交接给运维团队负责,目前已经在慢慢将测试环境交给开发和测试自行维护,但大家意识上还是比较多的依赖于DevOps和运维帮忙解决环境上的问题,这里先介绍流水线上发布模式进化的三个阶段:

第一阶段:我们叫它大锅饭年代
11.jpg

图11 发布流水线大锅饭年代

这个时期的流水线很简单,环境也很简单,问题点主要也就是上图中的情况。

第二阶段:又叫公交车模式

在这个阶段,我们的系统架构还没有Dubbo,这次调整只是为了解决环境共用导致的相互影响,所以搭建了t1、t2、等t系列测试环境。测试完成后将代码合并到Trunk推送预发布,在预发布做回滚测试,上线时直接将预发布的代码同步到生产环境,保证预发布的代码和生产环境代码一致。
12.jpg

图12 发布流水线公交车模式

公交车模式解决了第一个阶段提到的1和2两个问题,但项目仍然耦合。所以我们以公交车模式通过降低线上变更频率【每周二、四15点,公交车司机准点发车,将预发布上的代码同步到线上(并不是将Trunk代码发布到线上)】来达到耦合带来的问题;虽然解决了一部分问题,但随之而来的需要大量人工劳动力去维护这大量的测试环境,环境一致性问题随之突出。

第三阶段:也叫出租车模式
13.jpg

图13 发布流水线出租车模式

为了解决项目的耦合问题,以及环境一致性问题,我们开始给每个项目指定开发负责人,这种责任人制度,很大程度上解决了耦合的问题,大家都开始将各自负责的项目权限收起来了,业务范围和边界更清晰。同时引入Docker技术,实现构建一次处处运行,解决了环境一致性问题。分支策略也变得非常简单:branches开发,master发布,tags存档。大家可以在此分支策略基础上做任意变种,满足各个事业部不同开发人员的工作习惯。

在出租车模式发布的各个环境里,使用了在敏捷阶段介绍的deploy,每个环境推送,都必须指定一个deploy,这个deploy必须和你推送的项目工程有关:
14.jpg

图14 发布流水线研发流程控制关联

deploy必须到了某个阶段,才能推送对应环境,而deploy的每个阶段都有准出检查。

这就像一条河,河上有几个坝,每一个坝都会拦截一部分河里的垃圾,那这条河的下游相对上游肯定是更清澈干净一些,最终汇入大海的水才会清澈,海水就是我们的生产环境。
15.jpg

图15 发布流水线一级视图

每一个节点(环境)又有各自的流水线,各节点下的流水线:
16.jpg

图16 发布流水线二级视图

所以我们的流水线是二级流水线:第一级流水线对应我们的五大环境(测试环境用户可以自定义环境名称,所以又有子环境的概念);第二级流水线对应各环境所需要的原子任务组合。

所有功能我们做成原子任务,包括校验类和执行类。每个节点(环境)可以自由组合需要的原子任务(必须的原子任务由后台控制,非必须的原子任务由用户自行选择是否添加)。

校验类:我们在执行任务之前,有很多校验(此类任务一般使用Java实现),包括前面提到的和敏捷关联的deploy的流程校验,以及安全扫描是否通过,配置中心是否配置,告警中心是否有对应告警等多达十几个校验项;

执行类:各种校验内容通过后,才进入到执行类任务,包括从GitLab拉代码,编译构建,上传制品库,发布到代码源服务器,Docker镜像制作,上传Harbor仓库,启动容器等,其中大部分功能是Jenkins来完成的。

为了保证流水线的高可用,设计了Jenkins的多Master + 多 Slave的架构,具体架构情况如下:
17.jpg

图17 流水线核心架构

因为Jenkins的权限机制无法满足公司业务需求,所以我们将Jenkins放在了后台,用户不能直接接触到Jenkins,而是使用DevOps作为用户入口进行调度。

DevOps集群随机调度到对应的Master上,当DevOps在创建Jenkins的Job的时候会在所有Master上面创建;当DevOps在触发Jenkins构建的时候会随机选择一个Master执行(当某个Master异常,DevOps不会调度到该Master,当Master恢复正常后,后台任务会自动将多个Master间的任务置为一致),Slave放在Kubernetes集群中,当Slave队列满的情况下可自动增加Slave节点(构建Docker镜像的节点仍然在虚拟机中)。

Jenkins上的任务首先以项目工程为单位建立folder,再在folder下建立对应的执行类任务。我们没有使用Jenkins的Pipeline的原因,就是因为Pipeline统一维护困难,且没有层级划分。Jenkins在面向企业级方面还需要提供更丰富的功能。

每日构建次数:每日构建次数包括所有环境的发布次数,平均每日大概在1500次左右。
18.jpg

图18 每日构建次数

每日上线次数:每次上线次数为项目发布到生产环境的次数,平均每日大概100次左右,同时支持hotfix发布,随时回滚等。
19.jpg

图19 每日上线次数

组件库

因为我们开发语言的原因,所以不同开发语言有对应的组件仓库,这在前面的发布API里面已经讲过,主要是Java的Nexus仓库、PHP的PPKG仓库、Node.js的NPM仓库,这里就不重复了

制品库

制品库分两种,虚拟机和Docker发布,其中虚拟机发布的我们直接将编译构建好的内容保存起来,供推送其他环境时可直接使用,达到一次构建,处处运行的目的(和环境有关的配置统一放在配置中心,每次发布前通过校验类流水线任务,校验完成配置后方可发布)。

Docker的是直接构建成镜像,上传到Harbor镜像仓库,在触发Kubernetes容器集群启动容器时从镜像仓库获取镜像启动。

虚拟机发布

虚拟机发布是使用Rsync服务进行文件同步,将代码从制品库同步到对应服务器,然后服务器上有一个守护进程,会实时监测文件是否更新,若有代码更新则进行重启操作。
20.jpg

图20 发布流水线之 虚拟机发布

Docker发布

Docker发布是调用Kubernetes进行发布,将事先生成好的yml文件传递给Kubernetes,然后在对应数据中心启动容器,并通过zbjcheck服务校验功能确保服务启动正常后,再删除老的容器,达到不停机升级的目的。

自动化测试

目前DevOps集成了单元测试(包括自动生成单元测试用例)、接口测试、性能测试的功能。单元测试大部分情况下还是需要开发人员写用例,自动生成单元测试用例的功能并不是那么好用,所以用户较少,但在流水线上会自动进行单元测试,并将结果反馈给用户:
21.jpg

图21 自动化测试之单元测试

单测结果是基于Sonar的,在Jenkins上执行完单测后连同静态检测结果一起发布到Sonar,在Sonar上配置了通用的过滤条件,可以过滤掉部分不需要统计单测的代码(如框架自动生成的代码不计入单测覆盖率),用户可以在此基础上配置其他过滤条件。

接口测试和性能测试方面,我们在DevOps平台上做了一个关联的功能,每一个接口测试或者性能测试用例,都对应一个项目工程,关联关系梳理好后可以实现在发布流水线的任意环节触发接口测试或者性能测试。

和项目工程关联:
22.jpg

图22 自动化测试之接口测试

发布流水线触发接口测试:
23.jpg

图23 接口测试与流水线集成

发布流水线触发性能测试:
24.jpg

图24 性能测试与流水线集成

自动化测试的结果展示方面目前做的不够好,只是在日志中提供链接,用户点击链接进去查看结果。

CMDB

CMDB作为底层的统一资源管理中心,负责跨数据中心的混合云管理,提供统一的资源管理平台,不管私有云还是公有云,不管虚拟机还是Docker都统一管理,同时提供对底层服务的访问支持。提供机器与宿主机的拓补图关系等,对基础设施的管理提供了便利。
25.jpg

图25 CMDB功能架构图

一套OpenStack表示一个虚拟化集群,一套Kubernetes表示一个容器云集群,每个数据中心有一套或多套OpenStack和Kubernetes。CMDB通过数据中心和可用区来标示不同的集群。任何需要和虚拟机和容器对接的功能统一由CMDB提供接口管理。

DNS解析

DNS作为附加的功能,可由用户直接点击一个按钮实现域名解析:
26.jpg

图26 域名解析示意图

域名解析是一个比较复杂的过程,它需要和后台很多系统交互,还需要根据事先定义好的Nginx模版生成配置,Docker的服务还需要进行动态服务发现,最终将域名信息注册到DNS中。

扩缩容

DevOps平台同时支持对虚拟机和Docker的扩缩容功能,只要对应数据中心存在对应的服务,就可以进行扩缩容,一次扩容节点不能超过10个,缩容节点数最少保留一个。
27.jpg

图27 弹性扩缩容功能图

我们能对不同数据中心的服务进行扩缩容,并且所有的操作都有事件机制,能将每个服务所使用的资源进行归档管理,最终可以对各个部门所使用的资源进行服务器成本费用结算。

控制台

从浏览器进入服务器,且通过权限控制,有权限人员才能进入,更加方便排查问题:
28.jpg

图28 进入控制台界面图

29.jpg

图29 进入控制台界面图

监控

DevOps已经集成了监控的部分功能,包括接口调用情况、全站可用性、监控数据排行榜、金丝雀分析等。

可用性监控

30.jpg

图30 网站全局可用性监控图

31.jpg

图31 网站分类可用性监控图

32.jpg

图32 网站可用性详情

监控数据排行榜

33.jpg

图33 服务监控排行榜

34.jpg

图34 接口级服务监控

35.jpg

图35 接口级服务监控

接口调用情况

36.jpg

图36 接口级服务调用监控

37.jpg

图37 接口级服务响应

金丝雀分析

金丝雀分析主要用于在代码发布到灰度环境时,分析灰度环境和线上环境的相关指标值对比,以确保新版本代码质量不必老版本差。
38.jpg

图38 金丝雀分析功能图

目前只有以下几个指标数据,后续将不断完善指标内容:
39.jpg

图39 金丝雀分析结果图

灰度环境和线上环境都承担用户流量,通过Nginx的Upstream进行权重设置,我们可以根据金丝雀结果做一次上线发布前的质量评估。

未完待续

虽然我们完成了DevOps的大部分功能,要讲到技术细节,上面的每一个小节都能用一篇文章来讲解,所以以后我们会不断分享我们在DevOps中的一些技术细节,当然我们也还有很多需要优化和改进的。需求搜集和规划、项目管理和发布关联、自动化测试、金丝雀分析的改进、自助作业平台、CMDB对混合云的管理等都是后续需要改进的,整体的规划图如下:
40.jpg

图40 DevOps平台功能架构分布

DevOps平台功能架构分布中,还有很多工具以及功能未描述,上面讲到的每一个点都可以展开为一篇文章做详细介绍,这里主要为2017年做一个总结。

以上内容为猪八戒网最近几年来整个DevOps的发展演进史,公司的规模不同,整体架构以及方法可能不同,对于猪八戒来说,DevOps还在继续演进,同时也会不断学习业界优秀实践,为业务发展提供最基础的保障。

原文链接:https://zhuanlan.zhihu.com/p/34670468

0 个评论

要回复文章请先登录注册