卷2:第2章 Firefox发布工程

原文链接:http://www.aosabook.org/en/cmake.html

作者:Chris AtLee, Lukas Blakk, John O'Duinn, Armen Zambrano Gasparian

最近,Mozilla发布工程组在Firefox的发布自动化方面取得了非常多的进步。我们已经减少了在签字和发送通知时对人工参与的要求,并且自动化了许多其它的小的手工步骤,因为流程中每个手工步骤都可能犯错。尽管仍不算完美,我们始终在尽最大努力自动化发布过程,最终目标是真正的一键式发布;最小化人工干预将会消除我们在之前那种半人工半自动化的发布过程中所经历过的重复劳动和许多令人头疼的事情。在本章,我们将带着你走入并领略构成完整的Firefox快速发布系统的脚本和架构的世界(到Firefox 10为止)。

你将会看到一个可发布的Mercurial变更集是如何成为候选发布,进而成为公开发布的,此时就对全世界每日高达4亿5千多万的用户完全开放了。我们将会从构建和代码签名开始,接下来是定制的合作伙伴和本地化重打包,QA过程,以及如何为每个支持的版本、平台和本地化生成更新。每一个步骤都必须正确的完成,一个发布才可以被推送到Mozilla社区的镜像网络上供用户下载。

我们将会看到一些旨在改善此流程的决定;例如,健康检查脚本,帮助消除了许多人工错误导致的问题;自动签名脚本;移动发布集成到桌面发布流程;补丁程序,用来创建更新;以及应用更新服务(AUS - Application Update Service),将更新发送给使用着各种不同版本的用户。

本章描述了如何产生Firefox发布构建的机制,大部分篇幅都在讲解一次构建开始后发布流程的各个关键步骤。但是,在发布工程开始产生发布构建之前,还需要做足够的复杂的跨团队沟通。因此,我们就从这里开始吧。

2.1 在开始一个发布之前的N个工作

enter image description here

图2.1 从代码到“go to build”

在启动Mozilla发布过程改进项目之初,我们就有这样的假设:Firefox变得越普及,用户就会越多,就会越成为黑帽子黑客寻找安全漏洞进行攻击的目标;同样的,我们就必须保护更多的用户免受新漏洞的影响,因此,有能力尽快交付一个安全修复就变得更加的重要。我们为此专门发明了一个词叫:chemspill发布(化学泄漏chemical spill的缩写)。与其被常规发布之间偶尔的chemspill发布弄个措手不及,不如能设计出一种发布自动化机制,能支持每个发布都是chemspill发布。

这种思路带来三个重要的结果:

  1. 我们在每个发布之后进行一次事后分析,看是否存在改进的空间:有什么事情可以变得更加平顺、更容易、更快。即使再小的改进,我们也会在下一个发布之前立即实施。这种对发布自动化的持续优化意味着我们总是在寻找新的方法来减少对人工干预的依赖,以及在鲁棒性和周转时间上的改善。大量的工作花在了加强工具和流程使之严丝合缝毫无破绽上,能够尽快的捕获和处理类似网络断续、硬盘空间问题、人工拼写错误这样的“罕见”事件。虽然处理常规的、非chemspill发布已经够快了,我们仍然想减少未来发布中可能遇到的任何人工错误的风险。在chemspill发布中尤其如此。

  2. 当我们真的面临一个chemspill发布时,发布自动化越鲁棒,发布工程中大家的压力就越小。我们已经习惯了从容不迫而又精准的快速发布,通过开发一系列工具使得这一过程尽可能的安全和鲁棒。小的压力意味着在一个良好预演的流程里更从容不迫和精准地工作,这有助于chemspill发布更加的平稳。

  3. 我们在整个Mozilla范围内建立了一个 “go to build”流程。在一个常规的非chemspill发布中,让每个人查看同样的bug类选(triage)查询,看到最后一个修复生效并测试成功,一致同意何时开始构建是没有问题的。但是对一个chemspill发布,时间紧迫,争分夺秒,跟踪一个问题的所有细节、所有的bug确认和修复变得很复杂、很紧张。为了降低复杂度和出错的风险,现在Mozilla有一个全职人员负责跟踪代码是否准备就绪进入构建过程。在一个chemspill中改变流程是危险的,因此为了保证每个人即使在时间紧迫的情况下对流程也都很熟悉,chemspill发布和常规发布使用同一个流程。

