文章目录
持续集成(CI)和持续交付(CD)是软件生产中非常常见的术语。但你知道他们的真正含义吗?
图片来源: opensource.com
在谈论生产软件时,持续集成(CI)和持续交付(CD)是非常常用的术语。但他们真正的意思是什么?在本文中,我将解释这些和相关术语背后的含义和意义,例如连续测试和持续部署。
快速摘要
工厂中的装配线以快速,自动化,可重复的方式从原材料生产消费品。同样,软件交付管道以快速,自动化和可重现的方式从源代码生成版本。如何完成这项工作的总体设计称为“持续交付”。启动装配线的过程称为“持续集成”。确保质量的过程称为“持续测试”,使最终产品可供用户使用的过程称为“持续部署”。整体效率专家让一切运行顺畅,每个人都被称为“DevOps”从业者。
“连续”是什么意思?
连续用于描述遵循我在此描述的实践的许多不同过程。这并不意味着“永远在跑步”。它确实意味着“随时可以运行”。在创建软件的环境中,它还包括几个核心概念/最佳实践。这些是:
-
频繁发布:持续实践背后的目标是能够频繁地交付高质量的软件。此处的频率是可变的,可由团队或公司定义。对于某些产品,每季度,每月,每周或每天一次可能足够频繁。对于其他人来说,一天可能需要多次并且可行。连续也可以采取“偶尔,按需”的方面。最终目标是相同的:在可重复,可靠的过程中为最终用户提供高质量的软件更新。通常,这可以通过很少甚至没有交互或甚至用户的知识来完成(想想设备更新)。
-
自动化流程:实现这一频率的关键部分是拥有自动化流程来处理软件生产的几乎所有方面。这包括构建,测试,分析,版本控制,以及在某些情况下的部署。
-
可重复:如果我们使用的自动化流程在给定相同输入的情况下始终具有相同的行为,则处理应该是可重复的。也就是说,如果我们返回并输入相同版本的代码作为输入,我们应该得到相同的可交付成果集。这也假设我们有相同版本的外部依赖项(即我们不创建代码使用的其他可交付项)。理想情况下,这也意味着可以对管道中的流程进行版本控制和重新创建(请参阅稍后的DevOps讨论)。
-
快速处理: “快速”是这里的相对术语,但无论软件更新/发布的频率如何,连续过程都需要以有效的方式处理从源代码到可交付物的变更。自动化负责大部分工作,但自动化流程可能仍然很慢。例如,对于每天大部分时间都需要多次新候选发布的产品更新,对产品的所有方面进行集成测试可能会太慢。
什么是“持续交付管道”?
处理将源代码转换为可释放产品的不同任务和作业通常串联成一个软件“管道”,其中一个自动过程的成功完成启动序列中的下一个过程。这些管道有许多不同的名称,例如持续交付管道,部署管道和软件开发管道。整个管理程序应用程序在管道执行时管理不同管道部分的定义,运行,监视和报告。
连续交付管道如何运作?
软件交付管道的实际实现可以有很大不同。可以在管道中使用大量和多种应用程序,用于源跟踪,构建,测试,收集指标,管理版本等的各个方面。但是整个工作流程通常是相同的。单个业务流程/工作流应用程序管理整个管道,每个流程作为单独的作业运行或由该应用程序进行阶段管理。通常,单个“作业”是在业务流程应用程序理解并可作为工作流程管理的语法和结构中定义的。
创建作业以执行一个或多个功能(构建,测试,部署等)。每项工作可能使用不同的技术或多种技术。关键是作业是自动化,高效和可重复的。如果作业成功,则工作流管理器应用程序将触发管道中的下一个作业。如果作业失败,工作流管理器会向开发人员,测试人员和其他人发出警报,以便他们尽快纠正问题。由于自动化,可以比运行一组手动过程更快地找到错误。这种快速识别错误称为“快速失败”,并且在获取管道端点方面同样有价值。
什么是“快速失败”?
管道工作之一就是快速处理变更。另一种方法是监视创建发布的不同任务/作业。由于无法编译或未通过测试的代码可以阻止管道,因此快速通知用户此类情况非常重要。快速失败指的是管道处理尽快发现问题并快速通知用户的想法,以便可以纠正问题并重新提交代码以便通过管道进行另一次运行。通常,管道流程可以查看历史记录以确定谁进行了更改并通知该人员及其团队。
连续交付管道的所有部分都必须自动化吗?
管道的几乎所有部分都应该是自动化的。对于某些部分,有一个人为干预/互动的地方可能是有意义的。一个例子可能是用户验收测试(让最终用户试用软件并确保它能达到他们想要/期望的效果)。另一种情况可能是部署到生产环境,其中组希望拥有更多的人为控制。当然,如果代码不正确并且中断,则需要人工干预。
有了连续含义的背景知识,让我们看看不同类型的连续处理以及每个在软件管道上下文中的含义。
什么是持续整合?
持续集成(CI)是自动检测,拉取,构建和(在大多数情况下)进行单元测试的过程,因为产品的源代码已更改。CI是启动管道的活动(尽管某些预验证 - 通常称为“飞行前检查” - 有时会在CI之前合并)。
CI的目标是快速确保开发人员的新变更“良好”并且适合在代码库中进一步使用。
持续集成如何运作?
基本思想是让自动过程“观察”一个或多个源代码存储库以进行更改。当更改被推送到存储库时,观察过程会检测到更改,下载副本,构建它并运行任何相关的单元测试。
持续集成如何检测变化?
目前,观看过程通常是像Jenkins这样的应用程序,它还协调管道中运行的所有(或大多数)进程,并监视更改作为其功能之一。观看应用程序可以以几种不同的方式监视变化。这些包括:
-
轮询:监控程序反复询问源管理系统,“您对我感兴趣的存储库中有什么新东西吗?” 当源管理系统有新的更改时,监视程序会“唤醒”并完成其工作以获取新代码并构建/测试它。
-
定期:监控程序配置为定期启动构建,无论是否有更改。理想情况下,如果没有更改,则不会构建任何新内容,因此这不会增加额外的成本。
-
推送:这与使用源管理系统检查的监视应用程序相反。在这种情况下,源管理系统被配置为当将更改提交到存储库时将通知“推出”到监视应用程序。最常见的是,这可以以“webhook”的形式完成 - 一个程序被“钩住”以在推送新代码时运行并通过互联网向监控程序发送通知。为此,监控程序必须具有可以通过Internet接收webhook信息的开放端口。
什么是“预检”(又称飞行前检查)?
在将代码引入源存储库并触发持续集成之前,可以进行其他验证。这些遵循最佳实践,例如测试版本和代码审查。它们通常在代码引入管道之前构建到开发过程中。但是一些管道也可能将它们作为其监控流程或工作流程的一部分。
例如,一个名为Gerrit的工具允许在开发人员推送代码之后但在允许进入(Git远程)存储库之前进行正式的代码审查,验证和测试构建。Gerrit位于开发人员工作区和Git远程存储库之间。它“抓住”来自开发人员的推送,并且可以执行通过/失败验证以确保它们在被允许进入存储库之前通过。这可以包括检测建议的更改并开始测试构建(CI的形式)。它还允许组在那时进行正式的代码审查。通过这种方式,有一种额外的信心,即当变量合并到代码库中时,变化不会破坏任何东西。
什么是“单元测试”?
单元测试(也称为“提交测试”)是由开发人员编写的小型,集中测试,以确保新代码独立工作。“孤立地”这里意味着不依赖于或调用其他不可直接访问的代码,也不依赖于外部数据源或其他模块。如果运行代码需要这样的依赖关系,那么这些资源可以用模拟来表示。模拟是指使用看起来像资源的代码存根,可以返回值但不实现任何功能。
在大多数组织中,开发人员负责创建单元测试以证明其代码有效。事实上,一个模型(称为测试驱动开发 [TDD])要求首先设计单元测试作为清楚地识别代码应该做什么的基础。因为这样的代码更改速度快且数量众多,所以它们也必须快速执行。
由于它们与持续集成工作流有关,因此开发人员在其本地工作环境中创建或更新源,并使用单元测试来确保新开发的功能或方法有效。通常,这些测试采用断言形式,即函数或方法的给定输入集产生给定的输出集。它们通常进行测试以确保正确标记和处理错误条件。各种单元测试框架(例如JUnit for Java开发)可以提供帮助。
什么是连续测试?
连续测试是指在代码通过CD管道时运行扩展范围的自动化测试的实践。单元测试通常与构建过程集成,作为CI阶段的一部分,并专注于与其他与之交互的代码隔离测试代码。
除此之外,还有各种形式的测试可以/应该发生。这些可包括:
-
集成测试验证组件和服务组是否一起工作。
-
功能测试验证产品中执行功能的结果是否符合预期。
-
验收测试根据可接受的标准测量系统的某些特征。示例包括性能,可伸缩性,压力和容量。
所有这些可能不存在于自动化管道中,并且一些不同类型之间的线可能模糊。但是,在交付管道中持续测试的目标始终是相同的:通过连续的测试级别证明代码具有可以在正在进行的发布中使用的质量。基于持续快速的原则,第二个目标是快速发现问题并提醒开发团队。这通常被称为快速失败。
除了测试之外,还可以对管道中的代码进行哪些其他类型的验证?
除了测试的通过/失败方面之外,还存在一些应用程序,它们还可以告诉我们测试用例执行(覆盖)的源代码行数。这是可以跨源代码计算的度量的示例。此度量标准称为代码覆盖率,可以通过工具(例如JaCoCo for Java源代码)进行测量。
存在许多其他类型的度量,例如计算代码行,测量复杂度,以及将编码结构与已知模式进行比较。SonarQube等工具可以检查源代码并计算这些指标。除此之外,用户还可以设置他们愿意接受的范围的阈值,作为这些指标的“传递”。然后,可以设置流水线中的处理以针对阈值检查计算值,并且如果值不在可接受范围内,则可以停止处理。SonarQube等应用程序具有高度可配置性,可以进行调整以仅检查团队感兴趣的内容。
什么是持续交付?
持续交付(CD)通常是指整个流程链(管道),它自动获取源代码更改并通过构建,测试,打包和相关操作运行它们,以生成可部署的版本,基本上没有任何人为干预。
CD在生成软件版本中的目标是自动化,效率,可靠性,可重复性和质量验证(通过连续测试)。
CD包含CI(自动检测源代码更改,执行更改的构建过程,运行单元测试以验证),连续测试(对代码运行各种测试以获得对代码质量的连续可信度),和(可选)连续部署(从管道发布版本自动为用户提供)。
如何在管道中识别/跟踪多个版本?
版本控制是处理CD和管道的关键概念。连续意味着能够经常集成新代码并提供更新版本。但这并不意味着每个人都想要“最新,最伟大的”。对于想要开发或测试已知稳定版本的内部团队来说尤其如此。因此,管道版本对象创建并轻松存储和访问这些版本化对象非常重要。
从源代码在流水线处理中创建的对象通常可以称为工件。工件在构建时应该有应用于它们的版本。将版本号分配给工件的建议策略称为语义版本控制。(这也适用于从外部源引入的依赖工件的版本。)
语义版本号有三个部分:major,minor和patch。(例如,1.4.3反映了主要版本1,次要版本4和补丁版本3.)这个想法是,其中一个部分的更改表示工件中的更新级别。主要版本仅针对不兼容的API更改而递增。当以向后兼容的方式添加功能时,次要版本会增加。当进行向后兼容的错误修复时,补丁版本会增加。这些是建议的指导原则,但只要团队在整个组织内以一致且易于理解的方式这样做,团队就可以自由地改变这种方法。例如,每次为发布完成构建时增加的数字可以放在补丁字段中。
文物如何“升级”?
团队可以为工件分配促销“级别”,以指示测试,生产等的适用性。有各种方法。可以启用Jenkins或Artifactory等应用程序进行促销。或者一个简单的方案可以是在版本字符串的末尾添加标签。例如,-snapshot可以指示用于构建工件的代码的最新版本(快照)。可以使用各种促销策略或工具将工件“推广”到其他级别,例如-milestone或-production,作为工件稳定性和准备释放的指示。
如何存储和访问多个版本的工件?
从源构建的版本化工件可以通过管理“工件存储库”的应用程序进行存储。工件存储库就像构建工件的源管理一样。应用程序(例如Artifactory或Nexus)可以接受版本化工件,存储和跟踪它们,并提供检索它们的方法。
管道用户可以指定他们想要使用的版本,并在这些版本中使用管道。
什么是持续部署?
持续部署(CD)是指能够自动释放CD管道中的代码并使其可供最终用户使用的想法。根据用户“安装”代码的方式,这可能意味着在云中自动部署内容,使更新可用(例如手机上的应用程序),更新网站或仅更新可用版本列表。
这里的一个重点是,仅仅因为可以进行持续部署并不意味着总是部署来自管道的每组可交付成果。它确实意味着,通过管道,每组可交付成果都被证明是“可部署的”。这在很大程度上是通过连续测试的连续级别完成的(参见本文中的连续测试部分)。
是否部署了管道运行的发布可以通过人工决策和用于在完全部署之前“试用”发布的各种方法来进行门控。
在完全部署到所有用户之前,有哪些方法可以测试部署?
由于必须回滚/撤消对所有用户的部署可能是一种代价高昂的情况(无论是技术上还是用户的感知),已经开发了许多技术来允许“尝试”部署新功能并在问题时轻松“撤消”它们被发现。这些包括:
蓝/绿测试/部署
在这种部署软件的方法中,维护了两个相同的托管环境 - 蓝色环境和绿色环境。(颜色并不重要,仅作为标识符。)在任何给定点,其中一个是生产部署,另一个是候选部署。
在这些实例的前面是路由器或其他系统,它们充当产品或应用程序的客户“网关”。通过将路由器指向所需的蓝色或绿色实例,可以将客户流量定向到所需的部署。通过这种方式,交换出指向哪个部署实例(蓝色或绿色)对用户来说是快速,简单和透明的。
当新版本准备好进行测试时,可以将其部署到非生产环境中。在经过测试和批准后,可以更改路由器以将传入的生产流量指向它(因此它将成为新的生产站点)。现在,生产的托管环境可供下一个候选人使用。
同样,如果在最新部署中发现问题并且之前的生产实例仍然部署在其他环境中,则简单的更改可以将客户流量指回到先前的生产实例 - 有效地将问题实例“脱机”并且回滚到以前的版本。然后可以在其他区域中修复具有该问题的新部署。
金丝雀测试/部署
在某些情况下,通过蓝色/绿色环境交换整个部署可能不可行或不可取。另一种方法称为金丝雀测试/部署。在此模型中,一部分客户流量被重新路由到产品的新部分。例如,产品中的新版本的搜索服务可以与服务的当前生产版本一起部署。然后,可以将10%的搜索查询路由到新版本,以在生产环境中对其进行测试。
如果新服务处理有限的流量而没有问题,那么随着时间的推移可能会有更多的流量路由到它。如果没有出现问题,那么随着时间的推移,可以增加路由到新服务的流量,直到100%的流量流向它。这有效地“退休”了以前版本的服务,并使新版本对所有客户生效。
功能切换
对于可能需要轻松退出的新功能(如果发现问题),开发人员可以添加功能切换。这是代码中的软件if-then开关,仅在设置数据值时才激活代码。此数据值可以是全局可访问的位置,部署的应用程序将检查该位置是否应执行新代码。如果设置了数据值,则执行代码; 如果没有,它没有。
这为开发人员提供了一个远程“终止开关”,以便在部署到生产后发现问题时关闭新功能。
黑暗发射
在这种实践中,代码被逐步测试/部署到生产中,但是用户不会看到更改(因此称为“黑暗”名称)。例如,在生产版本中,Web查询的某些部分可能会重定向到查询新数据源的服务。可以通过开发收集此信息以进行分析,而无需向用户公开有关接口,事务或结果的任何信息。
这里的想法是获得有关候选变更如何在生产负载下执行而不影响用户或改变其体验的真实信息。随着时间的推移,可以重定向更多负载,直到找到问题或认为新功能已准备好供所有人使用。功能标志实际上可用于处理暗发射的机制。
什么是DevOps?
DevOps的是一组关于如何使开发和运营团队更容易合作开发和发布软件的想法和推荐实践。从历史上看,开发团队创建了产品,但没有像客户那样以常规,可重复的方式安装/部署它们。这组安装/部署任务(以及其他支持任务)留给运营团队在整个周期中进行整理。这经常导致很多混乱和问题,因为运营团队在周期的后期进入循环,并且必须在短时间内完成他们的工作。同样,开发团队经常处于不利地位 - 因为他们没有充分测试产品的安装/部署功能,他们可能会对该过程中出现的问题感到惊讶。
这往往导致发展和运营团队之间严重脱节和缺乏合作。DevOps理想主张从开发周期到结束时涉及开发和操作人员的工作方式,例如CD。
CD如何与DevOps交叉?
CD管道是几个DevOps理想的实现。产品的后期阶段(如打包和部署)始终可以在管道的每次运行中完成,而不是等待产品开发周期中的特定点。同样,开发人员和操作人员都可以清楚地看到事情何时起作用,何时起作用,从开发到部署。要使CD管道的循环成功,它必须不仅要通过与开发相关的过程,还要经过与操作相关的过程。
进入下一个级别,DevOps表明即使是实现管道的基础架构也会被视为代码。也就是说,它应该自动配置,可跟踪,易于更改,并在管道发生变化时产生新的管道运行。这可以通过将管道实现为代码来完成。
什么是“管道代码”?
Pipeline-as-code是通过编程代码创建管道作业/任务的通用术语,就像开发人员使用产品的源代码一样。目标是将管道实现表示为代码,以便它可以与代码一起存储,审查,跟踪一段时间,如果出现问题并且必须停止管道,则可以轻松地再次启动。有几个工具允许这样做,包括Jenkins 2。
DevOps如何影响生产软件的基础架构?
传统上,管道中使用的各个硬件系统一次一个地配置有软件(操作系统,应用程序,开发工具等)。在极端情况下,每个系统都是一个定制的手工设置。这意味着当系统出现问题或需要更新时,这通常也是一项自定义任务。这种方法违背了基本的CD理想,即具有易于重现和可跟踪的环境。
多年来,已经开发了应用程序来标准化供应(安装和配置)系统。同样,虚拟机被开发为模拟在其他计算机之上运行的计算机的程序。这些VM需要监控程序才能在底层主机系统上运行它们。并且他们需要自己的操作系统副本才能运行。
接下来是容器。容器虽然在概念上与VM类似,但工作方式不同。他们只需使用一些现有的操作系统结构来划分操作系统中的隔离空间,而不需要单独的程序和操作系统的副本来运行。因此,它们的行为类似于VM以提供隔离但不需要开销。
由于VM和容器是根据存储的定义创建的,因此可以轻松地销毁和重新创建它们,而不会影响它们运行的主机系统。这允许可重新创建的系统运行管道。此外,对于容器,我们可以跟踪对它们构建的定义文件的更改 - 就像我们对源代码一样。
因此,如果我们遇到VM或容器中的问题,可能更容易和更快地销毁和重新创建它,而不是尝试调试并修复现有的。
这也意味着对管道代码的任何更改都可以触发管道的新运行(通过CI),就像对代码的更改一样。这是DevOps关于基础架构的核心理念之一。
原文:https://opensource.com/article/18/8/what-cicd
作者:Brent Laster