从开发者的角度看:打包和部署

b2f5 9年前

如今的互联网软件越来越碎片化(micro services),Queue无处不在,服务依赖越来越多,使得软件功能的开发,到软件功能的部署,中间有很长的一段路。这段路,是持续集成(Continuous Integration)和持续发布(Continous Delivery)的基石,一般由devOps包圆了,对从不涉身其中的dev而言,看上去就像ops们用了黑魔法,设了道传送门一样,让写好的代码 biu的一下就变成了运行在浏览器,或者手机上的鲜活页面。本着不懂点devOps的dev不是好pm的态度,本文简单讲讲软件发布过程中的两个黑魔法:打包(packaging)和部署(deploying)。

我们先看「打包」。

打包


打包字面上的理解是把你的应用和其依赖的组件组织在一起,以便于分发到目标系统上。客户端软件的时代,如office 97烧录成一个iso(便于刻在光盘上)就是个典型的打包的过程;互联网时代,一个java项目生成 jar,python项目生成 wheel/egg,也是打包的过程。

打包的意义在于制作可以重复使用的软件。所有琐碎的活儿都在打包的时候完成了,而在要部署的目标系统上,无需使用源代码,无需处理依赖,无需编译,只要把打包好的软件「安装」好即可。我们知道,在计算机领域,合格的程序员倾向于消除一切重复的工作。打包的过程,实际上是一系列手工操作的合集,因此必然有相应的工具来帮助提高打包的效率。

打包软件的元老级人物应该是 make。这个常常伴随C/C++项目的任务管理工具的一大主要用途就是打包。当然,make 接近于 *nix shell 的语法并非人见人爱,于是各个语言都提供语言本身的任务管理工具,如grunt,rake。

简单的应用,打包的过程可以很快,因为只需应用本身的编译和依赖处理,秒级就可以完成;但复杂的应用可能需要数个钟头。比如说,一个嵌入式软件需要用 buildroot 把 OS,dependencies 及应用软件深度整合在一个可以直接烧录在硬件的 firmware 里,其 full build 可能需要几个小时。另外一个例子是一个复杂的系统可能会使用 ansible/puppet/chef 这样的工具将多个代码库的不同部分装进不同的 aws ec2 instances 中,安装依赖,配置系统时钟,配置 nginx,supervisor 等等服务,然后把这些 instances 制作成一个个 AMI(Amazon Machine Images),供日后部署之用。这往往也需要耗费半个小时到几个小时的时间。

打包的过程中,包括之后部署的过程中,还需要一样东西:资源管理工具。因为,就像 micro service 需要 consul 这样的工具提供服务发现,docker 需要 docker registry 提供 repository 一样,打包好的软件需要一个合适的地方放置,便于版本管理,部署以及可能的回退。

这个工具可以是S3,可以是自行开发的 repository,也可以用开源的 archiva 或 artifactory。后两者做java的同学应该有所耳闻。这样的资源管理工具有什么用?以python为例,如果你的软件会打包出很多私有的 egg/wheel 包,这些包无法被公开放置在 pypi 上,那么你可以用 artifactory(或achiva)取代 pypi,成为你 pip install 的 index server。artifactory 上没有的包(公共包)会自动去 pypi 上取。同样的,debian 的 index server,docker 的 registry 都可以用这样的工具构建。

部署


不少人把「打包」和「部署」两件事混在一起,是因为二者经常在一起执行:打包之后,不待喘息,就立刻部署。但部署的动作其实是独立的,一份打包好的软件,按使用场景,可能会有多种部署。互联网软件的部署,往往是相当复杂的,光线上环境而言,就有开发环境,测试环境,以及生产环境。这还不算生产环境中可能存在的各种版本(提供外部API的同学应该心有戚戚焉),所以,部署往往是比打包更让人头疼的事情。

我们举个具体的例子:一个线上的日程系统,运行在 aws 里,主要使用 dynamodb,elasticache,ec2 和 s3。开发环境无需考虑 scaling,以单台服务器承载所有服务,没有 ELB / auto-scaling,数据是线上数据的子集;测试环境有 ELB,服务分布在不同的EC2上,每种服务都有两台服务器做HA,但没有 auto-scaling;线上服务则有 ELB / auto-scaling。

一个新功能的开发和集成的过程中,开发环境可能会被部署多次;当集成完成后,系统会被部署到生产测试环境;而测试结束后,系统可以以蓝绿发布(blue green deployment)的方式部署到生产环境;或者,选取一定样本的用户做灰度发布(gated launch 或者 A/B test)。

在aws的世界里,部署的主要工具是 cloudformation / elastic beanstalk,因为在打包的过程中,已经通过 ansible/puppet/chef/docker 等生成好了 AMI 或者 docker image;在非aws的世界里,ansible等工具也被用于部署。

如之前例子所示,部署主要是做资源的调配。开发环境毋须消耗太多资源,所以分配少一些;生产环境是现金奶牛,必须保证资源的全力供应。

当然,部署并不单单是资源的调配,它还是服务的 ochestration(嗯,这词比较高大上)。拿 logging 为例,如何把分散在各个服务器上的日志集中起来用于查询和分析,就是部署的一项任务。

蓝绿发布的思想其实比较简单,就是提供两套一样的生产环境(production / staging),通过DNS对流量进行切换。如下图:

(图片来自:BlueGreenDeployment

当 staging 足够稳定时,可以通过DNS切换,把流量从 production 转入 staging。待稳定后,staging 变为 production,原有的 production 转为 staging,可以被 shutdown,也可以被用于下一个 release。如果使用AWS,可以通过 route53 进行 DNS redirection,或者 ELB 的 auto-scaling group进行蓝绿发布。

蓝绿发布的好处是一旦发现问题,可以迅速回滚。

灰度发布在王淮的《打造非死book》一书中有介绍:基本思想就是发布的时候控制发布的人群及其比例。比如先1%的用户,再扩大到5%,直至100%。人群可以根据多种属性来筛选,如:年龄、性别、国家、城市、语言、学历、工作单位等。

灰度发布的缺点是如果系统有不可逆的更改,则不能使用;对蓝绿发布而言,可以使用,但是系统不能回滚。

关于打包和发布的基础知识,就讲这么些。真正操作起来还是挺复杂的。就拿部署的速度而言,就有很多学问:层层缓存,最小化任务集合,对 full build 和 incremental build 采取不同的优化方式等。有同学可能会有疑问:如果打包和部署都已经自动化了,速度快一点,慢一点又有什么影响?殊不知以互联网的速度,如果你做一次部署要两小时,人家只需要五分钟,那么一天八小时内,你能部署四次,人家最多可以部署九十六次。效率提升差出来一到两个量级后,对开发人员的效率而言,会产生质的变化。

来自:http://zhuanlan.zhihu.com/prattle/20062049