enter image description here

图2.2:完整的发布时间线,以chemspill为例

2.2. 进入构建

谁来决定进入构建

在发布开始之前,一个人被指定负责协调整个发布过程。他/她需要参加类选会议、理解所有项目背景、公平的仲裁bug严重性上的争议、批准最新的变更、做出艰难的放弃决定等等。最后,在发布日,这个角色在现场负责与各个团队的所有沟通:开发、QA、发布工程、网站开发、公共关系、市场等等。

这个角色在不同的公司有不同的称呼:发布经理、发布工程师、Program Manager、项目经理、产品经理、产品沙皇、发布舵手等等。本章将使用“发布协调员”这一称谓,因为我们觉得这个词最清楚的表达了该角色在我们的流程里起的作用。重点在于这个角色及其代表的最终权威能够被每个人所清楚的理解,无论其背景或之前在其它地方的工作经历。在发布日,每个人都知道自己应该遵守和信任这个角色所做出的协调决定。

发布协调员也是发布工程之外唯一一个有权在重大问题出现后发出“停止构建”邮件的人。任何疑似重大问题报告也会被发送到发布协调员,由他/她来评估及做出go/no-go的决定,并及时的将此决定周知到每个人。在发布日,我们所有人必须遵守和信任这个角色所作出的协调决定。

如何发出“进入构建”信号?

早先通过IRC或者电话口头的通知带来了很多误解,时常给进行中的发布造成问题。因此,我们现在要求“go to build”信号通过电子邮件发送到一个包含了与发布过程相关的所有团队的每个人的邮件列表。邮件标题包含“go to build”加上产品名及版本号,例如:go to build Firefox 6.0.1。

类似的,如果出现了问题,发布协调员会发送一个新的“all stop”邮件给同样的邮件列表。我们发现另外一种做法——回复该发布的最新的邮件——是不行的,因为一些客户端的邮件会话功能会造成一些人注意不到藏的很深的“all stop”邮件。

在“Go to Build”邮件里有些什么?

  1. 构建的代码;理想情况下,是指向要生成发布构建的源码库里的特定变更的URL。

a) 类似“使用最新代码”这样的指令是绝对不行的;曾经有一个发布,在“go to build”邮件发出之后而构建开始之前,一个好心的开发未经批准提交了一个变更到一个错误的分支,导致发布将此变更包括在构建中。幸好这个错误在交付之前被发现了,但是,我们因而完全终止、全部重新构建,并推迟了发布。

b) 在象CVS这样的基于时间的版本控制系统里,要十分明确的使用准确的时间;精确到秒,并指定时区。曾经有一个发布,在Firefox还使用CVS的时候,发布协调员指定了一个构建的截至时间但是未说明时区。当发布工程注意到缺失时区信息时,发布协调员睡着了。发布工程正确的猜想应该是本地时间(加利福尼亚)。然而,在一次深夜的发布中,我们将PST看作了PDT,结果丢了最后一个关键的bug修复。这个错误在交付之前被QA发现了,但是我们不得不停止并使用新的截至时间重新构建。

2.对于特定发布的清晰的紧迫感。听起来显而易见,但在处理一些重要的特例时非常重要,简单总结如下:

a) 一些发布是例行的,可以在正常工作时间完成。这些都是预先安排的发布,也会按时完成,不存在紧急性。当然,所有发布的构建都需要及时的创建,只是不需要发布工程师熬夜赶工去完成。我们会事先做好安排,人们只需要在正常上班时间工作就可保证每件事情都按时完成。这将保持大家的体力,以便更好的应对那些意料之外的紧急工作。

b) 一些发布属于chemspill这样紧急性的,需要争分夺秒。典型的例子包括修复公开的安全漏洞,或者修复影响大量用户的崩溃性问题。Chemspills需要被尽快创建,而不是按预先的安排。

