《持续交付 发布可靠软件的系统方法》读书笔记
构建和部署系统必须一直保持活力,即这个系统不仅要从项目刚开始就开发,而且一直要持续到软件在生产环境中的维护阶段。一定要细心地设计和维护它,像对待其他源代码一样对待它,并定期使用,以便当我们需要时,可以确保它还能运行。
构建工具概览
所有构建工具都有一个共同的核心功能,即 可以对依赖关系建模 。在执行过程中,它能以正确的顺序执行一系列的任务,计算如何达到你所指定的目标,而且被依赖的任务也仅需要运行一次。书中列举的一些构建工具:Make、Ant、NAnt 与 MSBuild、Maven、Rake、Buildr、Psake。
构建部署脚本化的原则与实践
下面列出构建部署脚本化时所要遵循的原则与实践,无论你使用哪种技术它们都是适用的。
为部署流水线的每个阶段创建脚本
当项目刚开始时,可以将部署流水线中的每个操作都放在同一个脚本文件中,即使是那些还没有被自动化的步骤,也可以有对应的哑操作。但是,一旦脚本变得太长,就要将它们分成独立的脚本,让部署流水线中的每个阶段分别使用单独的脚本。这样,一个提交阶段的脚本就可以完成编译、打包、运行提交测试套件和执行代码静态分析的工作。功能验收测试脚本会调用部署工具,将应用程序部署到适当环境中,并准备相关数据,之后再运行验收测试。你还可再用一个脚本运行任何非功能测试,比如压力测试和安全测试。
确保将所有的脚本都放到版本控制库中,并且最好和源代码放在同一个版本 控制库中。对于开发人员和运维人员来说,最关键的是要能够合作完成构建脚本 和部署脚本,而想要做到这一点,就要把它们放在同一个仓库中。
使用恰当的技术部署应用程序
在做自动化部署工作时,应该使用恰当的工具,而不是通用脚本语言(除非部署流程十分简单)。
使用同样的脚本向所有环境部署
“使用同样的脚本部署每个环境” 和 “环境配置信息的不同(比如服务URI或IP地址)”这两件事应该分开管理,即将配置信息从脚本中分离出来,并将其保存在版本控制库中,并用一些机制让部署脚本去获得这些信息。这里有两个关键点:
- 构建和部署脚本在开发机器和类生产环境上都能运行;
- 开发人员使用这些脚本进行所有的构建和部署活动;
使用操作系统自带的包管理工具
在本书中我们使用“二进制包”指代部署过程中需要放在目标环境中的所有内容。大多数情况下,它是构建过程中产生的一堆文件,以及应用程序所需的库文件,可能还包括版本库中的某些静态文件。可是,“将一堆文件分别部署到文件系统的不同位置”这种做法效率非常低,维护起来也非常麻烦,尤其是在升级、回滚和卸载时。这也是包管理工具出现的原因。如果只有一种目标操作系统,或者一组相似的操作系统,我们强烈推荐使用操作系统自身的包管理技术把需要部署的文件打包在一起。
确保部署流程是幂等的(Idempotent)
无论开始部署时目标环境处于何种状态,部署流程应该总是令目标环境达到同样(正确)的状态,并以之为结束点。
部署系统的增量式演进
每个人都能看到一个完全自动化的部署过程的魅力,即“单击按钮即可发布软件”。当某个大型企业应用系统以这种方式部署时,看起来就像变魔术一般。但魔术有一个问题,即从外部看会显得极为复杂。事实上,当你查看我们的部署系统时会发现,它只是由一组非常简单的、增量的步骤组成的复杂系统,而这些步骤也是随着项目的进行不断完善的。我们想说的是,并不是完成所有的步骤之后才能获得价值。事实上,当你第一次写了一个脚本用于在本地的开发环境上部署应用程序,并将其分享给整个团队时,就已经节省了很多开发人员的时间。
部署脚本化
环境管理的核心原则之一就是:对测试和生产环境的修改只能由自动化过程执行。
多层的部署和测试
对于软件交付或某个复杂系统的构建和部署,假如说有一个基础的核心原则的话,那就是应该总是把根基扎在已知状态良好的基础之上。我们不去测试那些没有编译成功的代码,也不会对没有通过提交测试的代码进行验收测试等。
测试环境配置
任何一个层级的部署出错,都可能导致应用程序无法正常运行。所以,当准备每一层级时,都要对其进行测试。如果发现问题,就要让环境配置流程快速失败,而测试结果也应该给出清晰指示,指出错误出现在哪里。
小贴士
- 总是使用相对路径;
- 消除手工步骤;
- 从二进制包到版本控制库的内建可追溯性;
- 不要把二进制包作为构建的一部分放到版本控制库中;
- “test”不应该让构建失败;
- 用集成冒烟测试来限制应用程序;
小结
“脚本”这个术语被广泛应用,通常是指辅助我们进行构建、测试、部署和发布应用程序的所有自动化脚本。强烈建议你使用构建和部署流程作为组建该脚本集的一个指导。请以迭代的方式来识别最令你痛苦的步骤,并将其自动化,沿着部署流水线,逐步完善自动化构建和部署能力。请时刻牢记最终目标,即在开发、测试和生产环境中共享同一种部署机制,但不要过早地纠结于工具的创建。脚本应该贯穿应用程序的整个生命周期。我们应该对这些脚本进行版本控制、维护、测试和重构,并且将其用作部署应用程序的唯一机制。