CI和CD之间的真正区别 -Fire CI


了解CI和CD解决的问题以正确使用它们至关重要。这将使您的团队可以改善您的流程。并避免花力气追求那些不会给您的过程带来任何价值的幻想指标。

持续集成是一个团队问题
如果您在团队中工作,那么您是在同一个存储库上工作的多个开发人员。存储库中有一个主分支,其中载有最新版本的代码。开发人员在不同分支上从事不同的工作。变更完成后,他会将其推送或合并到主分支。最终,整个团队将拉取这一变化。
我们要避免的情况是错误的提交使其进入主分支。错误意味着代码无法编译或应用程序无法启动或无法使用。需要永远不要部署该版本并等待修复。
问题是您的整个团队都陷入了困境。所有提出错误提交的开发人员都将花费5分钟来思考为什么它不起作用。有些人可能会尝试查找错误的提交。有些人会尝试与有问题的代码作者并行解决问题。
这对您的团队来说是浪费时间。最糟糕的是,重复发生的事件加剧了对主分支机构的不信任,并鼓励开发人员分开工作。

持续集成就是为了防止主分支被破坏,从而使您的团队不会陷入困境。这并不是要让所有测试始终保持绿色并且主分支在每次提交时都可以部署到生产中。

持续集成的过程独立于任何工具。您可以手动验证分支和主分支的合并在本地是否有效。然后仅将合并推送到存储库。这是非常低效的。这就是为什么使用自动检查实现持续集成的原因。
检查应确保最低限度:

  • 该应用程序应构建并启动
  • 最关键的功能应始终处于工作状态(用户注册/登录过程以及关键的业务功能)
  • 所有开发人员都依赖的应用程序的通用层应该是稳定的。这意味着对这些零件进行单元测试。

实际上,这意味着您需要提取适用于您的任何单元测试框架并保护应用程序的公共层。有时,代码不是很多,可以很快完成。另外,您还需要添加“烟雾测试”以验证代码是否已编译以及应用程序是否启动。这对于带有疯狂依赖注入的技术(例如Java Spring或.NET Core)尤其重要。在大型项目中,很容易误解依赖项,因此必须确认该应用程序至少总是始终启动。

如果您有成百上千的测试,则不需要为每个合并运行所有测试。这将花费大量时间,并且大多数测试可能会验证“non team blocker”功能。

我们将在接下来的部分中看到连续交付的流程将如何充分利用这许多测试。

与工具无关
工具和自动检查都可以。但是,如果您的开发人员合并他们工作了几个星期的巨型分支机构,那么工具和自动检查将无济于事。团队将花费大量时间合并分支并修复最终将出现的代码不兼容问题。与错误的提交阻塞在一起一样浪费时间。

持续集成与工具无关。这是关于小块工作并将新代码集成到主分支并频繁提取的问题。

通常至少每天一次持续集成。将您正在处理的任务拆分为较小的任务。经常合并您的代码,并经常拉取。这样一来,没有人能分开工作超过一两天,就没有时间滚雪球了。
一项大型任务不必全部都在一个分支中。应该永远不会。将进行中的工作合并到主分支的技术称为“抽象分支”和“功能切换”。有关更多详细信息,请参见博客文章“ 如何开始进行持续集成 ”。

优质CI的关键点
非常简单 保持简短。最多3-7分钟。这与CPU和资源无关。这与开发人员的生产力有关。生产力的首要规则是专注。做一件事,完成它,然后移到下一件事。
上下文切换成本很高。研究表明,当您被打扰时,大约需要23分钟才能重新专注于某件事。想象一下,您推动分支进行合并。您开始另一个任务。您花了15到20分钟才能进入。在您进入区域后的一分钟,您会从前一个任务的20分钟的CI构建中收到“构建失败”通知。您回来修复它。您再按一次。您来回走动很容易超过20分钟。

每天一次或两次将20分钟乘以团队中开发人员的数量……这是浪费很多宝贵的时间。

现在想象一下反馈在3分钟之内到来。而且您知道会的。您可能根本不会启动新任务。您将有证据支持你再次阅读您的代码,或者在等待时检查PR。失败的通知将会到来。您将修复它。然后继续下一个任务。这就是您的流程应启用的焦点。
保持CI的构建时间短,这是一个折衷方案。在CI范围内运行时间更长或几乎没有价值的测试应移至CD步骤。是的,那里的故障也需要修复。但是,由于它们不会阻止任何人做他们的事情,因此您可以在完成工作后将这些修补程序作为“下一项任务”。只需在工作时关闭通知并不时检查即可。保持上下文切换到最小。