c) 一些发布在例行和chemspill之间转换。例如,当一个例行发布的安全修复意外的泄漏了,就变成了一个chemspill发布。当一个业务需求如给即将到来的一次会议公告准备的“特供预览”发布,由于商务原因被延迟时,就从chemspill发布变为例行发布。

d) 一些发布的性质存在争议,因为对相同的修复存在不同角度的理解。

正是发布协调员这个角色,负责平衡所有这些事实和观点,达成决定,并将有关紧迫性的决定清楚一致的周知到所有团队。一旦有新的信息,发布协调员会重新评估和周知。一些团队认为一个发布是chemspill而另外的团队认为是例行的,这种情形对跨团队的合作是非常有害的。

最后,这些邮件对于度量一次发布中的时间分配非常有用。尽管它们的准确度不会超过挂钟的时间粒度,但对于我们判断下一步应该把工作集中在哪里以加快速度来说已经是非常有用的了。正如古老的格言所说,先有度量,才能改进。

在Firefox的beta周期里,我们也在做mozilla-beta库的周发布。每个这样的beta发布都要经过我们通常的完整的发布自动化,与常规的最终发布几乎一模一样。为了最小化意外,发布自动化流程或底层架构在开始最终发布构建之前不能有任何未经测试的变化。

2.3. 打标签,构建,源码压缩包

enter image description here

图2.3:自动化打标签

我们最近开始使用一个脚本release_sanity.py为启动自动化做准备,这个脚本最初是发布工程的一个夏季实习生写的,能辅助发布工程师复核所有的配置与检入工具和配置库的内容相一致,还会检查mozilla-release特定发布的代码修订里的内容,以及用来生成构建和语言包的所有语言。

这个脚本的输入包括要使用的发布配置的buildbot config文件、要检查的分支(例如mozilla-release)、构建及其版本号,以及要构建的产品名(例如fennec或firefox)。如果发布库与配置内容不一致,或者语言库变更集与交付地区和本地化变更集文件不一致,或者发布版本号和构建号与构建工具得到的从产品、版本、构建号生成的标签不一致,脚本就会失败。当脚本里的所有测试都通过以后,就会重新配置运行该脚本的buildbot master,触发发布构建器,生成“send change”信号,启动自动化发布过程。

在发布工程师启动构建器之后,Firefox发布过程的第一个自动化步骤是对相关的源代码库打标记,记录该版本和构建号的候选发布所使用的源码、语言库和相关工具的修订。这些标记使我们得以在发布库里保留Firefox和Fennec(移动版的Firefox)发布的各种版本和构建号的历史。Firefox发布的一个标记的例子:FIREFOX_10_0_RELEASE FIREFOX_10_0_BUILD1 FENNEC_10_0_RELEASE FENNEC_10_0_BUILD1。

