写点什么

我在实施蓝绿部署后遇到的问题和解决方法

作者:Sarah Saunders

  • 2023-01-31
    北京
  • 本文字数:4200 字

    阅读完需:约 14 分钟

我在实施蓝绿部署后遇到的问题和解决方法

前几周,我被迫拒绝“批准”了 GitLab 项目的合并请求。我不喜欢他们提出的解决方案,即,对我们的应用程序代码库进行特定的更改,以支持蓝绿发布。它向我发出了一个代码更改的警告:将部署与代码绑定了;在环境应该是不可见和可互换的情况下,以编写代码来支持环境。创建这些类型的依赖将我们与特定的平台和发布方法绑定了,而额外的代码会导致各种可能的缺陷和错误,这些缺陷和错误可能会因环境而异,因此极难测试。

 

这是怎么发生的呢?它有一个非常有趣的背景,并且这样的事情非常普遍。这一切都是从一个愿望开始的,即改进发布,从而更频繁地将变更引入到生产环境中。

 

我们团队的应用程序相对现代化且灵活:托管在 Docker 容器中,并能自动部署到云上,单元和组件测试根据更改运行,一旦通过了全套的自动化测试并满足了代码质量标准,部署就可以自动继续。我们有一个“发布”的概念,即部署到云环境中的多个服务的构建构件的标签集合。

 

然而,将这些构件移动到“更高的环境”中(例如预发布环境、生产环境)需要停机时间来重新启动所有服务,并且必须安排在非工作时间,而且发布要由单独的团队来执行。如果我们希望运行某些类型的更新(例如,对 Liquibase 来说过于复杂或缓慢的数据库更改),则需要手动执行步骤,因此,这些发布窗口虽并不频繁,但对团队来说却很痛苦。更不用说那些令人筋疲力尽的反社会工时制了。总的来说,一个好的改进候选项和蓝绿发布应该要能有助于消除其所需的加班和停机时间。

 

简而言之,蓝绿部署的概念是同时运行(至少)两个应用程序实例。当发布新版本时,它只能发布到一个(或一些)实例上,而让其他实例仍在旧版本上运行。一开始可以完全限制对这个新版本的访问,然后可能会发布给一部分消费者,直到对新版本产生信任为止。此时,可以逐渐限制对运行的旧版本实例的访问,当然也可以升级这些实例。这为用户创建了一个零停机时间的发布。

 

当然,也有需要注意的地方。对数据源或 API 的任何破坏性更改都意味着旧版本的请求不能被新版本处理,这就排除了蓝绿发布的可能性。这是我最喜欢问的面试问题之一,问一个人如何在蓝绿环境中处理破坏性更改,以避免有人提出了一个很好的解决方案,但它可能会涉及一些定制的路由层来丰富或调整“旧”请求以适应“新”系统。在这一点上,你必须考虑一下,保留一些旧版本的停机时间是不是更好。虽然大多数软件团队都在尽最大努力避免破坏性更改,但破坏性更改通常是不可避免的。

 

所以,让我们假设一下最好的情况,我们没有任何的破坏性更改。我们还假设,就像我的项目一样,我们正在将 Docker 容器直接部署到云服务上——一个Azure应用服务,而不是Kubernetes或另一个支持自动扩缩和路由的 PaaS 层。那么,我们该怎么做呢?

 

我们的架构由许多微服务组成的,这些微服务通过 REST API 进行通信,并作为单独的构件进行部署。但是当前所有的构件都在一个 Git 存储库中,并在单个版本中同时部署。假设我们有两个运行 1.0 版本的微服务 A 和微服务 B,以及一个包含 A 接口的新版本(2.0 版),该接口将由 B 中的新方法调用。假设我们在生产环境中部署了负载均衡的 2 个 A 实例和 2 个 B 实例;对于蓝绿来说,每个实例都将迁移到新版本上。

 


你可以立即看到问题所在:2.0 版本的 B 实例只能调用 2.0 版本的 A 实例。如果它被定向到 1.0 的端点,则无法找到所需的新功能。由于这种特定的路由要求,服务 B 不能使用它从服务发现中所获取的负载平衡端点来调用服务 A,而是需要特定的“绿”实例地址。

 

我们团队也面临着同样的情景。来看看我们可以用的解决方案。

按依赖顺序发布

 

在调用 API 的功能之前发布 API。在上面的例子中,如果我们为微服务 B 做了一次蓝绿发布,检查它是否正常,然后确保微服务 B 的两个实例都迁移到了 2.0 版本,那么之后我们就可以安全地对微服务 A 做蓝绿发布。

 


这种模型是一种适应增量式、非破坏性 API 更改的良好且简单的方式,尽管它必然会导致更多的发布,因为在发布下一个服务之前,每个依赖项都需要就位。这确实让回答“我们线上有什么版本?”这个问题变得更加困难。你的标签版本跨越了多个微服务版本。但这确实是微服务、部署复杂性和计算效率之间的权衡。微服务架构意味着,如果系统的某个特定部分需要用更多的资源,你可以只水平扩展该部分,而不必扩展整个系统,但随后你必须要单独管理所有部分的生命周期。

 

