如果您上次更新 IT 安全标准是在五年或更久以前,那么它们很可能与当今 DevOps 和站点可靠性工程 (SRE) 实践不符。一个特别棘手的话题是在生产环境中进行测试——以及因此使用生产数据进行测试——因为 DevOps 和 SRE 模糊了生产环境和非生产环境之间的界限;什么是测试,什么不是测试。
为了澄清一些困惑,我们将深入探讨以下问题
- 为什么我们要分离开发/测试系统和生产系统?
- 我们应该按照生产系统的高标准管理什么?
- 为什么在生产系统上进行测试风险如此之高?
- 为什么我们应该在生产环境中进行测试?
- 生产数据又该如何处理?
- 我们如何才能降低在生产环境中进行测试的风险?
我应该注意到,这是一篇观点文章;它基于多年的 DevOps 和测试集体经验,但不应被解读为 IBM 的官方声明。
为什么我们要分离开发/测试系统和生产系统?
至少从合规性和风险管理的角度来看,区别对待开发、测试和生产系统是标准做法,主要是因为它们具有不同的安全性、数据和隐私控制。让我们退后一步,思考一下对这些部署环境采取不同态度的历史原因。
我们的生产系统是最重要的,因为它们运行着我们的业务和政府部门。这些系统为我们的客户服务,并对客户满意度产生直接影响。开发人员的工作环境偶尔“崩溃”几个小时是很正常的,但我们必须按照无可挑剔的质量、可靠性和可用性标准来管理生产系统。这就是为什么限制生产系统的风险至关重要。DevOps 和 SRE 仍然侧重于规避风险,但与其他实践(如 ITIL)相比,它们使用不同的降低风险策略。
此外,生产系统是特殊的,因为它们可以访问生产数据。生产数据必须是可靠的真相来源,因此我们必须保护它免受损坏。生产数据也可能包含我们只能与授权用户共享的信息,例如机密或个人数据,因此我们必须确保它受到生产级身份验证和授权的保护。最后,我们可能需要维护对生产数据的访问审计跟踪(创建、读取、更新和删除),这对于开发/测试系统是不需要的。

生产系统受到更严格的控制和监控,这是有充分理由的。
我们还需要对生产系统的当前状态有出色的可见性和控制力。我们仔细监控它们,以便快速检测问题,并且当问题发生时,了解这些系统的当前配置可以更容易地快速恢复。大多数人不会关心开发人员是否更改了他们个人笔记本电脑上的配置设置,但我们将生产系统锁定到已知配置,并实施安全的变更控制。无论我们是通过变更控制数据库还是基础设施即代码来锁定配置,目标都是相同的:可见性和控制。
最后,请记住,我们以不同的方式管理开发/测试和生产系统,因为存在专门针对生产系统的合规性规则和法规。没有什么比对我们的开发/测试环境施加不必要的负担更能扼杀速度了!
我们应该按照生产系统的高标准管理什么?
当我们开始思考在生产环境中进行测试时,我们很快意识到我们是从一个假设开始的:应该很容易确定什么是生产环境,什么不是生产环境。但是,正如大多数假设一样,我们错了。开发人员和测试人员希望快速行动;当有疑问时,我们倾向于将系统归类为开发/测试而不是生产,这样我们就无需处理生产系统管理开销。但是,我们如何知道何时需要实施生产控制?这并非完全是非黑即白的,但有几个考虑因素。
一些更明确的例子:我们可以同意,开发人员的笔记本电脑和专门为测试设计的环境(例如,集成测试、系统测试、性能测试)不是生产系统。此外,普遍的共识是,使用真实数据为真实客户提供服务(直接或幕后)的系统是生产系统。还有一些系统我们仅在内部使用,但对于公司运营至关重要,因此也被视为生产系统。