Firefox的一次发布使用来自大约85个版本控制库的代码,这些库包含着产品代码、本地化串、发布自动化代码和辅助性部件等。对所有这些库打标记,是为了保证发布自动化接下来的步骤使用相同的修订,同时还有很多其它好处:Linux发行版及其它贡献者能够用完全相同的代码和工具重新产生这些构建,并且支持将来做多个发布内容的比较。一旦所有的库都建好了分支并打了标记,一系列相关联的构建器自动启动:每个发布平台一个构建器,再加上一个包含该发布所用源代码的源码包。源码包及构建安装程序都被上传到发布目录。这使得任何人都能看到发布中的确切代码,并能在需要时用这个快照重新产生构建,例如,当VCS失败的时候。对Firefox的构建源代码来说,有时会需要从一个更早期的库中导入代码。例如,就beta发布而言,这意味着从Mozilla-Aurora中取得签署的修订,如Firefox10.0.b1。对一个发布而言,这意味着从Mozilla-Beta(一般是与10.0b6相同的代码)取得批准的变更放到Mozilla-Release库里。这个发布分支接着就被创建作为一个命名分支,其父变更集设置为发布协调员提供的“go to build”邮件中指明的签署的修订。此发布分支可被用于对源代码做发布相关的修改,例如校正版本号或者最终确定要构建的语言信息。如果将来发现了一个需要立即修复的重大的安全漏洞——一个chemspill——一个最小变更将会在此分支上发生,随后产生一个新版本的Firefox。当必须得为一个特定的发布做另一轮的构建时,buildN,我们可以从这些分支得到相同的代码,它们是被签署允许“go to build”的,也是任何对此发布代码的变更发生的地方。自动化流程再次启动并校正标签到该分支的新变更集上。标记流程对本地和远程的Mercurial库完成很多操作,为了能够自动完成一些最常用的操作,我们写了几个辅助工具:retry.py和hgtool.py。retry.py是一个简单的封装,能够运行一个给定的命令,在失败时重试几次;还可以捕获例外输出然后重试或者报告错误。我们发现将最常用的由于外部依赖可能出错的命令封装到retry.py里非常的有用。就标记而言,Mercurial操作会由于临时性的网络故障、web服务器问题或者后台Mercurial服务器短暂的超载而失败。能够自动重试这些操作然后继续得以节省大量的时间,因为我们不必进行人工恢复、清理然后再次启动发布自动化。Hgtool.py是一个封装了几种常用的Mercurial操作的小工具,如使用单次调用进行的克隆、拉取和更新。它还支持Mercurial的共享扩展,这个功能使用得非常频繁以避免在同一机器上把相同的库克隆多份。增加对共享的本地库的支持极大的加速了我们的标记流程,因为避免了大多数的对产品和语言库的完全克隆。开发类似工具的一个重要的动机是使我们的自动化尽可能的可测试。因为类似hgtool.py这样的工具是很小且功能单一的,用可复用的库开发,非常易于单独测试。

今天,我们的标记在两个并行的作业中完成:一个是桌面Firefox的,花费20分钟左右,包括了对80+语言库的标记;另一个是移动Firefox的,花费大概10分钟,因为现在移动发布的语言还比较少。我们计划将来进一步优化发布自动化流程,做到并行标记所有的库。初始的构建可以在产品代码和工具需求库标记完成之后立即启动,不必等待语言库的标记。到这些构建结束时,其余的库将会完成标记然后本地化打包和接下来的步骤就可以进行了。我们预计这将把构建完成的总时间减少15分钟。

2.4. 本地化重打包和合作伙伴重打包

一旦桌面构建生成并被上传到ftp.mozilla.org以后,自动化流程就会触发本地化再打包工作。一次本地化再打包将原来的构建解压、将en-US字符串替换成在此发布里要使用的另外一种语言,然后重新把所有的文件打包,这就是叫做重打包的原因。对该发布中的每一种语言重复此过程。开始的时候,所有的重打包都是串行的。然而,当语言越来越多时,这将会花费很长的时间,而且一旦出错必须从头重启。

enter image description here

图2.4: 对每一个语言进行Firefox重打包

现在,我们将整个repacks分成六个作业,放在六台不同的机器上并行执行。这种方法将时间减少到了原来的六分之一。这也使得我们可以在个别repack失败时重做一部分作业,而不是全部。我们可以将repacks分成更多、更小的并行的作业,但发现这将会占用太多的机器,进而影响到在持续集成系统上运行的由开发启动的无关作业。

移动发布(Andoid)流程稍有不同,因为我们仅产生两个安装包:一个英语版的,一个多语言版的将一打语言一块放进安装包里而不是每个独立的构建放一个。多语言版本的大小是一个问题,尤其是对移动设备的慢速下载而言。可能的一个改进是其它语言按需请求并从addons.mozilla.org取得。

在图2.4里,可以看到语言信息依赖三个不同的源:shipped_locales,l10_changesets 和 l10n-changesets_mobile-release.json。(计划合并成一个统一的JSON文件)这些文件包含不同本地化的信息以及某些平台例外。特别的,对于某个给定的本地化,我们需要知道对于给定的发布使用库的哪个修订,以及是否它可以用于所有支持的平台(例如,Mac上的日语来自于一个不同的库)。Desktop发布有两个这种文件,而移动发布有一个(此JSON文件包含平台列表和变更集)。