API 调用中的版本控制

 

有几种方法可以将版本控制引入到 API 调用中。例如,一种直接的方式是在 RESTful 端点的实际 URL 中放入一个版本。另一种方式是尝试使用 HTTP 头等元数据来表示版本控制;然而,这只适用于你能控制所有服务的服务内通信时。否则,你不能指定服务请求必须包含的版本控制信息。

 

如果我们的 API 端点是版本化的,这对我们的发布有何帮助呢?它将允许我们的服务 B 的 2.0 版本管理任何 HTTP 404“URL 未找到”响应,如果它碰巧向服务 B 的 1.0 版本实例发送了一个 V2 请求,并且它将允许服务 A 托管端点的 V1 和 V2,那么它就可以在前一个版本仍然存在时继续服务。一旦每个服务都迁移了,这将会导致一些工作,如管理和清理服务 B 中的 V1-mitigation 代码。

 


依赖基础设施

 

云原生选项。我们的团队将应用程序部署到 Azure。如果你要问 Azure 是如何做蓝绿发布的,他们会向你介绍他们的Azure Traffic Manager产品。这是一种基于 DNS 负载均衡的解决方案,提供了一种加权轮询路由方法。权重可以用于逐渐向新迁移的服务器上引入流量,你还可以添加规则,以确保“蓝”服务器只路由到其他“蓝”的服务器,从而将你的蓝环境和绿环境分开。这确实是有成本的,尽管成本不是很高。

 

回到我们的具体问题。我们还没有构建版本化的 API,正如我前面提到的,我们目前在一个版本中部署所有的微服务。我会将我们的服务归类为微服务,因为它们可以单独部署和扩展,但我们的发布过程有效地将它们合并到一个 BBOM(Big Ball Of Mud,大泥球)了。

 

对于选项三,如果没有 Azure Traffic Manager(这被认为过于昂贵),当“蓝”前端向后端微服务发送请求时,我们的团队无法检查或强制执行,它将调用“蓝”后端。这意味着,除非我们首先从后端传播更改(这并不总是可行,特别是当蓝和绿共享同一个数据库时),否则我们将面临路由无法处理请求的风险。让我非常畏缩的一个解决方法是:包含一个可以设置为蓝或绿的配置变量,然后在来自前端的请求中设置一个 HTTP 头,通过指定该变量来在应用程序代码库中有效地重新创建 Azure Traffic Manager 功能。哎唷。

 

代码可以在生成路由 URL 时使用这个 HTTP 头/配置变量作为标志,以决定是通过绿服务器还是蓝服务器来生成路径。因此,例如,“注销”链接将在前端配置中指定 2 个配置变量:一个用于绿,一个用于蓝,允许根据服务器“颜色”生成不同的注销链接......吃饱撑的吗?

 

我们团队知道这是一种创建蓝/绿发布流程的糟糕方式,它们是被预算和时间压力这两个常见的恶魔所逼迫的产物。我们的要求是在一个月内创建一个蓝绿部署流程,并且不使用 Azure 云原生服务,考虑到我们的起点,我们的选择非常有限。但是我们应该早点看到它的到来,例如,当我们一开始知道我们要构建 API 时,就应该考虑到 API 版本控制。

 

我们陷入了“DevOps 鸿沟”,因为我们有两个优先级不同的团队,一个开发团队的首要任务是尽快将更改引入到发布管道,而另一个 WebOps 团队的首要任务则是确保云平台的可重复性和安全性。当有人提出构建微服务的请求时,开发团队认为 WebOps 团队会管理蓝绿发布之类的事情,并没有停下来考虑他们应该如何构建解决方案来帮助他们。由于这样的疏忽,它最终会反噬,从而伤害我们。

 

那么我们现是做到什么地步了呢?目前,我们还没有使用硬编码版本的蓝绿发布;正如我所预测的那样,当我们尝试使用我们构建的流程时,我们会发现一些非常严重的路由缺陷。我期待的是,我们最终能改用 Azure Traffic Manager。到那时,我们就会开始将我们的“微服务大球”分解为多个部署管道,这样我们就可以计划一个自下而上的新变更发布了。在我们最初的示例中,我们的第一个版本将服务 A 升级到 2.0,以在 API 和数据库中可以使用新的端点字段,然后第二个版本则是更新服务 B,以调用服务 A 的新端点。

 

对我们来说,这是一个非常有价值的学习过程:让开发人员和 WebOps 团队更紧密地联系在一起,并与发布团队更密切地合作,以了解我们是如何帮助他们的。当技能组合不同时,人们很自然地会将他们认为属于其他人的任务委派给其他人(例如,负载均衡应用程序实例将委托给理解 Azure 云概念和各种模板语言的人来编写基础架构代码),但我们已经学会了分解这些任务,以便双方都能理解对方在做什么,从而帮助发现整个流程中的问题。

 

经验教训

 

总之,我们从早期的蓝绿设置尝试中学到了很多东西。

变革架构

 

