1 前言nginx
当代信息技术飞速发展,软件和系统的代码规模都变得愈来愈大,并且组件众多,依赖繁复,每次新版本的发布都仿佛是乘坐一次无座的绿皮车长途夜行,疲惫不堪。软件交付是一个复杂的工程,涉及到软件开发的各个细节,其中任何一环出现问题,都会致使软件不能及时交付,或者交付的质量堪忧。git
从企业的角度来说,如何利用更科学的工具、更科学的流程来提升产品质量,提高客户满意度,是刚需。从员工角度来说,生命里值得追求的事情不少,不能把宝贵的时间浪费在一些机械的、重复的事情上面。数据库
联想企业网盘从2007开始面向企业客户提供专业的云存储服务,10年来服务了250000+企业。软件的更新迭代司空见惯,联想企业网盘就是由成百上千台服务器组成的,是一个很是复杂的互联网应用,仅仅在服务端就有几十个模块协同工做,加上各类客户端,须要使用不一样的编译发布环境,有时候须要单独模块发布,有时候须要多个模块联合发布,使得每次的升级状况都很是复杂。曾经经历过一次大版本的升级迭代,运维和研发团队不眠不休的工做了40多个小时,既影响了用户的服务,也使得团队疲惫不堪。相似的经历,使得咱们思考如何经过技术革新来解决这一难题,可以把咱们的工程师们从简单劳动中解放出来,这样在将来面对更大规模的集群的时候,才可以游刃有余。服务器
缩短上线时间,提升上线准确度,是咱们建设这个系统的初衷。运维
2 问题分布式
先让咱们借用一张图(来源于 thoughtworks 官方文档)来回顾一下软件发布的一个完整的流程:模块化
整个过程当中,代码管理,集成和测试,发布上线是3个主要的环节。咱们全部的问题都集中在这3个环节当中。工具
一、代码管理post
代码管理混乱是一个研发团队的常见问题,研发的过程当中,代码的分支设计不合理,分支过多或者过少,分支依赖混乱,权限控制缺失,彻底靠人治,没有代码审核。单元测试
二、集成和测试
从研发环境到测试环境,都没有统一规范的部署环境,研发团队直接给测试出版本(野版本),由于编译环境,人员水平的差别会致使各类莫名其妙(有时候很低级)的问题,极大的影响了测试的效率和准确度。
三、上线交付
代码最终部署到生产环境的时候,须要运维人员和研发人员频繁手工操做,费时费力,还容易出错,整个过程不可重复且没有记录,回滚操做复杂,有时候甚至是没法回滚的,一旦是上线出现错误,对咱们用户的影响就是很是恶劣的。
3 实践
多年来,咱们在研发过程当中不断总结,想了不少的办法,在服务客户的同时积累了大量的生产环境运维经验,开发了许多工具和流程,来解决升级和产品上线的问题。,下面基于联想企业网盘的生产实践,分享一些咱们在建设持续交付系统方面的方法。
以下图所示,咱们主要讨论这几个方面:
3.1 代码管理
代码是软件交付过程的源头,因此合理的规划与管理尤其重要。
3.1.1 代码仓库
早期,咱们全部研发人员的代码都存放在一个 SVN 库里,分支和 Tag 散布在各个模块的子目录里。SVN 是很好的一个工具,可是太灵活了,要你们严格遵照纪律,可是更多时候要靠你们自觉,可是人老是会有松懈的时候。一旦有人不守纪律,对于后来者就是一个苦不堪言过程。
因此咱们的第一步,就是把 SVN 迁移至 Git。按照模块拆分为单独的库,每一个模块单独受权,统一分支模型。仓库软件用的 Gerrit,它本来是代码审核工具,拥有强大的权限管理系统,Git 仓库只是附带的功能。
其实在从SVN迁移到Git的时候,有不少工程师会有疑问,为何迁移到 Git?不是 SVN 很差,也不是为了追逐技术潮流,而是后面的自动化工做(包括代码审核工具)用 Git 更方便,固然 Git 强大的分支功能以及分布式也是一个重要缘由。
3.1.2 分支设计
分支咱们参考比较常见的一个 Git 分支模型(参考连接),针对咱们本身的需求作了一些调整,以下图:
一、 设计两条主分支,dev 和 master,dev 是开发分支,master 是对外的稳定分支,持续交付系统会从master分支拉取代码进行构建;
二、 辅助分支只使用 feature 分支和 hotfix 分支,feature 分支原则上是尽可能不建,只用于开发周期比较长的新功能开发,短平快的 feature 都直接提交至 dev。
3.1.3 审核
代码是产品质量的源头,代码质量不行,其余再多辅助手段都没用。代码审核是保证代码质量相当重要的一环。只要团队人员数大于一个就应该推行代码审核。
代码审核有两种模式:
l 集成前审核(pre review)
顾名思义,在代码合并至目标分支前进行代码审核,有问题改,改完再继续审核,审核经过则集成进目标分支,这一类审核的表明工具软件有:Github,Gerrit,其中 Github 是以分支为单位进行审核,Gerrit 以提交为单位进行审核。
l 集成后审核(post review)
先合并代码,而后进行审核,有问题只能用新的提交来修复了,这一类审核的表明工具软件(其实这两款软件也支持 pre review):reviewboard,phabricator。此种方式容易致使目标分支不稳定,因此通常不建议。
咱们采用的是第一种集成前审核的方式,工具软件用的 Gerrit,以提交为单位,强制审核事后再合并至目标分支(固然这个过程是自动的)。
好了,话很少说,有图有真相,下图是咱们的代码提交工做流:
图中黄色的部分便是代码审核的部分,每一个提交须要通过其余人审核(Code Review +2)和持续集成系统验证过(Verify +1)才能合并至目标分支。
代码审核页面:
3.2 构建部署
在这里我简单的将构建部署分为持续集成和部署流水线,实际上,这两块不少地方有重合,这里的持续集成仅仅只讨论构建验证和自动集成,部署流水线包括从构建到部署至不一样环境的整个过程。
3.2.1 持续集成
持续集成是一个大的议题,是敏捷开发的一项核心实践。在持续交付过程中,持续集成将从开发到部署的各个环节组成一条流水线,是整个交付过程的核心。重点是要快速反馈,在集成代码以前迅速发现问题并改正。
咱们把单元测试、编译验证、静态扫描和覆盖率检测分离出来(这一步骤的时间控制在 5分钟内,这也是前面为何要把库拆分的缘由之一),在研发人员提交代码后当即触发构建,在5分钟内把结果反馈给研发人员,继而快速修复错误,直至验证经过。
咱们采用的工具软件是 Jenkins,最流行的持续集成软件,经过插件支持 Gerrit,功能很是强大。
在实际的实施过程中,要求每一个模块都要提供在一个干净环境执行编译、单元测试等等步骤的脚本或方法,构建环境能够经过 Vagrant 或者 Docker 来自动配置,咱们内部采用了Docker 技术来隔离各个构建环境。
流水线
3.2.2 部署流水线
顾名思义,这一步骤就是把打包好的软件部署到不一样的运行环境,而且要自动处理各个环境的配置(例如域名、数据库信息、登陆信息等等),此步骤严重依赖于前面步骤的实现,仓库的规划、分支的规划、持续集成的流水线构建等等。
一个典型的部署流水线
在构建部署流水线的时候,咱们要遵循几个原则:
一、 过程可重复;
二、 一次构建多地部署;
三、 模块化部署;
四、 变动管理;
五、 审计功能;
六、 快速回滚。
在选择部署工具方面,咱们考察过两个:thoughtworks go 和 Jenkins(插件 Delivery Pipeline)。
Go 系统自带管道,可是灵活性不如 Jenkins;Jenkins 的一个好处是咱们的持续集成都在 Jenkins 里实现,不少脚本均可以复用,甚至不少任务都能直接复用,缺点是管道各任务之间数据共享比较繁琐,须要额外的插件(例如 Copy Artifact),因此实现的不是很天然。
在实际的实施过程中,可以彻底实现自动化(无人值守发布)是一种理想状态,但实践当中老是会受各类因素制约,因此必要时也必须向现实低头。咱们最终实现了一键部署加关键环境(例如生产环境)手工触发(下面图中的播放小箭头就是这样的步骤)相结合的流程,参见下图:
在实施过程中,配置文件的管理也是很重要的一个议题。配置文件主要分为两类:
一、 配置文件与运行程序不能分离,像J2EE这样的应用,配置文件与编译成果物打包成一个 war 文件,咱们的处理方法是把敏感信息(例如数据库信息)存放在其余的Git 库,构建的时候针对不一样环境分别构建,构建时由Jenkins 自动记录代码的版本和配置文件的版本;
二、 配置文件与运行程序能够分离,相似于 nginx 这样,咱们把程序打包成 rpm 或者 deb ,配置文件存放在 puppet 主服务器上,每次部署都触发 puppet 的自动分发。
在持续交付流程中,咱们能够清楚的知道当前每一个环节,每一个节点都处在一个什么版本状态,这对于清晰的了解,快速回滚很是有用。参见下图,某项目部分模块不一样环境版本信息(请忽略页面丑陋这个细节,红色即表示某个模块正在发布,还没最终上线):
@IT薄荷叶:4 尾声 目前联想企业网盘的服务已经全面采用流程化的上线交付体系,从研发环境到测试环境到生产环境,所有是流水线做业,保证了各个模块间代码和版本的一致性,表明的集成、发布只须要咱们轻点一下鼠标,而后就能够喝着茶耐心等待收到发布成功的邮件了。 持续交付是一个长期的须要不断完善的过程,公司的策略在变,产品需求在变,人在变,流程也在变,咱们所作的仅仅是开始,还须要继续去摸索,磨合,打造出更为完善的交付系统。这是一个任何软件开发团队都须要重点考虑的事情,创建规范,制定流程,利用科学的工具来实践规范和流程,脱离小做坊式的交付模式,按时按质按量交付产品。 (1小时前)
http://www.oschina.net/question/2448759_2186294