谁来决定发布哪种语言呢?首先,本地化负责人自己提名特定的变更集,然后由Mozilla的本地化小组评审,显示在一个web仪表盘里,其中列出了每种语言需要的变更集。发布协调员也会在发出“go to build”邮件前进行评审。发布的时候就可以获取变更集列表,加入到重打包中。

除了本地化重打包以为,我们还进行合作伙伴重打包。这是为希望定制其客户体验的各个合作伙伴而当定制的构建。主要的变化是定制的书签、主页和搜索引擎,但是很多其它的事情也可以被改变。这些定制的构建是为最新的Firefox发布生成的,不适用于beta版。

2.5. 签名

为了让用户肯定他们下载的Firefox是真实的来自Mozilla且未经篡改的版本,我们使用了几种不同类型的数字签名。

第一种签名用于Windows版本,我们使用了Microsoft Authenticode(signcode)签名键去签署.exe和.dll文件。Windows可以使用这些签名来验证应用来自可信赖源。我们还用Authenticode键对Firefox的安装程序进行的签名。

接下来我们使用GPG为所有平台上的所有版本生成一系列MD5和SHA1校验和,为校验和文件及所有构建和安装程序生成分割的GPG签名。这些签名供镜像网站及其它社区成员进行下载验证。

出于安全目的,我们有一个专门的通过防火墙和VPN与外部链接隔离的签名机器。Keyphrases, password和keystores通过安全通道在发布工程师间传送,经常是亲自取送,以最小化泄漏的风险。

enter image description here

图2.5:签名Firefox安装程序

直到最近这个签名过程还需要一个发布工程师在一个专用服务器(称为signing master)上,用接近一个小时手工的下载构建、签名然后回传到 ftp.mozilla.org,然后自动化才能继续。一旦签名完成及所有文件上传,一个记录所有签名活动的日志文件就会被上传到 ftp.mozilla.org上候选发布的目录。ftp.mozilla.org上该日志文件的出现说明了人工签名的结束,从此开始,监视该日志文件的相关构建器就能继续自动化过程了。最近,我们增加了一个签名步骤自动化的封装程序,现在发布工程师在signing master上打开一个Cygwin shell,设置几个与发布有关的环境变量,象VERSION, BUILD, TAG, 和RELEASE_CONFIG,帮助脚本在ftp.mozilla.org上找到正确的目录并取得发布内容被下载的时间以便开始签名。在获得签名工具最新的生产版本之后,发布工程师只需要运行make autosign,然后输入两个密码短语,一个是gpg的,另一个是signcode的。一旦这些密码短语经过了make脚本的自动校验,就开始了一个下载循环:监控发布自动化流程上载的构建和repacks,一旦可用就下载它们。当所有内容都被下载之后,自动化流程就立即开始签名,无需人工干预。

无需人工干预有两个好处。第一,减少了人工犯错的风险。第二,使得签名可以在非工作时间完成,无需发布工程师待在现场。

所有产物都有一个MD5SUM和SHA1SUM,这些哈希值会被写入同名文件,然后被上传回候选发布所在的目录,同时也会被同步到该发布在ftp.mozilla.org上的最终位置,以便每个从某个镜像下载Firefox安装包的人可以确信其真实性。当所有签名的东西都可用且经过验证后,就与日志文件一起被传回ftp.mozilla.org,而正在等待之中的自动化流程就可以继续执行了。

计划中对签名流程的下一轮改进,是写一个在构建/重打包的同时进行签名的工具。这包括编写一个签名服务器应用来接收来自发布构建机器的签名文件的请求,以及一个签名客户端工具,负责联系签名服务器,完成合法性认证,才能发送签名请求、上载文件、等待构建签名完毕然后下载并将其作为打包的构建的一部分。一旦这些增强上线,就可以放弃现有的整体式的签名流程和整体式的生成-更新流程(后详)了。这将会减少几个小时的发布时间。

