介绍
开发和发布软件可能是一个复杂的过程,特别是随着应用程序,团队和部署基础架构本身的复杂性增长。 通常,随着项目的增长,挑战变得越来越显着。 为了快速,一致地开发,测试和发布软件,开发人员和组织已经创建了三个相关但不同的策略来管理和自动化这些流程。
持续整合的重点是将个人开发人员的工作整合到主存储库,每天多次,以及时捕捉整合错误并加速协同开发。 持续交付涉及减少部署或释放过程中的摩擦,自动执行部署构建所需的步骤,以便随时安全地释放代码。 持续部署进一步通过每次更改代码时自动部署。
在本指南中,我们将讨论这些策略中的每一个,它们如何相互关联,以及如何将它们纳入您的应用程序生命周期可以改变您的软件开发和发布实践。
什么是持续集成,为什么是有益的?
持续集成是一种实践,鼓励开发人员将他们的代码早期并经常地集成到共享存储库的主要分支中。 在开发周期结束时,代替孤立地构建功能并集成它们,而不是每天开发人员在多个时间内将代码与共享存储库集成在一起。
这个想法是通过早日考虑来最大限度地降低整合成本。 开发人员可以尽早发现新代码和现有代码之间的边界冲突,而冲突仍然相对容易调和。 一旦冲突得到解决,工作就可以保证新代码能够满足现有代码库的要求。
经常集成代码本身不会对新代码或功能的质量提供任何保证。 在许多组织中,集成是昂贵的,因为使用手动过程来确保代码符合标准,不会引入错误,并且不会破坏现有功能。 当自动化水平不符合质量保证措施时,频繁的集成可能会产生摩擦。
为了在集成过程中解决这种摩擦,实际上,持续集成依赖于可靠的测试套件和运行这些测试的自动化系统。 当开发人员将代码合并到主存储库中时,自动化过程将启动新代码的构建。 之后,针对新版本运行测试套件,以检查是否引入了任何集成问题。 如果构建或测试阶段失败,则会警告小组,以便他们可以修复构建。
持续整合的最终目标是使集成成为日常开发工作流程中的一个简单而可重复的过程,以降低集成成本并及早应对缺陷。 努力确保系统稳健,自动化和快速,同时培养团队文化,鼓励频繁的迭代和响应能力来构建问题是战略成功的基础。
什么是持续交付,为什么是有用的?
持续交付是持续整合的延伸。 它专注于自动化软件交付过程,以便团队可以随时轻松自信地将其代码部署到生产中。 通过确保代码库始终处于可部署状态,释放软件将成为无复杂仪式的不起眼的事件。 团队可以相信,只要他们需要没有复杂的协调或后期阶段测试,他们就可以释放。 与持续整合一样,持续交付是一种需要技术和组织改进的混合才能有效的做法。
在技术方面,持续交付大量地依赖于部署管道,以自动化测试和部署过程。 部署管道是一种自动化系统,可以将系统日益严格的测试套件针对构建作为一系列顺序阶段。 这样一来,连续集成就脱离了,所以可靠的连续集成设置是实现连续交付的先决条件。
在每个阶段,构建或者不通过测试,这会提醒团队,或者通过测试,这将导致自动升级到下一个阶段。 随着构建运行通过管道,后续阶段将构建部署到尽可能接近生产环境的环境中。 这样可以一起测试构建,部署过程和环境。 管道以一个可以在一个步骤中随时部署到生产中的构建结束。
持续交付的组织方面鼓励将“可部署性”列为主要关注点。 这对构建功能并挂接到其他代码库的方式有影响。 必须考虑到代码的设计,使功能可以随时安全地部署到生产中,即使不完整。 已经出现了一些技术来协助这一领域。
持续交付是有吸引力的,因为它可以自动执行检查代码到存储库中的步骤,并决定是否将经过良好测试的功能版本发布到生产基础设施。 帮助确定代码的质量和正确性的步骤是自动化的,但是关于要发布的内容的最终决定由组织掌握在最大的灵活性之内。
什么是持续部署,为什么是有用的?
持续部署是连续传送的延伸,可自动部署通过完整测试周期的每个构建。 连续部署系统不是等待人类网守决定什么和何时部署到生产,而是部署了已经成功遍历部署管道的所有内容。 请记住,当新代码被自动部署时,存在技术以在稍后的时间或一小部分用户上激活新功能。 自动部署功能并快速修复客户,鼓励在范围有限的情况下进行更小的更改,并有助于避免与目前部署到生产中的内容混淆。
这种完全自动化的部署周期可能是担心放弃对自动化系统的控制的组织担心什么被释放的焦虑的根源。 自动部署提供的权衡有时被认为对他们所提供的收益来说太危险了。
其他组织利用自动发布的承诺,作为确保始终遵循最佳实践的方法,并将测试过程扩展到有限的生产环境中。 在部署一段代码之前,没有最终的手动验证,开发人员必须承担责任,确保他们的代码设计精良,并且测试套件是最新的。 这样就会崩溃了关于什么和什么时候承诺主仓库的决定,什么和什么时候将生产释放到一个牢固地掌握在开发团队手中的单一点。
持续部署还使组织能够从一致的早期反馈中受益。 功能可以立即向用户提供,缺陷或无益的实施可以在团队在无效的方向下付出巨大努力的早期被捕获。 获得快速反馈的功能不是有用的让团队转移焦点,而不是将更多的精力投入到一个影响最小的地区。
连续过程的关键概念和实践
虽然持续的整合,交付和部署在其参与范围上有所不同,但有一些概念和实践是每个成功的基础。
小的,迭代的变化
采取持续整合的最重要的做法之一是鼓励小的变化。 开发人员应该把更大的工作分解成小块,早日实现。 通过抽象和特征标志(见下文)分支的特殊技术有助于保护主分支的功能免于进行中的代码更改。
小的变化使集成问题的可能性和影响最小化。 通过尽可能早地到共享的分支机构,然后在整个开发过程中不断进行整合,整合成本降低,无关的工作定期同步。
基于中继线的开发
通过基于中继的开发,工作将在存储库的主分支中完成,或者以频繁的间隔合并到共享存储库中。 短期特征分支是允许的,只要它们代表小的变化,并尽快合并。
基于干线发展的理念是避免违反上述小型,迭代变化概念的大型承诺。 代码可以早期提供给同行,以便在范围很小时可以解决冲突。
从主分支或从专门为此目的创建的发行分支执行释放。 在发行分支上没有发生发展,以便将重点放在主分支作为真实的单一来源。
保持建筑和测试阶段快速
每个过程都依赖自动化建立和测试来验证正确性。 因为构建和测试步骤必须经常执行,所以必须精简这些流程,以最大程度减少花费在这些步骤上的时间。
建设时间的增加应被视为一个主要问题,因为每个提交启动一个构建的事实使得影响更加复杂。 由于持续的过程迫使开发商每天参与这些活动,减少这些地区的摩擦是值得追求的。
在可能的情况下,并行运行测试套件的不同部分可以更快地移动构建通过管道。 还要注意确保每种类型的测试的比例是有意义的。 单元测试通常非常快,维护开销最小。 相比之下,自动化系统或验收测试通常是复杂的并且易于破损。 为了解决这个问题,通常很有可能依靠单元测试,进行相当数量的集成测试,然后退出更多复杂测试的次数。
整个部署管道中的一致性
因为连续的传送或部署实现应该是测试版本的价值,因此在进程的每个步骤(构建本身,部署环境和部署过程本身)中保持一致性至关重要:
- 代码应在管道开始时建立一次 :生成的软件应该存储并可访问以后进程而不进行重建。 通过在每个阶段使用完全相同的工件,您可以确定您不会因为不同的构建工具而引入不一致。
- 部署环境应该是一致的 :配置管理系统可以控制各种环境,环境变化可以通过部署管道本身进行,以确保正确性和一致性。 应为每个测试周期配置清洁的部署环境,以防止遗留条件损害测试的完整性。 阶段性环境应尽可能地紧密地匹配生产环境,以减少构建提升时存在的未知因素。
- 应该使用一致的流程来在每个环境中部署构建 :每个部署应该是自动化的,每个部署应该使用相同的集中式工具和过程。 应该消除专门部署,以便仅使用管道工具进行部署。
解除部署和释放
将代码部署从其发行版分离到用户是连续交付和部署中非常强大的一部分。 代码可以部署到生产中,而不必初次激活或使用户可以访问该代码。 然后,组织决定何时发布独立于部署的新功能或功能。
通过将业务决策与技术流程分开,给组织带来了很大的灵活性。 如果代码已经在服务器上,那么部署不再是发布过程的一个微妙部分,它可以最大程度地减少个人数量和发布时所涉及的工作量。
有许多技术帮助团队部署负责功能的代码,而不会释放它。 功能标志设置条件逻辑,以检查是否根据环境变量的值运行代码。 通过抽象分支,开发人员可以通过在资源消费者和提供者之间放置抽象层来替换实现。 仔细规划并入这些技术可以让您脱离这两个过程。
测试类型
持续的集成,交付和部署都非常依赖自动测试来确定每个代码更改的功效和正确性。 在这些过程中需要进行不同类型的测试,以获得给定解决方案的信心。
虽然下面的类别绝对不是详尽的列表,尽管对每种类型的确切定义存在分歧,但这些广泛的测试类型代表了不同上下文中评估代码的各种方法。
烟雾测试
烟雾测试是一种特殊的初步检查,旨在确保非常基本的功能以及一些基本的实施和环境假设。 烟雾测试通常在每个测试周期开始之前运行,作为在运行更完整的测试套件之前的健全检查。
这种测试背后的想法是帮助在实现过程中捕获大红旗,并引起注意可能表明进一步测试是不可能或不值得的问题。 烟雾测试不是很广泛,但应该非常快。 如果一个变化失败了烟雾测试,它的核心断言的早期信号被打破,你不应该花更多的时间来测试,直到问题解决。
可以在任何新的相位测试开始时使用具体的烟雾测试,以断言满足基本假设和要求。 例如,可以在集成测试或部署到分段服务器之前使用烟雾测试,但是每种情况下待测试的条件都会有所不同。
单元测试
单元测试负责以孤立且高度针对性的方式测试代码的各个元素。 各个功能和类的功能自己测试。 任何外部依赖关系都被替换为存根或模拟实现,将测试完全集中在所涉及的代码上。
单元测试对于内部一致性和正确性在被放置在更复杂的上下文中之前,对各个代码组件的正确性进行测试至关重要。 测试的有限程度和依赖性的消除使得更容易追查任何缺陷的原因。 它也是测试各种可能难以打击的输入和代码分支的最佳时机。 通常,在任何烟雾测试之后,单元测试是进行任何更改时运行的第一个测试。
单元测试通常由个体开发人员在自己的工作站上运行,然后再提交更改。 然而,在开始集成测试之前,持续集成服务器几乎总是将这些测试再次运行为安全防护。
集成测试
单元测试后,集成测试通过将组件分组在一起并将其作为组件进行测试来执行。 当单元测试隔离验证代码的功能时,集成测试确保组件在彼此接口时协作。 这种类型的测试有机会捕获通过组件之间的交互暴露的完全不同类别的错误。
通常,当将代码检入共享存储库时,会自动执行集成测试。 连续集成服务器检查代码,执行任何必要的构建步骤(通常执行快速烟雾测试以确保构建成功),然后运行单元和集成测试。 模块以不同的组合钩在一起并进行测试。
集成测试对共享工作很重要,因为它们保护了项目的健康。 更改必须证明它们不会破坏现有功能,并且与预期的其他代码进行交互。 集成测试的第二个目标是验证这些更改可以部署到一个干净的环境中。 这通常是由开发人员自己的机器执行的第一个测试周期,因此在此过程中也可以发现未知的软件和环境依赖关系。 这通常也是第一次根据真正的外部库,服务和数据测试新的代码。
系统测试
一旦执行集成测试,可以开始另一个称为系统测试的测试级别。 在许多方面,系统测试作为集成测试的扩展。 系统测试的重点是确保组件组件作为一个整体的整体运行正常。
系统测试通常不会专注于组件之间的接口,而是评估整个软件的外部功能。 这套测试忽略了组成部分,以便将组合软件评估为统一实体。 由于这种区别,系统测试通常侧重于用户或外部可访问的接口。
验收测试
验收测试是在交付前在软件上执行的最后一个测试类型之一。 验收测试用于确定一件软件是否满足业务或用户观点的所有要求。 这些测试有时是根据原始规范构建的,并且经常测试接口的预期功能和可用性。
验收测试通常是一个更加涉及的阶段,可能会延伸到软件的发布之外。 可以使用自动验收测试来确保设计的技术要求得到满足,但手动验证通常也起作用。
通常,通过将构建部署到反映生产系统的分段环境开始。 从这里可以运行自动测试套件,内部用户可以访问系统,检查它们是否按照需要的方式运行。 在发布或提供对客户的beta访问后,通过评估软件如何正常使用并通过收集用户的反馈来进一步验收测试。
附加术语
虽然我们已经讨论了上面的一些更广泛的想法,但是您可以在了解持续集成,交付和部署过程中遇到许多相关的概念。 我们定义您可能会看到的其他一些术语:
- 蓝绿色部署 :蓝绿色部署是在类似生产环境中测试代码并以最少的停机时间部署代码的策略。 维护了两套具有生产能力的环境,并将代码部署到可以进行测试的非活动集合。 当准备发布时,生产流量将通过新代码路由到服务器,立即使更改可用。
- 分支抽象 :分支抽象是一种在活动项目中执行主要重构操作的方法,而在源代码存储库中没有长期存在的开发分支,持续的集成实践阻止了这一点。 在消费者和现有实现之间构建和部署抽象层,以便并行地在抽象背后构建新的实现。
- 构建(名词) :构建是从源代码创建的软件的特定版本。 根据语言,这可能是编译代码或一组一致的解释代码。
- 金丝雀发布 :金丝雀版本是发布对有限子集的更改的策略。 这个想法是确保一切与生产工作负载正常工作,同时尽可能减少影响,如果有问题。
- 黑暗发射 :黑暗发射是将代码部署到生产流程的做法,但不影响用户体验。 新的更改与现有实施一起部署,相同的流量通常路由到两个地方进行测试。 旧的实现仍然与用户界面挂钩,但是在幕后,可以使用生产环境中的真实用户请求来评估新代码的正确性。
- 部署管道 :部署管道是一组组件,通过越来越严格的测试和部署方案来移动软件,以评估其准备发布。 流水线通常以自动部署到生产或提供手动执行的选项来结束。
- 功能标志或功能切换功能标志是一种在条件逻辑后面部署新功能的技术,它决定是否根据环境变量的值运行。 新代码可以部署到生产中,而不必通过适当地设置标志来激活。 要释放软件,环境变量的值被改变,导致新的代码路径被激活。 功能标志通常包含允许用户子集访问新功能的逻辑,创建一种逐渐推出新代码的机制。
- 促进 :在连续过程的上下文中,促进意味着将软件构建转移到下一个测试阶段。
- 浸泡测试 :浸泡测试涉及在显着的生产或生产类似的负载下长时间测试软件。
结论
在本指南中,我们引入了持续集成,持续交付和持续部署,并讨论了如何安全,快速地构建和发布经过良好测试的软件。 这些过程利用广泛的自动化,并鼓励持续的代码共享早日修复缺陷。 虽然实施这些解决方案所需的技术,流程和工具是一个重大的挑战,但设计良好且使用正确的系统的好处可能是巨大的。