CI/CD管道中共享公共任务是什么?
发表时间:2023-08-29 15:02:22
文章来源:炫佑科技
浏览次数:196
菏泽炫佑科技
CI/CD管道中共享公共任务是什么?
发展概况
当它在 2019 年秋季发布时,立即引起了人们的关注,因为它迎来了“CI/CD 平台的第三次浪潮”。 从可重用的开源构建块构建可组合管道的独特方法显然在提高 CI/CD 管道操作的效率和维护方面具有巨大潜力。 然而,尽管该平台的设计具有内在的吸引力,但许多组织,尤其是已经构建了 CI/CD 系统的大型企业,对于冒险尝试犹豫不决,这是可以理解的。 在某种程度上,这是由于平台处于起步阶段的局限性,例如企业内部执行和共享的限制。
幸运的是,自*初版本以来,已经采取了一些步骤来消除企业使用可维护性的障碍。 此后不久,引入了自托管,这是在现有企业内部网络中执行作业的基本功能。 随后,2021 年 11 月, 发布,极大扩展了交付可重用管道的能力,减少了重复步骤和样板代码量,缩小了与许多更成熟的 CI/CD 产品的差距。 真正让此功能为企业采用做好准备的是 2022 年 1 月宣布的内部共享操作的能力,这使得平台工程团队能够打包和发布常见的可重用步骤,而无需将其暴露给外界。 *后,我们认为有能力成为企业 CI/CD 生态系统的基础。
我们为什么去
近年来,我们投入了大量精力来改善 CI/CD 工具的开发体验,包括自动化从模板快速生成应用程序管道的经过验证的黄金路径。 尽管如此,我们在提供平衡一致性和灵活性的平台方面遇到了限制。
我们当前系统的缺陷之一是共享 CI/CD 管道中的常见任务。 我们的共享脚本存储库提供了有限的封装,并与应用程序的构建历史记录混淆,将来自实际应用程序存储库的提交与来自共享任务存储库的提交混合在一起。
在升级管道模板时,我们保留用户自定义的能力也有限。 如果我们在模板中引入新步骤或修复错误,开发人员将必须重新生成整个管道才能接受更改,这将删除他们所做的所有自定义。
*后,还有一个不太明显的因素可以*大限度地减少开发人员使用 CI/CD 系统的障碍。 随着我们的技术组织进入增长期,随着新开发人员的涌入,提供一个平台来帮助这些开发人员快速启动和运行并满足他们的期望变得势在必行。 在*近和*近的调查中,大多数开发人员回答说他们使用 . 考虑到它在开源社区中的地位,这并不奇怪。 通过扩展平台原生 CI/CD 功能的使用,我们看到了以下机会:
总体而言,该平台的设计借鉴了现代开发方法。 开发人员可以使用可复用的组件灵活构建管道,将团队在开发活动中使用的开源思维转移到CI/CD管道中。 然而,随着我们对生态系统的深入研究,CI/CD 的处理方式出现了一些显着的差异,这促使我们重新思考之前做出的一些假设,并制定一个新的策略,将限制变成优势。
术语速览
在系统内部,有几个术语由于在 CI/CD 生态系统中广泛使用而可以具有不同的含义,但在框架内,它们指的是特定资源(即“工作流”、“作业”、“操作”、“事件”和“”)。 如果您不熟悉定义,那么我建议您快速浏览一下文档。
工作流程可视化(来源:)
改变主意
过渡时要理解的首要区别之一是存储库和管道工具之间的关系。 我们一直使用的 CI/CD 产品与应用程序的存储库集成,尽管本质上是分开的。 即使是 CI/CD 领域的其他工具,可能会为整个应用程序生命周期提供更全面的解决方案(通常将存储库、管道和其他交付工具捆绑到单个产品中),但往往会提供更多高级构造,例如“项目”或“应用程序”,明确区分存储库和管道,使它们相对平等。 当 CI/CD 流程开始时,所有注意力都会转向管道工具视图。
相反,使用 ,存储库仍然是宇宙的中心。 平台中触发的工作流程主要存在于存储库的上下文中。 这种方法有优点也有缺点。
优势
缺点
制定使用策略
现在,了解了这个观点及其优点和缺点后,我们可以开始制定有效使用该平台作为 CI/CD 解决方案的策略。 以下是指导我们决策的一些关键原则。
优先选择拉取请求批准而不是工作流程批准
CI/CD 平台的主要关注点之一是有效收集和显示输出,并对这些结果执行质量控制。 此前,我们一直使用许多组织熟悉的流程:
以前的方法:存储库和管道检查是分开的
在这种方法中,推送到目标分支会触发管道。 管道在一系列阶段中执行,每个阶段都会输出一些结果,并通常根据这些结果评估工件的生产准备情况。
我们的新目标是使这些信息更接近自然开发活动,同时注意结果和工件显示方式的一些固有限制,因此我们希望有一种更好的方法来提供这些控件,而无需拉取请求功能是合乎逻辑的选择。 拉取请求维护更长的审核历史记录(与工作流执行的保留时间限制相比),并且讨论集中在更改本身,并且代码可供参考。 使用拉取请求作为主要审批仪表板需要架构的转变,拉取请求收集相同的结果并执行相同的质量检查,但不需要额外导航回存储库来查看相关更改。
新策略:从拉取请求中收集必要的信息
制定可重用组件指南
构建可重用管道片段的 DIY 库也会带来许多问题。 我们如何处理共享工作流程和操作的更新? 如果我们想要平衡多个团队,使用略有不同的方法来完成看似相同的任务,那么什么级别的抽象是合适的?
面对这些挑战,我们的目标是实现一系列“铺好的道路”,其中每个新存储库都应该能够使用我们团队支持的模板、操作和可重用工作流程进行部署,但可以根据需要灵活地进行自定义。 这为持续交付指令奠定了基础,使存储库始终处于可部署状态。 为了实现这一目标,我们制定了一些准则。
推送所有版本的语义版本标签
维护准确的版本使用户能够根据其可接受的风险级别保持更新。 在我们之前的 CI/CD 工具中,共享任务是从存储库的 分支中提取的,这意味着我们需要非常小心,不要引入无意的更改。 虽然支持这种用法,但*好使用语义版本范围来在保持*新和避免重大更改之间取得平衡。 我们在这里学到的一个重要教训是确保为每个版本推送/更新多个标签(主要、次要和补丁标签),确保关注主标签(如“@v2”)的用户也获得新的补丁版本。
像管理任何其他 API 一样管理您的界面
在向内部团队提供资源时,很容易陷入这样的陷阱:假设他们比开源项目或外部供应商更了解内部工作原理。 这很快就会导致抽象泄漏,从而降低所提供的共享组件的价值,因为用户除了了解如何与其 API 交互之外,还必须承受额外的认知负担。
为了保持更一致的封装水平,我们的目标是明确我们的和输出,尽量减少假设和对环境副作用的依赖。 从那时起,我们一直在尝试提供一个合理的默认值,以便用户可以专注于提供大多数用例所需的值。 *后,如果使用环境变量,我们建议尽可能缩小其范围。
例如,如果某个环境变量仅在一个步骤中使用,则在该步骤中声明;如果在多个步骤中使用,则在作业中声明;*后,如果在多个作业中使用,则在工作流程中声明。 这是一个通用的、独立于平台的建议,旨在降低意外变量修改或命名冲突的风险,并通过将信息保留在靠近使用位置的位置来提高可读性。
专注于工作流程
在一个生态系统中,人是*受关注的; 毕竟,产品都是以他们的名字命名的。 然而,在铺好的道路上,操作只不过是砖块。 它们非常适合将流程分解为功能步骤,但是,为了向内部交付团队提供*大价值,平台工程师应该投入同样多的时间来开发将这些步骤联系在一起的可重用工作流目录。 可重用的工作流程确保不同的步骤按所需的顺序执行,并简化设置和拆卸活动。
例如,我们的团队创建了一个将容器部署到环境的操作。 为此,需要提供环境元数据作为输入的一部分。 为了更好地管理调用此操作的活动,我们使用工作流来执行一些附加步骤、收集所需的元数据、执行部署,然后将结果添加到输出中。 但我们发现此工作流的代码在许多不同的情况下都会重复 - 对于不同的触发事件,以及不同的部署环境(开发、暂存、生产等)。 为了进一步*大化重用,我们将这些工作流程重构为单个可重用工作流程CI/CD管道中共享公共任务是什么?,该工作流程根据触发事件确定正确的目标和镜像上下文。
进一步重用:合并 3 个几乎相同的作业...
进入可重用的工作流程
降低使用第三方的风险
的文档提供了一些很好的安全强化通用指南。 其中有警告称“从互联网上的第三方存储库获取操作存在重大风险”。 为此,他们提供了有关将第三方操作版本锚定到提交 SHA、审核操作源代码以及仅使用您信任的创建者的操作的指导。
这给我们带来了一些困难,因为我们习惯于由软件组合分析(SCA)工具自动提供适当外部组件的风险(漏洞/权限)信息,这使我们能够更广泛地在应用程序开发活动中应用它成分。
重新手动检查所有外部操作可能会严重限制开源市场的实用性,而在我们的旅程开始时,开源市场就曾有过这样的承诺。 随着供应链攻击的增加,保护管道变得至关重要,但是手动检查操作的源代码和创建者的方法无法扩展,因为我们的团队可能对给定操作所使用的语言没有深入的了解,并且当它来自单个用户的贡献,创作者的可信度很难评估。
*近,宣布了对警报的支持,这是朝着正确方向迈出的良好**步。 然而,这仍然不如我们希望的那么安全,原因如下:
生成的警报很大程度上依赖于创建者自己报告的漏洞。 在个人提供的小型业务中,尚不清楚他们可以提供什么级别的报告。
仍然没有风险基线评估——当用户浏览市场时,没有现成的数据可以让用户了解操作中现有的漏洞或创建者的漏洞管理流程。
还存在有人故意将恶意代码嵌入到操作中的风险(如果他们是原作者,则在创建操作时,或者更隐蔽地通过供应链攻击),这种方法无法捕获此类恶意代码。
*后,当前许多公司在依赖管理方面的*佳实践是在内部托管一个存储库并代理到其他主要公共存储库(NPM、Maven、PyPI 等)。 对于公司产品使用的依赖项,有一个内部缓存,可以在依赖项来源无法访问时帮助确保业务连续性。 现在,运营同样重要,因为它们对工作流程至关重要,任何中断都可能会花费开发人员大量时间。
为了解决上述限制,我们开发了一种使用现有工具并结合设置中的控件的方法,以尝试在风险和开发速度之间取得平衡。 首先,我们允许任何内部写操作和任何写操作。 下一个一般控制是允许经过验证的创建者列表,并允许来自我们已建立信任关系的组织的所有操作。 *后,我们有一个针对较小的、未经验证的第三方的个人行为的允许列表。
为了加快这些操作的审批流程自动化软件开发,我们利用现有的 SCA、SAST 和容器安全扫描工具来扫描操作的存储库和/或容器映像,从而暴露任何潜在的漏洞。
在某些情况下,我们使用的*后一种技术是将操作存储库的副本分叉或导入到企业自己的存储库中。 这提供了三个保证:
如果需要,总是有可用的代码;
可以修改代码以更好地匹配我们自己的用例;
您可以确信任何更改版本引用的尝试(例如更改标签)都不会影响我们。
当然,我们正在不断努力将源存储库中的任何有用的更改或修复合并到我们自己的版本中,因此在使用这种方法时需要进行权衡。
他们的路线图中还计划继续提高运营安全性。 显然,这是一个不断发展的领域,我们希望平台和解决方案生态系统的进步将减少我们对自行开发的评估流程的依赖。
扩展您的基础设施实践以跟上需求
随着平台应用范围的扩大,提高性能和可靠性已成为人们关注的焦点。 我们根据从运营使用中吸取的重要经验教训扩展了我们的战略。
通过自托管增强弹性
与许多企业一样,为了满足需求并帮助管理成本,我们大量使用自托管,使作业能够与内部网络上的资源进行通信,以便我们可以更好地管理镜像工具和设置。
尽管依赖自托管,但我们希望与使用托管实例的体验保持一致,即在作业启动时准备就绪(*大限度地减少等待可用的作业的排队时间),并将它们视为一次性临时实例,*大*小化先前执行留下的更改将影响下一个作业的幂等性的可能性。
这次,我们维护一个一次性热池 - 当一项新作业启动并获取时,我们使用一个热池来启动下一个作业。 这样,池始终能够处理当前的工作负载。 此外,我们还在每个工作日开始时用默认分配预先填充池(然后在晚上将其关闭),并随着使用量的增加而扩大该池。
使用缓存来缩短构建时间
如上所述,我们的工作是一次性的,我们为每项工作提供一个干净的运行时。 虽然这在构建一致性和隔离方面带来了明显的好处,但这也意味着生成的任何文件都不能被后续作业使用,除非使用此类功能直接共享它们。 我们必须克服的主要挑战之一是花费大量时间来重建现有资产。
幸运的是,当需要共享大量很少更改的数据(例如应用程序依赖项)时,可以提供多种缓存功能。 我们需要解决的三种*常见的情况是共享应用程序工件、容器映像和操作映像。
**种情况涉及应用程序工件和作业之间使用的依赖关系。 在这种情况下,我们使用缓存操作快速提高了工作流程的性能。
容器镜像(包括常用的基础镜像层)是第二常见的情况。 为了缓解频繁重新拉动常用镜像的问题,我们研究了受支持的镜像。 我们在大多数映像构建任务中使用这些选项。 在测量了内联缓存、GHA(缓存)和注册表缓存的不同选项后,到目前为止,我们在容器注册表 (GHCR) 托管的注册表缓存方面取得了*大的成功。
*后,*棘手的部分是操纵镜子。 需要理解的一个重要概念是,每次使用打包为图像的操作时,您都在使用它们从头开始构建的版本(除了在 Hub 中使用公共图像之外,还有另一种选择,但我们不想公开发布内部操作,所以这是不可行的)。
为了减轻这种痛苦,我们遵循常见的图像*佳实践,使图像尽可能小。 但是,我们也在考虑将一些作业作为容器化操作从执行中拉出,并将相同的逻辑打包为预构建的独立映像,然后将作业配置为在该映像中运行。 然后该作业将执行一个脚本。 该脚本通常用作操作,其行为与在本地作为操作运行时非常相似。 这样做的好处是我们可以拉取镜像,而不是每次都重建每一层,这使得我们可以在启动期间预先拉取常用的镜像,并在工作流程开始之前缓存它们。
即将推出
虽然我们提高了运营组合和工作流程的质量和效率,但我们面临的主要问题之一是在应用程序部署和运营阶段保持敏捷性和可见性。 我们*初的部署方法是使用自定义操作将变量替换为参数化模板,*终形成适用于我们环境的完整清单。
这给我们的团队带来了很大的负担,因为我们需要使用复杂的逻辑来处理各种部署样式、重试和部署失败恢复以及清理过时的部署。 部署问题也变得更难以排除故障,因为包含所有变量的*终清单在部署后不会保留在任何地方。 这也意味着回滚或升级工件需要重新调用整个过程。
为了应对这些挑战,我们再次着手研究如何重塑部署策略以利用 CI/CD 平台。 重申上面的一些经验教训,我们认识到我们需要一个解决方案:
至此,熟悉这个概念的读者可能会开始理解我们的想法了。 在建议的部署策略中,运行时状态在 Git 存储库中声明,并由环境中运行的代理自动拉取和协调。
转向部署模型需要采用新技术和行为模式,但这使我们能够利用开源社区专家优化的部署和编排逻辑,并维护干净、持久、受版本控制的环境更改历史记录,清晰的路径(拉取请求)可以轻松更改版本并在需要时保留批准记录。 这一切都基于开发人员现有的熟悉程度,正是这种熟悉程度吸引了我们。
我们正处于这一转变的早期阶段,但很高兴采取下一步行动,为我们的客户提供更好、更可靠的价值交付方式。
原文链接: