70+专家分享实战经验,2024年度AI最佳实践都在AICon北京 了解详情
写点什么

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

作者: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:008729

评论

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

人脸识别:现代科技与隐私保护的博弈

来自四九城儿

语义分割标注:从认知到实践

来自四九城儿

《流畅的Python》第二版上市了,值得入手么?

Python猫

Python

Matlab实现PCA算法

Shine

三周年连更

3月底JAVA面试太难,吃透这份JAVA架构面试笔记后,成功涨到30K

程序知音

Java java面试 java架构 后端技术 Java面试八股文

龙蜥社区 4 月度运营大事件回顾

OpenAnolis小助手

开源 运营 龙蜥社区 sig 月度回顾

智能公厕设备升级方案@光明源智慧公厕

光明源智慧厕所

智慧城市

SBOM喊话医疗器械网络安全:别慌,我罩你!Part Ⅱ

安势信息

网络安全 SBOM 开源组件 医疗器械 医疗网安

通过“群战”实现全民普惠,e签宝带来哪些思考?

ToB行业头条

编程界的新星 — Rust 凭什么被业界青睐(内附学习资源)

Greptime 格睿科技

rust 云原生 时序数据库 分布式时序数据库

连ChatGPT都不懂的五一调休,到底怎么来的?

禅道项目管理

程序员 GPT 调休

ShareSDK 抖音平台注册指南

MobTech袤博科技

云服务规划技术

阿泽🧸

云服务 三周年连更

大型水利投资集团,打造数智财资管理新范式

用友BIP

软件测试/测试开发丨Python装饰器常见报错信息、原因和解决方案

测试人

Python 软件测试 自动化测试 装饰器 测试开发

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

TakinTalks稳定性社区

【民生证券】敏捷转型大步迈进!民生证券敏捷实践培训圆满结束!

嘉为蓝鲸

敏捷转型 民生证券

苹果商店上架流程_App上架苹果流程及注意事项

雪奈椰子

Go 方法接收器:选择值接收器还是指针接收器?

陈明勇

Go golang 方法 三周年连更 方法接收器

开启云上高效开发新时代,华为云开发者日东莞站成功举办

华为云开发者联盟

云计算 华为云 华为云开发者联盟 企业号 4 月 PK 榜

LoRA: 大语言模型个性化的最佳实践

Zilliz

Towhee 大语言模型

Confidential Containers发布0.5.0版本,龙蜥将基于八大特性构建开箱即用的机密容器解决方案

OpenAnolis小助手

开源 云原生 龙蜥社区 机密计算 机密容器

如何进行带有透明压缩技术的SSD基准测试?

ScaleFlux

扩容 存储技术 压缩数据 固态硬盘 企业数据

从五一的旅游热潮看,该如何实现数字文旅的转型升级?

加入高科技仿生人

低代码 旅游业 数字赋能

程序员真的要失业了?新技术潮如何改变我们的职业生涯? | 社区征文

一道圣光

职业成长 ChatGPT 三周年征文

Bash 脚本中,特殊变量$0到底是什么?

wljslmz

bash Linux 三周年连更

Matlab实现神经网络

袁袁袁袁满

三周年连更

好玩的策略游戏:群星Stellaris+DLC

真大的脸盆

Mac mac游戏 科幻策略游戏 游戏推荐 游戏安利

多云管理的六大价值

穿过生命散发芬芳

多云管理 三周年连更

什么是对象存储?对象存储的原理是什么?有哪些开源的、非开源的对象存储服务?

Java架构历程

对象存储 三周年连更

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