现代软件开发和交付实践可能会模糊开发、测试和生产系统之间的界限。
但是,通常,“生产”和“非生产”之间的界限取决于您的独特情况以及您对这些术语的使用
- 暂存
- 预生产
- 预上线
- 预览
例如,您的暂存环境可能是您仅针对其运行测试的环境,在这种情况下,它更像是一个测试系统。另一方面,您的暂存环境可能是您的业务合作伙伴在您发布新 API 之前用于测试新 API 的环境。在这种情况下,您应该像管理生产系统一样管理它,在大多数意图和目的上都是如此,因为您希望它模拟这些 API 的真实用户体验。也许您可以容忍该类型服务器更多的停机时间,但您应该使用生产质量的身份验证和授权;您应该对服务器配置进行控制,并且应该像生产系统一样监控服务器。
内容管理系统的预览环境是另一种听起来像一种类型但实际上是另一种类型的系统示例。预览内容尚未发布。也许它也对时间敏感,例如未发布产品的网站。在发布公告后,有人会将新产品的网页发布给全世界观看;但在发布之前,它们是高度机密的。因此,预览环境必须具有比生产环境更严格的身份验证和授权控制。除非当前用户有权查看预览页面,否则不得呈现预览页面。
我们也应该像对待生产系统一样对待这些系统
- 蓝/绿部署。为什么?未获得流量的备份环境可能随时成为生产环境。
- 高可用性配置中的备份服务器。为什么?备份服务器可能随时开始为生产流量服务。
- 金丝雀部署。为什么?这些服务器为一小部分生产流量服务。
- 分阶段发布。为什么?所有版本的硬件和软件都在为生产流量服务,因此都“在生产环境中”。
- A/B 测试服务器。为什么?即使名称中带有“测试”,这些服务器也在为生产流量服务。
在将规则和启发法应用于系统和环境时,保持一致性非常重要。您不应将暂存环境一天视为生产系统,第二天又视为测试系统。那是灾难的根源。确保每个人都了解哪些系统是生产系统,哪些不是,然后记录您团队的决策和任何例外情况。
努力了解哪些系统是生产系统,哪些不是生产系统,并对其进行适当处理,将确保您在不损害开发和测试速度的情况下保护您的生产系统。
为什么在生产系统上进行测试风险如此之高?
当人们说“不要在生产环境中测试”时,是因为他们想避免几种可能的(坏)结果
- 损坏或无效的数据
- 泄露受保护的数据
- 不正确的收入确认(取消订单等)
- 系统过载
- 对其他生产系统产生意外的副作用或影响
- 高错误率,触发警报并呼叫值班人员
- 倾斜的分析(流量漏斗、A/B 测试结果等)
- 充满脚本和机器人活动的不准确的流量日志
- 不符合标准
为什么我们仍然应该在生产环境中进行测试呢?
是的,在生产环境中测试是有风险的,但我们仍然应该这样做,而且不应仅在罕见或特殊情况下才这样做。这些在生产环境中进行的测试在 DevOps 和 SRE 社区中被认为是最佳实践
- A/B 测试和实验
- 可用性测试和 UX 研究
- 蓝/绿部署的最终冒烟测试
- 功能标志
- 分阶段发布
- 金丝雀测试
- 健康检查和其他生产系统监控,包括脚本化的健康测试
- 网页的视觉回归测试,以比较暂存版本与生产版本
- 可访问性回归测试(在初始测试和部署之后)
- 扫描网页以查找断开的链接并报告错误的脚本
- 真实用户监控
- 混沌工程
- 故障转移测试
- 高可用性/灾难恢复计划的其他测试
- 漏洞赏金计划
生产测试帮助我们
- 防止糟糕的部署破坏生产系统
- 客观地识别哪些用户体验更有效
- 设计更令人愉悦的用户/站点交互
- 逐步推出新功能
- 快速获得有关我们最新更改成功或失败的反馈
- 在用户注意到问题之前发现问题
- 了解网页性能特征和更改影响
- 构建更具弹性的系统
- 提高系统质量
通过在部署时或按计划频率运行多种类型的生产测试,我们可以涵盖各种关键的非功能性需求
用户体验 | 可用性 | 发布更改 | 反馈 | 质量 | 性能 | 弹性 | |
A/B 测试 | ✔ | ✔ | |||||
可用性/用户体验 | ✔ | ✔ | ✔ | ||||
冒烟测试 | ✔ | ✔ | ✔ | ✔ | |||
功能标志 | ✔ | ✔ | ✔ | ||||
分阶段发布 | ✔ | ✔ | ✔ | ||||
金丝雀测试 | ✔ | ✔ | ✔ | ✔ | |||
健康检查 | ✔ | ✔ | ✔ | ||||
回归测试 | ✔ | ✔ | |||||
断链检查器 | ✔ | ✔ | |||||
真实用户监控 | ✔ | ✔ | ✔ | ||||
混沌工程 | ✔ | ✔ | ✔ | ✔ | |||
故障转移测试 | ✔ | ✔ | ✔ | ||||
高可用性/灾难恢复测试 | ✔ | ✔ | ✔ | ||||
漏洞赏金 | ✔ | ✔ | ✔ | ||||
渗透测试 | ✔ | ✔ | ✔ |
各种类型的生产测试的目标
……以及一个异常值(因为难道总会有一个问题儿童吗?):第三方渗透(“pen”)测试。我们应该在生产系统上进行吗?一方面,这无疑是有风险的;例如,如果渗透测试人员发现注入漏洞,您最终可能会损坏数据库中的数据。另一方面,黑客可能每周都在您的面向互联网的系统上运行渗透测试套件。因此,无论您是否批准,渗透测试都在您的许多生产系统上进行。这就是为什么我将其包含在此生产测试列表中的原因。我有两条建议
- 确保您聘请的渗透测试人员正在使用类似生产环境的环境,而不是玩具环境。
- 针对您的测试系统运行最流行的安全测试套件,并在其他人针对您的生产系统运行相同的测试之前修复您发现的任何错误。

您的生产系统需要能够抵抗黑客攻击并优雅地处理这些攻击。
最后,您是否注意到这些在生产环境中进行的测试有一些共同之处?它们都没有制作生产数据的“测试副本”。它们都直接在真实的生产系统和数据上运行。
生产数据又该如何处理?
这是一个捷径:开发/测试环境可能不需要特殊的测试数据。它们通常可以使用任何人都可以访问的生产数据,例如实际的网页内容,只要您的测试不会修改该数据,从而节省您创建测试数据的时间和费用。上一节中的所有生产测试都属于这一类,许多 Web 服务和 API 也是如此。
但是要当心!仅仅因为数据在互联网上可用或 REST API 可以免费使用,并不意味着您可以将其用于您的开发/测试目的。在您获取和使用开放数据之前,请务必了解并遵守任何适用的许可协议和网站使用协议。
如果您可以通过使用生产数据来节省时间和金钱,那就太好了,但是您的某些应用程序和服务需要修改您的数据存储,因此您将需要也修改数据的测试。在不损坏生产系统的情况下在生产环境中运行这些测试是很难做到的。面对这种现实,当为了验证测试场景而必须修改数据存储时,大多数开发团队选择使用不同的数据源:一个用于开发/测试,一个用于生产。但是,您如何设置足够真实和完整的测试数据以进行良好的测试呢?
如果您的生产数据库足够小,您可以在技术上制作它的副本,然后对其进行测试,但是将生产数据复制到开发/测试环境是有问题的,因为它可能会绕过安全和隐私控制。(GDPR,有人吗?)
让我们举个例子。您已经到位了您精心设计的安全和隐私控制措施。您设置了您的生产系统,以便只有“需要知道”的人才能访问任何个人数据;您知道您的数据存储在哪里;您已经建立了一个按需从您的系统中删除个人数据的流程;等等。也许您的数据库中有客户地址和电话号码。如果有人将数据库复制到开发/测试系统,而您没有在那里实施您的安全和隐私控制,那么您的系统就会出现漏洞。如果客户行使其“删除权”并要求您删除他们的地址和电话号码,您将如何知道需要更新哪些开发/测试系统以删除该信息?如果开发人员的笔记本电脑或带有个人数据的测试移动设备被盗了怎么办?您是否需要报告并减轻安全漏洞?为了堵住这些漏洞,您需要将个人数据排除在您的开发/测试系统之外,或者将有权访问个人数据的开发/测试系统纳入您的生产数据合规范围。

用链条锁住您的笔记本电脑和手机不是最好的计划。假设这些设备最终会被盗,并决定如何相应地管理它们。
显而易见的替代方案是为开发/测试环境使用模拟数据,但是决定何时使用模拟数据进行测试是很困难的,因为创建和维护模拟数据既费时又容易出错。如果您从生产数据库开始并手动清理它以模糊或删除敏感数据,您可能会遗漏一些东西。如果您清理得太过分,您可能会损坏数据或限制其测试实用性。相反,如果您从头开始构建测试数据库,则很难创建您需要包含在良好测试套件中的所有排列和边缘情况。
只有您和您的队友才能决定哪个方向适合您的独特目的,但以下是一些将有所帮助的注意事项
- 在使用生产数据之前,请了解您的生产数据上有什么控制措施,并尊重这些控制措施。
- 确保您的整个团队就敏感数据和个人数据的含义达成一致。
- 定义并获得您处理敏感数据和个人数据的协议的认可。
- 记录并了解您的系统中的敏感数据和个人数据。确保您的开发人员和测试人员确切了解他们使用的敏感数据和个人数据。
- 如果您决定清理生产数据以删除个人或敏感信息,请确保清理数据的过程本身不是安全/隐私/合规性漏洞。考虑使用第三方清理和消毒软件,因为它比自制解决方案更不容易导致错误。
我们如何才能降低在生产环境中进行测试的风险?
“不要在生产环境中测试”这句格言的目的是保护我们的生产系统。现在我们已经确定我们可以而且应该每天在生产环境中进行测试,我们如何保持生产系统的安全?

制定测试计划并在将新组件投入生产之前完成它。经过充分测试的代码不太可能在生产环境中失败。
首先也是最重要的,在进入生产环境之前,使用自动化测试彻底测试所有系统。我坚信 100% 的自动化单元测试覆盖率,单元测试与它们验证的代码更改在同一个更改集或拉取请求中。您应该在进入生产环境之前完成多个测试层:功能/行为测试、集成测试、部署/配置测试、可访问性测试、安全测试和高可用性故障转移测试。如果您正在逐步推出新功能,也要测试推出过程。是的,我也相信手动测试,但绝不能取代自动化测试!
那么在生产环境中进行自由形式的测试呢?两个词:小心谨慎。例如,“错误狩猎”日是一种最佳实践,您可以要求团队中的每个人花费一定的时间尝试查找软件中的错误。这些活动既有趣又富有成效……只要您设置了适当的护栏。与您的团队一起审查在生产环境中进行测试的风险,并教导您的错误猎手他们不应该做什么,例如使用他们的个人信用卡下订单并立即取消订单。这些类型的测试会干扰收入确认和订单统计。
此外,不要手动重新配置您的生产系统,无论是出于测试目的还是任何其他原因。手动更改会使您的系统处于未知状态,并且可能很难将其恢复到已知配置。使用基础设施即代码(Chef、Helm 等)和/或发布管理和编排工具(如 IBM UrbanCode Deploy 或 Kubernetes)来管理生产系统的配置。
在进行任何混沌工程之前,请确保您已根据 混沌工程的基本原则计划了实验
- 计划实验
- 控制爆炸半径
- 扩展或压缩
您还可以通过满足以下先决条件来降低混沌工程的风险:可靠的自动化测试覆盖率、良好的监控和警报、具有快速自动化故障转移的高可用性设置,以及一个随时待命并在服务级别目标 (SLO) 内准备好恢复服务的团队(如果发生故障)。在我的团队中,我们通常在周末与值班的开发人员一起运行每个组件的第一个故障转移测试,并且团队在通过第一组测试后“毕业”到在正常工作时间内测试弹性。

不要让混沌工程、可扩展性或性能测试在您的系统中引起一系列问题。松耦合的组件、良好的错误处理和计划的故障模式有助于隔离故障。
在计划可扩展性和性能测试时,请确保您不会影响您的客户。不要向您的生产系统抛出一堆 API 请求并抱最好的希望。如果成本效益分析证明是合理的,请使用单独的隔离环境。如果您需要在生产环境中测试可扩展性或性能,请在监控系统的同时逐步增加流量,并在服务中断或故障之前停止。并且不要忘记从您的生产分析中过滤掉可扩展性/性能测试流量!
这些降低风险的技术将帮助您保持生产系统的弹性,并降低因在生产环境中进行测试而导致故障的可能性。
结论
在生产环境中进行测试在现代软件工程、IT 运营和 IT 安全中非常有价值,并且是一种最佳实践。生产测试帮助我们
- 防止糟糕的部署破坏生产系统
- 客观地识别哪些用户体验更有效
- 设计更令人愉悦的用户/站点交互
- 逐步推出新功能
- 快速获得有关我们最新更改成功或失败的反馈
- 在用户注意到问题之前发现问题
- 了解网页性能特征和更改影响
- 构建更具弹性的系统
- 提高系统质量
因此,我们不应避免在生产环境中进行测试;相反,我们应该了解固有的风险,并在我们的系统中构建安全措施来解决这些风险。我们还应该更新我们的安全和合规性标准,以将现代生产测试实践考虑在内。
感谢 Devopsdays Charlotte 的“在生产环境中测试”开放空间的与会者,他们共同集思广益并提炼了我们对“测试”和“生产”这两个术语的真正含义,以及我们真正需要做些什么来保护我们的生产系统。我还想感谢 Craig Cook 和 Jocelyn Sese 对本文早期草稿提供的有益反馈。
4 条评论