我非常反对“面向未来”的应用程序。如果没有性能问题,请不要构建缓存。如果你没有删除内容的要求,那么就不要执行删除。你对需求的猜测很有可能是错误的。

 

然而,你应该从一开始就让这些未来的变更变得可行且容易。这意味着在构建整体应用程序设计时,你应该考虑如何在数据库级别实现更改,以及如何向 API 中添加版本等。

不要为了微服务而微服务


微服务不必是设计的默认设置。如果你的架构中没有契合点,也没有比其他架构更容易被大流量冲击的点,并且如果你的组件只是彼此通信,而且部署在相同的近似位置(例如,相同的云或相同的数据中心),那么你可能无法从微服务架构中获得很大的收益。

 

通过减少移动部件的数量以及减少组件调用之间的网络延迟,你可能能从简化部署中获得更多的好处。不要只是随大流,要好好思考你想要实现的目标。

注意团队边界


对于任何需要一起协作的团队,无论是用户体验设计师和开发人员、业务分析师和 QA,还是开发人员和运营团队,我们都需要意识到项目中风险最大的领域是团队之间的边界。

 

每个团队都会一直在做假设,例如,开发人员会假设用户体验设计师正在提供有效的 HTML 原型;业务分析师会假设 QA 团队已经根据文档化的需求进行了自动化测试;运营团队会假设他们已经收到了应用程序依赖项的通知。每当两个团队开始协作时,最好使用一些技术来消除这些假设,例如,你可以从领域驱动设计中获取一些工具,并运行事件风暴事件研讨会。

 

在一个项目中,越早将这些假设作为风险项提出,事情就会越好,也就越安全!

 

原文链接:

https://www.infoq.com/articles/blue-green-deployments/


相关阅读:

亚马逊云科技为蓝绿及金丝雀策略引入 CloudFront 持续部署

部署策略对比:蓝绿部署、金丝雀发布及其他

2023-01-31 08:008813

评论

发布
暂无评论
发现更多内容

2022南京14届-物联网-博览会

InfoQ_caf7dbb9aa8a

在线SVG在线编辑器

入门小站

工具

如何使用参数化查询提高Cypher查询的性能

华为云开发者联盟

参数化 Cypher查询 华为云图引擎 GES 参数化查询

Apache ShenYu源码阅读系列-Divide插件

子夜2104

设计消息队列存储消息数据的 MySQL 表格

「架构实战营」

react源码解析7.Fiber架构

buchila11

React

“一只股票一张表”, TDengine 在青岛金融研究院量化分析场景中的应用

TDengine

数据库 tdengine 物联网

云效 Projex是什么?Projex企业级高效研发项目管理平台

阿里云云效

阿里云 项目管理 研发 敏捷研发 项目协作

Retool 是什么,怎么样? —— Retool 低代码工具测评

蒋川

低代码 低代码开发平台 retool

读《Software Engineering at Google》(02)

术子米德

架构师成长笔记

Python 中的鸭子类型和猴子补丁

AlwaysBeta

Python

2022南京14届-智慧工地-博览会

InfoQ_caf7dbb9aa8a

Linux驱动开发-编写RFID-RC522射频刷卡模块驱动

DS小龙哥

4月月更

区块链一周热点回顾|虎符元宇宙建筑Hoo HQ已对外开放体验

区块链前沿News

虎符交易所

linux之chattr命令

入门小站

如何做好复盘

Hockor

复盘

健康码如何影响世界

王字 Wannz

小程序 微信 finclip 凡泰极客 健康码

自己动手写Docker系列 -- 5.6实现删除容器

Go Docker 4月月更

jackson学习之七:常用Field注解

程序员欣宸

4月月更

生于彼,长于此:狗形机器人的中国情缘

脑极体

[Day12]-[动态规划]-零钱兑换

方勇(gopher)

LeetCode 数据结构和算法

2022南京14届-人工智能-博览会

InfoQ_caf7dbb9aa8a

【PIMF】开源鸿蒙首款IDE低代码入门OpenHarmony应用开发

离北况归

低代码 OpenHarmony Openharmony啃论文俱乐部 OpenHarmony应用开发 可视化界面

云图说丨不同区块链之间如何跨链交互?

华为云开发者联盟

区块链 跨链 可信 可信跨链服务 跨链交互

龙蜥社区成立DeepRec SIG,开源大规模稀疏模型深度学习引擎

OpenAnolis小助手

深度学习 开源 龙蜥社区 sig 稀疏模型

坐实大数据资源调度框架之王,Yarn为何这么牛

华为云开发者联盟

大数据 hadoop mapreduce YARN 资源调度框架

读《Software Engineering at Google》(01)

术子米德

架构师成长笔记

腾讯一面:你平时怎么排查并调优慢 SQL 的

老周聊架构

MySQL 4月月更

react源码解析8.render阶段

buchila11

React

Docker 实战教程之从入门到提高(二)

汪子熙

Docker 容器 虚拟化 docker image 4月月更

为什么要进行数字化转型

王字 Wannz

数字化生态 数字化转型 finclip 小程序容器

我在实施蓝绿部署后遇到的问题和解决方法_DevOps & 平台工程_InfoQ精选文章