Adobe 用 Argo 高级部署模式的最佳实践
关注公众号并添加到“星标⭐”,防止错过消息
后台回复【资料包】获取学习资料
作者:Ionut-Maxim Margelatu
译自:https://u.kubeinfo.cn/vLS4u7
几年前,Adobe 采取了一项战略举措来拥抱 Kubernetes,帮助工程师开发和发布可跨云移植的应用程序。团队已经接受了 K8s,并且看到了可扩展性和可用性的提高以及成本的降低。随着时间的推移凸显出副作用,我们已经看到大量的 CI/CD 技术被使用,以及大量的本地代码,所有这些都用于处理部署基础设施。
为了减少技术蔓延并允许工程师加速其他计划,Adobe 正朝着使用基于 Argo 项目的 CI/CD 通用平台的方向发展。选择它主要是因为:项目的模块化、对 Kubernetes 的原生支持、浅的学习曲线和易于设置。
我们的团队是 Spinnaker
的长期用户
Spinnaker 是一个开源 CD 软件平台,可与 Kubernetes、Google Cloud Platform、AWS、Microsoft Azure 和 Oracle Cloud 配合使用。它主要是一个部署和交付平台,用于获取工件并将其部署到生产中。Spinnaker 的仪表板和界面都非常易于使用。开发人员可以轻松地将他们的代码推送到发布分支,该工具会自动构建、测试、验证并将代码推送到生产环境。借助 Spinnaker,你可以使用 Seamless Kubernetes、 Github 和 Google 的云构建集成,轻松交付、部署对软件的更改。
多年来,我们依靠它为众多项目构建了持续部署管道。但在此过程中,我们也遇到了一些挑战。当 Adobe 决定在 Argo 之上构建 CI/CD 平台时,我们抓住了改用 GitOps 和 Argo 的机会。主要原因是 GitOps 附带的自我修复选项(我们过去曾受此影响)以及使用原生 K8s 对象而不是使用 Spinnaker API 和 UI 所带来的复杂性降低。
然而,我们转向 Argo 并非没有挑战。我们不得不将我们的思维方式转变为一种新的范式:GitOps
,并适应 Argo 的实现。例如,Argo 不提供开箱即用的自动升级或自动回滚。以前,我们认为这些功能是理所当然的。现在,我们必须使用 Argo Workflows 调整和实现这些功能。
提升和回滚
因此,我们构建了一个工作流,可以自动将提交从 Dev 提升到 Stage 以及从 Stage 到 Prod。提升的决定是基于健康检查和测试结果的,后者是在 PostSync hook 上执行的:
https://argo-cd.readthedocs.io/en/stable/user-guide/resource_hooks/
每个环境的部署逻辑都非常简单:
工作流通过提交新的应用程序版本来促进对环境的提交 然后,工作流触发 Argo 应用程序的同步,并等待同步成功完成,以确保 Argo 应用程序状态是健康的 PostSync 钩子触发一个 Kubernetes 作业,该作业针对更新的环境执行一套功能测试 如果作业成功完成,Argo 应用程序的同步将成功返回,工作流将进入下一个环境
在每个环境都成功更新的理想情况下,结果将是刚刚部署的应用程序版本将已为每个环境提交。
那么如果在部署过程中出现问题怎么办?这就是自动回滚发挥作用的地方。
假设部署管道在 Dev 中成功部署,但在 Stage 中失败,因为测试失败。回滚就是恢复两个提交:一个用于 Stage,一个用于 Dev。
那么这是怎么发生的呢?正如我们之前提到的,测试是在 PostSync 挂钩上执行的。如果测试失败并且运行它们的作业未成功完成,则同步阶段将失败。反过来,这将使我们的工作流程中的同步和等待任务失败。此时,工作流也将被视为失败。
那么回滚什么时候发生呢?我们使用了一个退出处理程序,它在工作流完成时被调用,无论成功与否。退出处理程序检查工作流状态;如果失败,它会检索工作流所做的所有提交并还原它们。
即使持续部署管道
包含质量门和功能测试
预览环境
即使持续部署管道包含质量门和功能测试,正在部署的更改也有可能(即使不太可能)包含难以发现的错误。即使是最短的故障也可能对关键应用程序(例如数据收集)产生巨大影响。那么,我们如何进一步确保将失败的风险降到最低呢?
我们多年来一直使用的一种模式是为每个打开的 PR 创建预览环境。那么这是如何工作的呢?
这很简单,首次打开 PR 时,我们构建代码,然后将 PR 代码部署到专用的按需环境中。环境是部分或完全隔离的,这取决于应用程序的性质。它允许我们在考虑合并代码之前单独验证 PR。
渐进式部署
预览环境和部署后测试相结合,可以进行可靠的验证。我们甚至可以在合并到主线之前部署代码并自动对其进行测试。然而,有时会出现错误场景,甚至是验证只能在现实环境中随着时间的推移才能完成。那么我们如何处理这些情况并进一步降低失败的风险呢?想到的第一件事是使用带有 Argo Rollouts 的渐进式部署。
这包括逐步向 prod 环境推出,推出步骤由验证和分析控制。例如,我们可能会路由功能测试以针对金丝雀副本运行,并使用它们来验证金丝雀部署
这适用于公开 HTTP API 的应用程序。对于流式应用程序,我们可以进行分析
并根据处理指标决定是否提升金丝雀。或者我们甚至可以将两者结合起来。
Wave 部署
在 Adobe 中,许多服务部署在全球各地。例如 Experience Platform Edge Network 部署在七个地区。
如果出现应用程序缺陷,一次在所有区域部署边缘服务可能会产生重大影响。难以发现的问题可能潜伏在代码更改中;如果更改在整个应用程序部署中同时推出,这可能会带来灾难。
那么我们如何减小爆炸半径呢?按顺序部署远非理想,因为它会使部署不必要地冗长。解决方案是分波部署。也就是说,将部署拆分为多个波次,其中每个波次包含一个或多个地理区域。
如果第一波成功,您可以继续在其他地区进行第二波部署,依此类推。通过分波部署,您可以将功能测试和金丝雀分析未发现的错误的影响限制在最少的用户身上。如果发生故障,您可以回滚已部署的整个区域集。
你可以更进一步: 第一波可能包括一个dark launch
。我们在 Adobe 中做到这一点的方法是,我们使用一个不接收任何实际流量的 prod 配置将代码部署到一个专用的 pre-prod 环境中。环境接收由功能测试生成的合成流量,并用于在类似生产的设置中验证代码。
从持续部署退一步
我们是持续部署的大力支持者。事实上,我们多年来一直在成功地使用持续部署。它帮助我们更有信心地部署质量代码。它还帮助我们晚上睡得很好,因为这些年来我们发生的事件较少
。
然而,我们意识到持续部署并不适合所有用例。当持续部署对团队不起作用时,存在现实世界的场景。
可能是部署需要很长时间 可能需要缓慢地将金丝雀部署到生产环境以捕获关键业务指标 或者部署工作流需要执行许多任务
如果部署需要很长时间(例如 30 分钟或更长时间),则部署将排队。您不能期望开发人员等待数小时才能部署他们的更改。
可能是您有一个大型团队在处理单个 repo,并且向主线提交的频率很高。或者,业务环境可能要求部署遵循一定的节奏。比如说,每天甚至每周。
我们如何处理这种情况?在这些场景中,使用持续交付是更好的选择。它需要与持续部署模型一样的勤奋和对质量的重视,因为它要求构建可在任何时间点发布的工件,就像持续部署模型一样。不同之处在于您不会将所有更改都部署到生产环境中。部署到 prod 成为一个单独的操作,可以在以后采取,具体取决于团队的部署策略。我们探索的一种模式:
总结
通过采用这些实践,您可以构建稳定可靠的部署管道,从而使部署到生产环境没有什么特别之处。虽然从 Spinnaker 迁移到 Argo 并非没有挑战,但我们已经设法在 Argo 之上构建了同样强大的工作流程并进一步发展和优化。
- END -
推荐阅读
K8S 1.25 中的重大更改和删除14 张图详解 Zookeeper + Kafka on K8S 环境部署阿里开源K8S 本地调试工具包 kt-connect对象存储也可以通过 K8S API 管理了!
K8S 1.25 针对 Pod 又有了新的变化
史诗级整理 Jenkins 流水线详解
Helm 进阶到骨灰玩家,收藏版!
2.4W 字 Helm 从入门到专家
Docker 镜像构建保姆级入门实战指南
K8S 运维开发调试神器 Telepresence 实践指南12 图入门高性能分布式对象存储 MinIO
32 张配图详解 K8S 1.24 高可用部署,保姆级详细版!
Kubernetes 1.25 正式发布,所有变化都在这儿了
17 张图实战 + 理清 K8S 网络排错思路,硬核!16 张图硬核讲解 Kubernetes 网络模型K8S 的 TCP 数据包流量可视化超详细分布式对象存储 MinIO 实战教程