2.6. 更新

通过更新,用户可以使用浏览器内嵌的更新功能快速的、简单的升级到最新的Firefox版本而无需下载独立安装包。从用户角度看,更新包的下载都是在后台静悄悄的完成的。只有当更新文件下载到本地并准备好被应用以后,Firefox才会提醒用户应用更新并重启。

我们生成了大量的更新。对生产线上的一系列发布,我们会生成从所有支持的老版本到最新版本的更新。对FirefoxLATEST,来说,这意味着为LATEST-1, LATEST-2, LATEST-3, … 生成各个平台、各个语言、各个安装包的更新。同时为几个不同的生产线完成这些事情。

更新生成自动化修改每个发布的构建的更新配置文件,维护一个需要为哪些版本号、平台和语言创建更新的权威列表。更新以代码片段(snippets)的形式提供。在下面的例子里可以看到,这个小脚本不过是一个XML指针文件,位于我们的AUS上,通知用户的Firefox浏览器(完整的或部分的) .mar文件的位置。

主要更新 vs. 次要更新

<updates>
<update type="minor" version="7.0.1" extensionVersion="7.0.1"
          buildID="20110928134238"
          detailsURL="https://www.mozilla.com/en-US/firefox/7.0.1/releasenotes/">
<patch type="complete"
       URL="http://download.mozilla.org/?product=firefox-7.0.1-complete&os=osx&lang=en-US&force=1"
       hashFunction="SHA512"
         hashValue="7ecdbc110468b9b4627299794d793874436353dc36c80151550b08830f9d8c5afd7 940c51df9270d54e11fd99806f41368c0f88721fa17e01ea959144f473f9d"
       size="28680122"/>
<patch type="partial"
       URL="http://download.mozilla.org/?product=firefox-7.0.1-partial-6.0.2&os=osx&lang=en-US&force=1"
       hashFunction="SHA512"
       hashValue="e9bb49bee862c7a8000de6508d006edf29778b5dbede4deaf3cfa05c22521fc775da126f5057621960d327615b5186b27d75a378b00981394716e93fc5cca11a"
       size="10469801"/>
</update>
</updates>

图2.6:更新脚本示例

由图2.6可见,更新脚本有一个 type 属性,取值 major 或minor。次要的更新将软件升级到最新版本;例如将所有3.6.*的发布升级到最新的3.7发布,所有的快速发布beta用户升级到最新的beta,所有的Nightly用户升级到最新的Nightly版本,等等。大多数时候,更新是次要的,只需要用户确认并重启。

主要更新在我们需要向用户公告最新发布上线的时候采用,提醒他们“一个新版本的Firefox发布了,你想更新吗?”,并显示一个广告牌展示新版本的主要特性。我们的新快速发布系统意味着我们不再需要这么多的主要更新了;一旦3.6.*发布火车不再支持,我们将会停止产生主要更新。

完整更新 vs. 部分更新

构建产生完整更新.mar文件,包含新版本的所有文件,用bz2压缩然后打包成一个.mar文件。无论是完整更新还是部分更新,都会通过用户的Firefox注册的更新通道自动下载。有不同的更新通道(即,发布用户在发布通道上寻找更新,beta用户在beta通道上寻找,等等),以便在不同的时间服务发布用户和beta用户(一个例子)。

部分更新.mar文件是通过比较新旧发布的完整的.mar文件产生的,只包括了有改动的文件的二进制差异,以及一个manifest文件。正如图2.6所示,部分更新文件更小一些。这对于那些慢速或拨号Internet用户非常重要。

在老版的更新自动化流程里,对所有语言和平台生成部分更新花费6到7个小时,包括完整的.mar文件的下载、比较和打包。最终我们发现,许多部件变化在不同平台上是一样的,因此很多差异可以被复用。通过使用一个缓存差异各部分哈希值的脚本,部分更新的创建时间被缩小到40分钟左右。

在更新文件被上传并部署到AUS上之后,运行一个更新验证步骤来a)测试下载该文件 b)用下载的.mar文件运行更新程序,确认更新被正确的应用了。

现在,部分更新.mar文件的生成和所有的更新文件都是在签名完成之后进行的。这样做的原因是,部分更新的生成依赖于两个发布版本的签名文件,因此更新文件的生成也必须等到签名的构建可用。一旦我们将签名集成到构建流程中去,我们就能够在完成一次构建或重打包后立即生成部分更新。再加上对AUS软件的改进,这意味着一旦我们完成了构建和重打包,就可以立即推送到镜像。这有效的并行化了所有更新的创建,从总时间里砍掉了几个小时。

2.7. 推送到内部镜像和QA

验证发布过程生成了预期的产出是非常关键的,这通过QA验证和签字过程来实现。

一旦签名的构建可用,QA就开始手工和自动化的测试。QA依赖于散布在世界各地的社区成员、合同工和正式员工来加速此验证过程。与此同时,我们的发布自动化产生所有受支持发布的所有语言和平台的更新。这些更新文件通常在QA结束验证签名的构建之前准备好。QA接着就可以验证用户能够安全的从各种老版本升级了。

从机制上看,我们的自动化流程会把二进制代码推送到内部镜像(Mozilla负责的服务器)上供QA来验证更新。只有在QA完成验证之后,才会推送到社区镜像上。这些社区镜像对于满足全球范围的用户流量是必须的,这些用户可以从本地镜像节点下载更新,而不是直接请求ftp.mozilla.org。值得指出的是,我们在QA签名之后才会将构建包和更新包放到社区镜像上,因为一旦QA在最后时刻发现了严重问题,候选构建必须被撤回。

构建和更新可用后的验证过如下:

  • QA与其它时区的社区和合同工一起,进行手工测试
  • QA触发自动化系统运行功能测试
  • QA独立的验证修改了的问题和新特性已经达到了可以交付给用户的足够好的质量
  • 同时,发布自动化生成更新
  • QA签字确认构建通过
  • QA签字确认更新通过

注意用户在QA签字确认以及发布协调员发出上线构建和更新的邮件之前是不会得到更新的。

2.8. 推送到公共镜像和AUS上

一旦发布协调员从QA和Mozilla其他各团队拿到了签字确认,就会通知发布工程师将文件推送到社区镜像网络上,处理接下来几天内高达几亿用户的更新下载请求。此时,所有的安装包以及所有平台和语言的完整或部分更新已经在内部镜像网络上了。推送文件到外部镜像涉及到为外部镜像模块修改一个rsync exclude文件,此修改导致镜像开始同步新发布的文件。每个镜像都有一个分值或者权重;我们监视哪个镜像已经完成了同步并加总各单独的分值计算出一个总的uptake分值。一旦达到某个uptake阈值,我们就会通知发布协调员镜像已经有了足够的uptake处理发布了。

此时这个发布就可以公开了。发布协调员会发送最终的“go live”邮件,而发布工程师会更新web服务器上的链接,这样web和ftp站点的来访用户就可以发现最新的版本了,同时还会在AUS上公布Firefox老版本所需的更新文件。

用户机器上的Firefox会定期的检查AUS服务器看是否有了更新版本。一旦我们发布了更新文件,用户就可以自动的升级到最新版本。

2.9. 教训

作为软件工程师,总是会情不自禁的解决自己认为紧迫和明显的技术问题。然而,发布工程师的工作范围更宽——既有技术的也有非技术的——因此理解技术和非技术问题都很重要。

获得其它干系人认可的重要性

确保所有干系人理解缓慢的、脆弱的发布工程会使组织和用户面临风险是十分重要的。这牵涉到组织的各个级别都承认缓慢脆弱的自动化带来丧失的商业机会和市场风险。而且,Mozilla采用超级快的发布周转来保护用户的能力随着更多的用户到来将会变得愈加重要,而这反过来使我们更具吸引力。

有意思的是,有些人在他们的职业生涯中只见过脆弱的发布自动化,所以会带着“啊,就是这么糟糕”的期望来到Mozilla。将一个鲁棒的、可扩展的发布自动化流程能带来的潜在商业收益解释给大家,有助于帮助每个人理解现在还不可见但即将展开的发布过程改进工作。