持续交付和部署是工程问题
让我们解决一下定义,以消除这些障碍。
持续交付是指能够随时部署任何版本的代码。实际上,它是指代码的最新版本。您不会自动部署,通常是因为您不必或不受项目生命周期的限制。但是只要有人愿意,就可以在最短的时间内完成部署。有人可以成为想要在暂存或预生产环境中进行测试的测试/ QA团队。或者实际上可能是时候将代码推向生产了。
连续交付的想法是准备与您要在环境中运行的东西尽可能接近。如果使用Java,则可以是jar或war文件,如果使用.NET,则可以是可执行文件。它们也可以是已转译的JS代码的文件夹,甚至是Docker容器的文件夹,无论使部署变得更短(即,您已尽可能预先构建)。
通过准备这些脚手架,这通常是一些脚本和执行时间。准备方式:

运行所有测试,以确保代码一旦部署便可以正常工作。如果可以自动执行单元测试,集成测试,端到端测试,甚至性能测试。

这样,您可以过滤主分支的哪些版本实际上已准备好生产,哪些尚未准备就绪。理想的测试套件:

  • 确保应用程序关键功能正常工作。理想情况下,涵括所有功能
  • 确保没有引入性能破坏因素,因此当您的新版本受到众多用户的欢迎时,它就有机会持续生存
  • 空运行您的代码避免需要的任何数据库更新,以免出现意外

它不需要非常快。30分钟或1小时是可以接受的。
持续部署是下一步。您将代码的最新版本和生产就绪版本部署到某些环境。如果您足够信任CD测试套件,则是理想的生产方式。
请注意,根据上下文,这并非总是可能或值得付出。持续交付通常足以提高生产力。特别是如果您在封闭的网络中工作并且环境有限,则可以部署到该环境。也可能是软件的发布周期阻止了计划外的部署。
持续交付和持续部署(从现在起将它们称为CD)不是团队问题。他们的目的是在执行时间,维护工作和测试套件的相关性之间找到合适的平衡点,以便能够说“此版本可以正常工作”。这是一个平衡。如果您的测试持续30个小时,那就有问题了。有关Oracle数据库测试套件的外观,请参见这篇史诗般的帖子如果您花费大量时间使测试与最新代码保持最新,从而阻碍了团队的进步,那也不是一件好事。而且,如果您的测试套件几乎没有任何保证……那基本上是没有用的。

在理想的世界中,我们每次向主分支提交都需要1组可部署的工件。您可以看到我们有一个垂直的可扩展性问题:我们从代码转移到工件的速度越快,我们就越准备好部署最新版本的代码。

有什么大不同?
持续集成是一个水平可伸缩性问题。您希望开发人员经常合并其代码,因此检查必须快速。理想情况下,几分钟之内就可以避免开发人员始终通过CI版本的高度异步反馈来切换上下文。
您拥有的开发人员越多,则在所有活动分支上运行简单检查(构建和测试)所需的计算能力就越高。

良好的CI构建:

  • 确保没有将破坏基本内容并阻止其他团队成员工作的代码引入主分支
  • 足够快,可以在几分钟内向开发人员提供反馈,以防止任务之间进行上下文切换

持续交付和部署是垂直可伸缩性问题。您需要执行一个相当复杂的操作。

良好的CD发布:

  • 确保尽可能多的功能正常运行
  • 速度越快越好,但这不是速度问题。30至60分钟的构建就可以了

一个常见的误解是将CD视为诸如CI之类的水平可扩展性问题:从代码移至工件的速度越快,实际处理的提交越多,并且越接近理想的情况。但是我们不需要。尽可能快地为每次提交生产脚手架通常是过大的。您可以尽最大的努力很好地使用CD:拥有一个CD构建,它将在给定构建完成后立即选择最新提交进行验证。
毫无疑问CD真的很难。获得足够的测试信心才能说您的软件已准备好自动部署,通常可以在诸如API或简单UI之类的底层应用程序上使用。在复杂的UI或大型整体系统上很难实现。

结论
用于执行CI和CD的工具和原理通常非常相似。但是目标是非常不同的。
持续集成是在反馈给开发人员的反馈速度与执行的检查(构建和测试)的相关性之间做出的折衷。没有任何妨碍团队进步的代码可以进入主分支。
持续交付部署是要进行彻底检查,以发现代码问题。检查的完整性是最重要的因素。通常以测试的代码覆盖率或功能覆盖率来衡量。尽早发现错误可以防止将损坏的代码部署到任何环境,并节省测试团队的宝贵时间。
​​​​​​​精心设计CI和CD版本以实现这些目标并保持团队的生产力。没有工作流程是完美的。问题会时不时地发生。每次使用它们时,都可以将其作为学习的经验教训来加强您的工作流程。