让其他团队也参加进来

为了使发布过程更有效、更可靠,需要发布工程及Mozilla的其他团队共同做很多事情。然而,有意思的一点是看到人们经常把“需要很长时间交付一个发布”误读成“需要发布工程团队很长时间交付一个发布”。这个误解忽略了发布过程团队之外的其他团队完成的发布相关的工作,使发布工程师感觉很受伤。消除这个误解需要让Mozilla全体人员明白一次发布的时间都花在了不同团队的那些环节。我们使用了非常低技术方式:跨团队交割邮件清晰的记录了各个时间点,blog里详细的记录了时间花在了哪里。

  • 这有助于理解哪些不同的团队牵涉在一个发布里
  • 这有助于人们赞赏发布工程师的改进,这反过来促进了发布工程师做更多的改进
  • 这有助于其他团队思考他们怎样做也能帮助改进整体的发布流程——这对整个组织来说是一个很大的思维方式上的转变。
  • 最后,这也消除了团队之间所有不清楚的交割沟通,这在历史上造成了许多反复、错误的开始,及其它代价巨大的中断。

建立清晰的交割

许多发布工程问题实际上是人的问题:团队之间的错误沟通;缺乏清晰的领导力;以及由此导致的在chemspill发布中的压力、疲惫和焦虑。通过定义清晰的交割来消除这些人的沟通问题,我们的发布马上变得更加平顺了,跨团队的交互很快得到了改善。

管理(人员)周转

当开始这个项目的时候,人员流失非常频繁。这就事情本身而言就够糟糕的了。然而,更糟糕的是,缺乏准确的最新的文档意味着绝大多数对发布流程的技术理解是口口相传的,当人员离开时就丢失了。我们必须尽快改变这种状况。

我们感觉提振士气、显示事情正在好转最好的办法就是确保人们看到我们有一个计划去改善现状,而人们能掌握自己的命运。我们做到这一点的方式是确保每次发布以后安排时间改进至少一件事情——任何事情!我们要到了发布后1-2天的不受打扰时间。解决最急迫的小问题,此时这些问题在人们的脑袋里还很清晰,也不会被其他事情分心,其他更大的长远的问题留在以后的发布中解决。更重要的是,这给人们一种感觉,就是我们重新掌握了自己的命运,事情正在好转。

管理变化

在我们正在做改进使,由于市场压力,Mozilla发布流程的业务和产品需求变了。这并不是什么罕见的事情,我们应该预料到。

我们知道在开发新流程的同时,必须得继续用老的发布流程交付发布。我们决定抵制住建立一个全新的项目同时支持现有系统的诱惑;我们觉得现有系统太脆弱了,以至于根本没有时间去做任何新的事情。

我们从开始就假定我们没有完全了解什么出错了。通过每个增量式的改进,我们得以在下一次改进之前回顾和发现新的惊讶。贯穿整个项目,每当我们发现新的惊讶时,类似“排干沼泽地”、“剥洋葱”、“以前竟然是这么做的”的话就不绝于耳。

基于此,我们决定对现有流程做多个小的、持续的改进。每个迭代改进使得下一个发布好一点。更重要的是,每个改进可以释放更多一点时间,发布工程师用来做下一次改进。这些改进象滚雪球一样,直到我们发现已经超过了临界点,可以做更加重大的改进了。此时,发布优化带来的收益就真正兑现了。

2.10. 更多信息

对迄今为止所完成的工作,以及它在新的白热化的全球浏览器市场背景下带给Mozilla的竞争力,我们由衷的自豪。

4年以前,一个月内完成两次chemspill发布在Mozilla值得称道。相比之下,上周公布的一个利用第三方库缺陷的安全漏洞导致了Mozilla在2天之内交付了8个chemspills发布。

同任何事物一样,我们的发布自动化仍然有足够的改进空间,需求一直在变化。要了解我们正在进行的工作,参见: