设计和实施微软 DevOps 解决方案:AZ-400 考试指南(三)

原文:annas-archive.org/md5/eb2d156388068d02b11a808e92183ccf

译者:飞龙

协议:CC BY-NC-SA 4.0

第十章:整合持续测试

在前面的章节中,你了解了不同的技术,这些技术有助于提高你将变更交付到生产环境的速度。如果你已经在日常工作中使用这些技术,你会很快发现,这只有在你的工作质量足够高时才可能实现。如果你的工作质量不够高,你将面临许多故障或问题,最终用户也不会满意。要取得成功,提高变更的速度和提高工作质量必须齐头并进。要评估并提高工作质量,你首先需要知道什么是质量。这就是测试的作用所在。测试是报告软件质量的学科。

为了引入测试的主题,本章将首先讨论如何衡量软件开发的质量。之后,将深入探讨功能测试的主题。在本章的进展过程中,我们将探讨不同的测试策略,以确定需要哪些类型的测试,以及每种测试应使用多少次。之后,我们将逐一讨论不同类型的测试。你将了解它们的工作原理、测试内容以及每种测试的优缺点。最后,最后一部分将重点讨论如何利用你的管道生成和收集的所有指标和测试结果,持续报告团队工作的质量,甚至防止质量不足的变更传播到用户。所有这些都将帮助你保持软件的高质量,并使你能够自信地快速频繁地交付软件。

本章将涵盖以下主题:

  • 定义质量

  • 理解测试类型

  • 在管道中执行测试

  • 维护质量

技术要求

要实验本章中描述的技术,你可能需要以下一项或多项:

  • 一个具有构建和发布管道及仪表板访问权限的 Azure DevOps 项目

  • Visual Studio Code、Visual Studio 2019 或 Visual Studio 2022

  • Azure DevOps 的 Basic + 测试计划许可

  • 一个 SonarCloud 订阅

所有这些都可以免费获得,或在有限的试用期内免费提供。

定义质量

第一章中讨论的 DevOps 思维模式的主要目标之一是增加价值流向最终用户。为了做到这一点,软件必须频繁部署,甚至可能一天多次部署。要使频繁部署成为可能,有两个重要因素:自动化和质量。自动化在前面的章节中已经讨论过了,因此现在是时候转向质量的主题了。

一旦自动构建和发布流水线就绪,且更改开始以越来越快的速度流向生产环境,就该开始衡量这些更改的质量了。更重要的是,这使我们能够中止质量不够高的更改。

实际上,什么构成足够的质量可能因项目而异。在创建游戏时,一些小错误可能对用户造成困扰,但不会造成其他影响。而在为飞机或医疗用途开发软件时,一个错误可能会危及生命。在软件开发中,较高的质量通常更昂贵且/或需要更多时间。因此,我们在交付功能的数量和能够保证的质量之间存在权衡。每个项目都有不同的最佳权衡点。

在质量得以衡量之前,首先要确定如何衡量软件的质量。监控软件质量的常见方法是收集一个或多个度量。例如,可以决定每周收集五个度量值。随着时间的推移,将这些度量值绘制成图表,可以深入了解软件质量如何变化。一个例子可能像这里显示的图表那样:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_01.jpg

图 10.1 – 软件质量度量示例

接下来的部分讨论了几个度量示例。

质量度量

度量是捕捉某些内容的手段,这些内容通过数字来表示。在软件开发中,度量通常用于表示一个特定的质量方面,这个方面本身可能很难量化。例如,一段软件的质量可能很难单独描述。这一点对于质量变化的描述尤为明显。出于这个原因,我们通常会收集多个数字,综合来看它们能反映软件的质量。

需要意识到,度量是一个很好的工具,但应该谨慎使用。一方面,可能有比正在测量的度量值更多的因素影响软件的(感知)质量。另外,一旦人们知道某个特定的度量值被记录下来,他们可能会优化工作方式以提高或降低该度量值。虽然这可能在报告中显示出期望的数字,但并不一定意味着软件质量真正得到了改善。为了解决这个问题,通常会记录多个度量值。

一个广为人知的例子是在敏捷工作环境中使用故事点速度。记录团队的迭代速度,以观察其是否随着时间变得更加高效,这听起来很有效;然而,如果团队规模在每次迭代中都不同,那么这个度量可能就没什么用处,因为团队成员的出席情况会影响速度。此外,团队可以轻松地通过每次迭代时将所有估算值乘以一个随机数来伪造这个度量。尽管这样每次迭代的数字会增加,但它与团队的生产力增长并无关系。

进入到衡量软件质量的指标时,客观地衡量编写代码的质量可能会很困难。开发人员通常对什么构成优质代码有许多看法,讨论越多,团队越难达成共识;然而,当我们将注意力转向使用这些代码后产生的结果时,就更容易识别出可以帮助提供代码质量洞察的指标。

下面是一些例子:

  • 集成构建失败的百分比:如果代码无法编译或无法通过自动化测试,这表明代码的质量不足。由于测试可以通过构建流水线在每次推送新变化时自动执行,它们是判断代码质量的绝佳工具。而且,由于它们可以在将变更部署到生产环境之前执行并收集结果,这些结果可以用来取消那些质量不足或可能影响某些系统功能的变更,从而在发布流水线的下一个阶段前阻止这些问题。这种方式保证了只有质量足够的变更才会传递到下一个阶段。

  • 自动化测试覆盖的代码百分比:如果大部分代码都通过单元测试进行测试,这将提高软件的质量。

  • 变更失败率:这是指部署新版本代码后导致问题的百分比。一个例子是应用程序的新版本部署后,Web 服务器内存耗尽的情况。

  • 计划外工作的数量:在任何一段时间内必须执行的计划外工作的数量是衡量质量的一个重要指标。如果团队正在创建一个同时在运行的 SaaS 产品,那么就会有时间花费在运营职责上。这通常被称为计划外工作。计划外工作的数量可以反映计划工作质量的情况。如果计划外工作的数量增加,可能是因为质量下降了。计划外工作的例子包括现场故障事件、跟进警报、热修复和补丁。

  • 用户报告的缺陷数量:如果用户报告的错误数量增加,这可能是质量下降的迹象。通常,这是一种滞后性指标,一旦这个数字开始上升,质量可能已经在一段时间内下滑了。当然,这个数字增加可能有很多其他原因,比如新的操作系统,用户数量的增加,或用户期望的变化。

  • 已知问题的数量:即使发现或报告的新缺陷很少,如果缺陷从未被修复,并且已知问题的数量一直在缓慢增加,那么软件的质量将随着时间的推移而逐渐下降。

  • 技术债务的量:技术债务是一个术语,用来描述为短期利益(例如快速交付代码)而牺牲代码质量的后果。技术债务将在下一节中详细讨论。

测试是一项活动,旨在发现并报告软件的质量。测试结果(对质量的洞察)可以用来决定是否允许或取消某个更改进入下一个发布阶段。

在下一部分,将探讨质量的另一个维度:代码库中的技术债务量。

技术债务

技术债务是一个术语,用来描述为追求其他目标而牺牲代码质量所带来的未来成本。例如,为了加快新特性的交付,开发者可能选择快速扩展现有类并添加一些新方法。如果由此产生的类不符合面向对象设计原则,或者变得过于庞大,那么这个类可能会变得难以理解、维护或以后进行更改。术语债务意味着某种东西(时间、质量、注意力或工作)在解决方案中仍然欠缺。只要这笔债务没有偿还,你就必须支付“利息”,即所有其他工作的进度都会稍微放慢。

技术债务有许多形式,以下是一些示例:

  • 没有任何单元测试覆盖的代码,其中对该代码的实现进行更改时无法使用原始测试来验证

  • 没有以自解释的方式编写的代码,即没有使用有意义的变量和方法名称

  • 不遵循编码原则的代码,例如 KISS、YAGNI、DRY 和/或 SOLID

  • 类因为变量和方法太多而变得过于复杂

  • 方法因为语句太多(尤其是流程控制语句)而变得过于复杂

  • 在应用程序的不同部分之间存在循环依赖的类或命名空间

  • 不遵循应用程序架构设计的类

技术债务有许多形式,监督所有这些形式可能会让人感到艰难。因此,市面上有很多工具可以自动衡量代码库中的技术债务并报告它。处理这些问题的工具将在维护质量一节中讨论。

虽然技术债务通常被认为是一件坏事,但有时故意制造技术债务也可能有正当理由。就像常规债务一样,管理债务的规模并确保能够支付利息并偿还债务是非常重要的。

公司在初创阶段通常会承担技术债务,这往往是为了快速创建一个可用的解决方案而做出的有意识决定。虽然这个初始版本用于验证商业提案并吸引资金,但开发者可以通过重新实现或重构(部分)应用程序来偿还这笔债务。

另一个原因可能是市场机会或已提前几个月计划的重要商业事件。为了按时交付并满足截止日期,承担一定的技术债务可能是值得的。

然而,如果从未偿还债务,而只是随着时间推移不断增加更多债务,这也会增加隐喻上的利息,每次开发者需要进行更改时都需要支付。结果是,任何更改都将比上一次花费更多时间。如果这种情况开始发生,最终会不可避免地出现某个时候任何更改都不再值得进行,因为成本总是大于收益。在这一点上,项目或产品就失败了。

在谈论测试时,理解存在哪些类型的测试是非常重要的。下一节将深入探讨这个话题。

理解测试类型

在传统的软件开发中,测试通常在开发完成应用程序被声明为开发完成功能集被冻结或类似的情况下执行。在宣布开发完成后进行测试,通常会进入一个长时间的测试与修复 bug 往返周期。结果通常是,在上线后仍然发现许多 bug。

向左移动(Shifting left)是一个测试原则,指的是应该在开发过程的早期进行自动化测试。如果将与软件开发相关的所有活动绘制成从初始到发布的时间线,那么向左移动意味着将自动化测试活动更靠近初始阶段。

为了做到这一点,已经认识到许多不同类型的测试——例如单元测试、集成测试和系统测试。不同的来源可能会建议不同类型的测试,但这些是一些比较知名的类型。不管测试的具体名称是什么,从高度抽象的层面来看,它们通常被分为以下两类:

  • 功能测试:功能测试用于测试应用程序是否实际实现了所需的功能。

  • 非功能测试:非功能测试用于验证应用程序的其他期望属性是否得以实现,并确保没有出现不期望的属性。

这些类型进一步细分为更小的子类别,如下图所示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_02.jpg

图 10.2 – 理解测试类型

接下来的三节内容简要回顾了不同类型的功能性测试和非功能性测试。这是为了便于后续讨论在不同情况下选择哪种测试类型以及项目可能需要多少种测试。

自动化功能测试的类型

在谈论自动化功能测试时,三种最常用的类型是单元测试、集成测试和系统测试。这些测试类型可以从多个维度进行比较:创建测试所需的时间、执行测试所需的时间以及它们测试的范围:

  • 单元测试:单元测试是最快编写的,它们的执行速度非常快,通常在不到一毫秒的时间内完成。它们测试的是应用程序中最小的范围,通常是单个类或方法。这意味着,一旦编写完成,几乎不需要更改单元测试。对于许多系统来说,更有可能的是测试会被删除,而不是被修改。

  • 集成测试:集成测试需要更多的时间来编写,因为它们涉及多个必须设置以便协同工作的单元。这些测试的执行仍然应该很快,通常从不到一秒到几十秒不等。集成测试的测试范围更大,这意味着,作为回报,它们将覆盖更多的代码部分,更有可能检测到因更改而引入的缺陷。

  • 系统测试:系统测试测试的是一个完全组装并正在运行的应用程序。根据应用程序的类型,这些通常是 API 测试或自动化 UI 测试。由于这些测试依赖于已部署的系统运行,并且通常需要在数据库或其他持久存储中设置初始状态,所以创建这些测试需要大量时间。它们的执行时间很长,有时每个测试需要几分钟。与单元测试和集成测试相比,系统测试的可靠性较差且更脆弱。即使是接口的小改动,也可能导致一系列测试失败。另一方面,系统测试能够检测到单元测试和集成测试无法检测的错误,因为它们实际测试的是正在运行的系统。

重要说明

请注意,测试中拥有较大测试范围既有优点也有缺点。优点是它可以检测到许多错误。缺点是,当测试范围非常大时,测试失败只提供有限的关于错误发生原因的信息。此类测试失败通常需要比小范围测试失败更多的调查。

以下部分将更详细地探讨每种测试类型。

单元测试

单元测试用于测试单个单元的独立性。在面向对象编程语言中,这通常意味着为应用程序中的每个类编写一个测试类。为了实现完全的测试覆盖,测试类将为对应应用程序类的每个公共方法编写一个或多个测试。

单元测试应该运行得非常快——平均来说,应该在几毫秒内完成。为了实现这一点,每个类都是在没有其依赖项的情况下实例化的。这是通过使用接口来实现的,类依赖接口,而不是直接依赖其他类。在测试中,依赖项会被模拟类替代,如下图所示。左侧显示的是运行时配置,右侧显示的是测试期间的配置:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_03.jpg

图 10.3 – 接口测试

一个模拟类实现相同的接口,但默认没有任何行为。可以根据每个测试设置特定的行为。模拟还可以用于验证是否调用了依赖项上的某些操作或函数。举个例子,以下是一个 C#类:

public class WorkDivider
{
   private readonly IMessageSender _messageSender;
   public WorkDivider(IMessageSender messageSender)
   {
      _messageSender = messageSender;
   }
   public void DivideWork(IEnumerable<WorkOrder> workOrders)
   {
      foreach(var workOrder in workOrders)
      {
         _messageSender.SendMessage(workOrder.GetMessage());
      }
   }
}

要在自动化测试中实例化此类,需要实现IMessageSender接口。为了绕过这个依赖,可以使用像 Moq 这样的模拟框架来测试WorkDivider,如下所示。在这些示例中,NUnit作为测试框架:

[TestFixture]
public class WorkDividerTest
{
   private Mock<IMessageSender> _messageSender; 
   private WorkDivider _subject;
   [SetUp]
   public void SetUp()
   {
      _messageSender = new Mock<IMessageSender>();
      _subject = new WorkDivider(_messageSender.Object);
   }
   [Test] 
   public void
WhenSendingAnEnumerableOfWorkingOrders_EverOrderIsSendToTheMessageSender()
   {
      var workOrder = new WorkOrder();
      _subject.DivideWork(new[] { workOrder });
      _messageSender.Verify(x => x.SendMessage(workOrder), Times.Once);
   }
}

这意味着无法为与其他系统(如数据库、缓存或消息队列)交互的类编写单元测试。为了确保这不会使覆盖应用程序的大部分部分变得不可能,通常的做法是将与其他系统的集成隔离在单独的类中。这些类包含与远程系统的交互,但不包含业务逻辑,并且尽可能少的代码。然后,接受这些类不包含在单元测试中的事实。通常用于实现这一点的设计模式有外观模式(Facade)、适配器模式(Adapter)和仓库模式(Repository)。

提示

本章末尾附有更详细的关于编写单元测试和如何模拟类的指南链接。

单元测试应该能够在每个开发者克隆应用程序代码库的计算机上运行。它们不应要求在本地计算机上进行任何特殊配置或设置,并且应随时可以运行。这样,所有与代码库合作的人员都可以在本地计算机上运行单元测试。因此,开发者在推送更改到中央代码库之前,应该在自己的计算机上运行所有单元测试,这是一个很好的实践。

除了本地验证步骤,单元测试还应该成为持续集成构建的一部分。稍后你将学习如何在管道中执行测试的部分完成这一过程。只要拉取请求中有失败的单元测试,就最好不要将更改合并到主分支。这甚至可以通过使用 Git 仓库分支策略来实现,正如在第四章中讨论的,一切从源代码管理开始

在下一节中,自动化功能测试的讨论将继续进行,重点是集成测试。

集成测试

集成测试用于验证一组组件是否能正确地协同工作。这些测试有两个目的:

  • 增加应用程序中未被单元测试覆盖的部分的测试覆盖率,例如与其他系统交互的类。

  • 解决单元测试未覆盖的风险,并在各个组件与其他系统交互时,减少风险以验证正确的预期结果。

理解可能存在的集成风险可能比较困难。通常假设如果各个部分或组件按其规格工作,那么整个解决方案也必定能正常运作。然而,事实并非总是如此,很多问题在单元集成后才显现出来。为了更好地理解这个风险,假设有两个组件共同负责气候控制。一个组件通过摄氏度来测量温度,另一个则基于温度做出反应,期待输入的是华氏度。很快就会发现,尽管这两个组件按预期工作,交换数字并根据这些数字采取行动,但它们的组合并不会产生预期的结果。

集成测试,尤其是那些与其他系统交互的测试,将不仅比单元测试运行得更慢,而且通常需要更多的设置或配置。这甚至可能包括用户名、密码或证书等机密信息。为处理此类配置,可以在测试旁边创建一个设置文件,并在执行测试之前从中加载设置。每个开发人员可以创建自己的该文件副本,并使用自己的配置运行测试。

继续使用上一节的示例,假设实现了IMessageSender接口的MessageSender类需要一个连接字符串来执行工作。MessageSender的测试类可能如下所示:

[TestFixture]
public class MessageSenderTest
{
   private MessageSender _messageSender;
   [SetUp]
   public void SetUp()
   {
      var connectionString = TestContext.Parameters["MessageSenderConnectionString"];
      _messageSender = new MessageSender(connectionString);
   }
}

connectionString,用于构建MessageSender类,来自TestContext上的Parameters对象。这是可用的.runsettings文件。具体方法可能会因测试框架而异。一个示例的.runsettings文件如下所示:

<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
 <TestRunParameters>
 <Parameter name="MessageSenderConnectionString" value="secret-value" />
 </TestRunParameters>
</RunSettings>

将设置移到单独的文件中,确保机密信息不会被提交到源代码控制中。在在流水线中执行测试一节中,你将学习如何为在流水线中运行测试构建.runsettings文件。

这是因为,如果可能的话,集成测试也应该是持续集成构建的一部分。然而,这也存在一个风险,那就是可能会使持续集成构建变得过于缓慢。为了解决这个问题,可以实施以下解决方案之一:

  • 集成测试在与持续集成构建并行触发的单独构建中执行。通过这种方式,持续集成构建的时长保持较低,同时集成测试仍然会被持续执行,开发人员能够快速获得反馈。

  • 集成测试会在管道的后期执行,接近软件发布时执行——例如,在部署到测试环境之前或之后。

第一种方法的缺点是,以这种方式执行集成测试意味着测试将不再作为质量门控,在代码合并到主分支之前进行检查。当然,它们仍会继续作为质量报告机制工作。这意味着,虽然错误可能已经合并,但它们会被构建过程检测并报告。

第二种方法没有这种风险,因为执行测试仍然是从源代码管理到生产的管道的一部分;然而,在这种方法中,测试的执行可能会推迟到稍后的时间点,前提是并非每个构建都至少进入了部分发布管道。这意味着缺陷可能会稍后显现,从而延长了检测和修复问题之间的时间。

无论采取哪种方法,失败的集成测试将不再阻止合并更改,因此你必须找到另一种方式,确保开发人员会负责修复导致测试失败的缺陷。

这些权衡在系统测试中尤为明显,系统测试通常需要很长时间,因此无法将它们作为持续集成构建的一部分。

系统测试

第三种也是最后一种自动化功能测试类型是系统测试。这些测试是针对一个完全组装并正在运行的应用程序进行的。系统测试有两种类型,取决于应用程序的类型:API 测试或 UI 测试。系统测试可能需要很长时间来执行,而且常常有复杂的测试数据设置,导致测试时间超过一分钟。

提示

你可能会遇到一种叫做编码 UI 测试的东西。这是一个现在已经被废弃的微软解决方案,用于编写 UI 测试。这些测试可以从 Azure Pipelines 中执行。幸运的是,有许多替代方案,详见微软在devblogs.microsoft.com/devops/changes-to-coded-ui-test-in-visual-studio-2019中发布的弃用通知。

系统测试是在正在运行的应用程序上执行的,这意味着在运行之前需要进行配置和设置。应用程序需要在受控环境中运行,并且所有与数据存储的集成都需要完全正常运行。与其他系统的集成要么需要正常运行,要么需要用替代的模拟工具进行替换,以确保所有与这些系统集成的操作能够正常运行。

这些条件使得开发人员在本地机器上执行这些测试的可能性较低,特别是在他们修改应用程序时。只有在创建新测试或更改测试时,他们才可能执行这些测试。然而,即使在这种情况下,他们执行的测试可能并非针对本地运行的应用程序版本,而是针对已经部署到测试环境中的版本。这不一定是好事,但在大多数团队中往往是现实情况。

重要提示

创建 API 或 UI 测试的介绍不幸超出了本书的范围。市场上有许多产品可供选择,最佳的使用产品因项目而异。

在作为管道一部分执行系统测试时,它们通常是在代码至少部署到一个环境后进行的。这通常是测试环境。这意味着系统测试是从源代码更改到生产部署的关键路径的一部分。如果这个路径过长,它们也可以被移出管道。然后,它们按照计划运行——例如,每晚运行一次。就像集成测试一样,这加快了管道的速度,但也失去了将系统测试作为质量门的机会。

系统测试,特别是 UI 测试,通常是脆弱的,在进行微小更改后可能会停止工作。因此,建议将这些测试的数量保持在最低限度;然而,需记住,这些测试可以捕捉到特定错误,如配置错误、其他运行时错误、数据库与应用程序的不匹配或创建错误状态的操作序列。

除了自动化功能测试,还有手动功能测试,这在许多 DevOps 项目中具有价值。将在下一节讨论,但首先介绍一下不稳定的测试。

不稳定的测试

不稳定的测试是指在代码或配置没有明显变化的情况下失败,或者代码在本地机器上运行正常,但在持续集成时失败。经过多次重试后,测试最终会通过。

不稳定的测试是可靠性差的,会对构建质量信心产生负面影响。解决不稳定测试问题的一种方法是将这些测试静默处理,以便持续集成和发布不失败,同时将不可靠的测试结果从自动化测试报告中排除。

手动功能测试的类型

虽然自动化测试是一个快速且频繁获取开发反馈的好工具,但仍有一些内容需要手动测试。虽然自动化重复性测试是持续监控质量的最佳方式,但某些事情仍需要人工检查。

手动测试是向左 shift 的临界点。每当任何类型的测试或验证被 shift 到左侧时,意味着它是在执行手动测试之前进行的。这样做的好处是,这些自动化活动增加了我们对被测试版本的信心,提升了该版本也能通过手动测试的可能性。换句话说,当手动测试开始时,应该很不可能再发现任何新问题。

有两种类型的手动测试:

  • 脚本化测试

  • 探索性测试

这两种测试类型将在接下来的部分中讨论。

脚本化测试

脚本化测试是一种用于在确保全面覆盖所有相关测试用例的同时,最小化测试执行时间的技术。通过将测试分为两个不同的阶段:测试准备和测试执行,来实现这一目标。测试准备与待测试功能的开发并行进行,甚至在开发开始之前就已完成。在测试准备阶段,功能被分析并识别出正式的测试用例。

一旦必须执行的测试用例被识别出来,就会编写手动测试脚本,描述在后续测试执行阶段每个要执行的步骤。这些脚本的编写方式使得它们易于跟随,并且没有任何疑问或困惑的空间。它们的编写方式还确保执行步骤的数量尽可能少。虽然这可能需要更多的准备时间,但所有这些都是为了确保在测试执行过程中花费的时间尽可能少。

测试分析及如何识别测试用例的深入讨论超出了本书的范围。虽然你负责创建测试用例,但 Azure DevOps 会在这方面提供支持。通过使用测试计划服务,你可以创建测试计划并记录其中的测试用例,以便日后快速执行。

要创建新的测试计划,请执行以下步骤:

  1. 打开 Azure 测试计划菜单。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_04.jpg

图 10.4 – Azure DevOps 测试计划菜单

  1. 在此菜单中,点击测试计划。这里将展示你当前所有测试计划的概览。

  2. 点击新建测试计划按钮开始创建新的测试计划。这将打开一个新的对话框,如下所示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_05.jpg

图 10.5 – Azure DevOps 新测试计划

  1. 给测试计划命名一个有意义的名字,例如,能说明测试计划目的的名称。

  2. 将测试计划链接到正确的产品区域路径。

  3. 选择与此测试相关的正确迭代或冲刺。

  4. 点击创建以完成测试计划的创建。这将自动打开此测试计划,如下所示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_06.jpg

图 10.6 – Azure DevOps 测试套件

一个测试计划可以拆分为多个测试套件,而测试套件又可以拆分为子测试套件。从本质上讲,测试套件对于测试就像文件夹对于文件一样。通过点击测试套件上悬停时出现的省略号按钮,可以管理测试套件。这在前面的截图中有展示。

创建测试计划后,就该添加一个或多个测试用例到计划中。为此,请确保测试套件的定义选项卡已打开,然后点击新建测试用例按钮。一个新的弹出窗口将打开。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_07.jpg

图 10.7 – Azure DevOps 新建测试用例

在这里,可以定义测试步骤和预期结果。要定义一个新的测试用例,请执行以下步骤:

  1. 为测试用例输入标题。

  2. 在对话框中,输入一个或多个操作步骤和预期结果,以详细描述测试用例。

  3. 一旦测试用例完全描述,点击保存并关闭按钮以保存测试用例并返回到上一个屏幕,在那里你可以管理测试套件。

一旦准备工作完成,功能准备好进行测试,所有测试就会执行。由于所有测试都有详细脚本,这可以快速而高效地完成。甚至可能有开发人员、业务分析师或其他部门的人员参与测试执行。这意味着测试执行本身将非常快速。

要开始执行测试套件或计划,请执行以下步骤:

  1. 导航到执行选项卡。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_08.jpg

图 10.8 – Azure DevOps 执行测试用例

  1. 选择一个或多个测试用例。

  2. 选择右上角的一个运行选项。

选择针对网页应用程序运行测试时,会打开一个带有测试运行器的新浏览器窗口。此测试运行器可以用来逐个执行所有测试用例,对于每个测试用例,依次执行所有步骤,跟踪所有成功和错误,如下所示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_09.jpg

图 10.9 – Azure DevOps 测试用例步骤

每个测试步骤后的勾选标记或叉号可用于跟踪每个步骤的结果。如果某个步骤标记为不正确,可以添加一个带缺陷的评论。要将测试用例标记为通过或标记,可以使用右上角的蓝色下拉菜单。选择测试结果后,运行器会自动继续执行下一个测试。一旦所有测试执行完毕,可以使用左上角的保存并关闭按钮保存结果。

要查看测试运行的结果,导航到测试计划,然后点击运行以获取以下仪表盘:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_10.jpg

图 10.10 – Azure DevOps 测试运行

在这里,你可以选择你想查看结果的运行,以快速概览测试结果。在第二个标签测试结果中,可以查看所有测试用例的列表以及它们是否通过。

拥有详细脚本的一个主要好处是,可以多次执行相同的测试,从而降低每次执行的成本。如果一个测试计划执行多次,所有的运行历史记录都会被保存,并且可以通过前述截图中显示的视图访问。这对于将手动测试作为回归测试的一部分非常有用;然而,一旦情况变成这样,通常通过系统测试来自动化这些测试会更为有益,尤其是在可能的情况下。

提示

可以多次执行相同的测试,但针对不同的配置。当开发 Web 应用程序时,通常会使用不同的浏览器进行测试。对于桌面应用程序,这可能会用于测试不同的操作系统。关于配置的工作,微软文档中有详细说明,参见docs.microsoft.com/en-us/azure/devops/test/mtm/test-configurations-specifying-test-platforms?view=azure-devops

下一部分将讨论功能测试的最终形式,即探索性测试。

探索性测试

编写和执行详细的测试脚本可能会花费大量时间,既对测试工程师,也对测试执行者,因此这些测试通常会被自动化。一旦它们被自动化,就会归类为系统测试,特别是自动化 UI 测试。

这并不意味着手动测试完全没有价值或没有好的投资回报。有些东西是人眼能发现的,而计算机不能,例如不友好的用户界面、未对齐的界面元素,以及未完全显示但被其他元素遮挡的文本行或图像。

为了在不花费大量时间编写详细测试脚本的情况下捕捉这些错误,探索性测试可能是一个解决方案。在这种方法中,测试人员打开应用程序并开始调查他们认为在即将发布的版本中包含最大风险的应用程序部分。在探索应用程序的过程中,测试人员会记录他们访问了哪些应用程序部分,以及执行了哪些测试用例。与此同时,测试人员还会跟踪他们发现的新的风险或尚未执行的测试用例。通过这样做,他们在工作时创建了一个已覆盖和未覆盖的测试用例列表。这也使测试人员能够始终集中关注最重要的风险和测试用例。探索性测试完成后,测试人员可以报告哪些应用程序领域和测试用例已经覆盖,哪些没有,哪些风险完全没有被探索过。这份报告对产品经理来说可能是一个宝贵的输入,帮助他们决定是否继续发布。

一个常见的误解是,探索性测试意味着测试人员只是随便点击,以查看应用程序是否正常工作。事实并非如此,前面的段落已经说明,探索性测试是一项高度结构化的活动,且需要实践。如果操作得当,测试准备和测试执行将在探索性测试过程中交织进行。

当时间有限或可用的测试时间无法提前确定时,探索性测试是一项很好的工具。探索性测试可能会发现需要记录为缺陷的问题。接下来将讨论如何进行记录。

报告手动测试结果

测试的一项活动还包括报告发现的缺陷或其他问题。这通常是繁琐且耗时的工作。你必须尝试重新现现该问题,回忆问题是如何发生的,并记录下所有这些步骤。然后,还需要描述期望的和不期望的结果,拍摄截图,并将所有内容插入到缺陷追踪或工作管理工具中,例如 Azure DevOps。

为了简化这一过程,Azure DevOps 提供了一个Test & Feedback扩展。该扩展提供了按钮来录制截图或视频,并用文本或图形进行注释。一旦发现问题并通过录制或截图进行记录,它可以自动提交到 Azure Boards。

这个扩展可以免费从 Azure DevOps 市场下载,并可以在 Firefox、Chrome 和 Edge Chromium 中运行。该扩展的链接将在本章末尾提供。

重要说明

Test & Feedback 扩展可以在执行脚本化测试和进行探索性测试时使用。

这就结束了对不同类型功能测试的讨论。接下来的部分将帮助你决定在项目中使用哪种类型的测试。

决定需要哪些类型功能测试的策略

面对如此多不同类型的测试,哪种测试最适合你的项目?鉴于测试类型繁多且各自特性不同,答案正如你所料:它们的组合,因为它们各自有不同的特性。

以下图表显示了不同类型测试执行所需时间与它们提供的软件质量信心之间的关系。图表显示,尽管成功完成的手动测试最有可能识别缺陷,但它们也需要最长的执行时间。对于自动化测试,执行数万次单元测试所需的时间通常可以保持在几分钟内,而进行 10 到 100 次系统测试可能需要超过 30 分钟:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_11.jpg

图 10.11 – 质量信心与测试执行时间的关系

从这个权衡来看,通常可以理解为什么单元测试比集成测试更受青睐,集成测试比系统测试更受青睐,任何类型的手动测试都优于自动化单元测试。

提示

如果单元测试和集成测试的质量提高,那么这条线将进一步攀升到左上角。高质量的软件架构也有助于减少系统和集成测试的需求,并增加早期发现缺陷的机会,这正是单元测试的优势。自动化的单元测试和集成测试运行更快,结果一致,对整体构建质量产生积极影响。

对这种权衡的理解有助于理解两种可以用于决定测试策略的模型,即测试金字塔和测试奖杯,这将在接下来的两个部分中进行讨论。

测试金字塔

在许多旧项目中,自动化功能测试的数量并不多。通常,这些测试运行缓慢,测试范围大,难以维护,并且经常失败而没有明确的原因。这些测试所提供的价值通常非常有限。为了弥补缺乏良好的自动化测试,通常会有许多手动测试被用来在新版本部署之前进行完整的回归测试。这些自动化测试非常耗时,且很少执行。开发人员无法得到快速反馈,缺陷通常在较晚阶段被发现。在这种情况下,很难实践 DevOps,因为 DevOps 的重点是频繁且高频率地发布新版本。

这样的测试组通常被称为“冰淇淋锥形测试”,其中包括许多手动测试和少量自动化测试,而其中只有少数是单元测试。冰淇淋锥形测试是一种反模式,但在旧项目和/或长期运行的项目中经常出现。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_12.jpg

图 10.12 – 手动与自动化测试的测试金字塔

为了应对这一点,引入了另一个相反的模型:测试金字塔。这个模型主张拥有许多单元测试,可以在几分钟内提供关于应用程序质量的反馈,快速指出大部分错误。在此基础上,还可以叠加其他类型的较慢测试,以捕获前面层次无法捕获的错误。使用这种方法,可以在测试覆盖率和测试持续时间之间取得良好的折衷。

重要提示

请注意,测试金字塔并不主张分层方法。不要先构建一层单元测试,然后只有在所有单元测试完成后才进行集成测试。相反,它主张比例。你应该在单元测试、集成测试和系统测试之间保持健康的比例。

在不同类型测试之间找到最佳比例的一般建议非常困难。但在大多数项目中,金字塔中每个步骤的比例为 1:5-15 可能是合理的。

测试奖杯

尽管测试金字塔是一个广为人知且经常使用的分类测试和决定创建哪些类型测试的方法,但这种方法也受到了批评。虽然远离手动和系统测试在 DevOps 团队中被广泛接受是必要的,但并不是所有人都接受单元测试的重点。一些人反对测试金字塔暗示创建的单元测试数量比集成测试多得多。

这一反对意见的原因如下:

  • 单元测试部分的 WorkDivider 中,我们可以看到它依赖于了解 DivideWork 方法的实现方式。测试验证了实际的实现:对 SendMessage() 的调用。许多单元测试具有这种特点,因此增加许多单元测试会增加更改解决方案类级设计实现所需的工作量。

  • 单元测试的变动率通常比集成测试高。单元测试类与它们测试的类密切相关。这意味着如果测试的类被替换,该类的单元测试也会失去所有的价值。因此,有人认为集成测试可能会有更高的投资回报率。

  • 真正的价值来自于组件集成,而不是单个组件。即使所有单元都在隔离状态下工作,系统可能也不会提供任何价值。软件的真正价值只有在集成并准备运行时才会体现出来。由于测试应该确认价值交付,有人认为应该专注于编写集成测试而不是单元测试。

为了应对这些反对意见,Kent C. Dodds 提出了测试奖杯模型。该模型采用了测试金字塔的理念,提倡尽可能少使用手动和系统测试,但与之不同的是,它并不强调单元测试高于集成测试,而是强调集成测试优于单元测试。测试奖杯这一名称来源于如果将其绘制出来,它将呈现出类似奖杯的形状。

不幸的是,世上没有灵丹妙药,最好的建议是了解这三种模型及其背后的推理,并将适当的推理应用于当前的情况。在测试方面,并没有一种适用于所有情况的最佳解决方案。

非功能性测试的类型

功能测试主要关注验证应用程序展示的行为是否符合预期;然而,在应用程序开发中存在更多的风险:应用程序是否能足够快速地执行操作,随着更多用户同时使用系统时性能是否会下降,系统是否易于最终用户使用。验证这些属性的测试被称为非功能性测试。

有许多类型的非功能性测试,其中在 DevOps 场景中重要的三种如下:

  • 性能测试

  • 负载测试

  • 可用性测试

让我们逐一来看。

性能测试

性能测试的执行是为了确定在给定一组资源的情况下,应用程序执行某个操作的速度。性能测试通常使用专门的工具执行,并在完全组装的系统上运行。如果用于自动化 API 或 UI 测试的工具记录了测试的持续时间,那么这些测试的持续时间也可以作为性能结果使用。

为了比较多次测试的结果,确保影响性能的所有因素在测试之间保持一致是非常重要的。测试对象和测试运行者的虚拟机设置应该保持一致。应用程序配置应保持不变,集成点应该尽可能处于相同的状态——例如,不是重复使用同一个数据库,而是在每次性能测试前从备份中恢复相同的数据库。这样可以确保结果具有可比性。

虽然性能测试和负载测试常常混淆,但它们是两种不同类型的测试。

负载测试

负载测试的目的是测量系统在崩溃前能够承受的负载量。这类测试有时也被称为压力测试。与性能测试不同,负载测试会并行执行大量请求。测量的是所有请求的平均性能,同时逐步增加系统的请求数量。在大多数情况下,这会确定一个临界点,即每秒请求数达到某个特定值时,性能会突然下降。这是系统最大能承载的每秒请求数。执行负载测试时,随着最大请求数量的增加,通常会得到如下图所示的图表:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_13.jpg

图 10.13 – 负载测试图表示例

该图表显示了了解应用程序临界点的重要性:过多的负载可能会因为响应时间突然变化而意外地让系统崩溃。知道这个临界点在哪里可以让操作人员在生产环境中到达此点之前采取措施。

本章末尾提供了一个链接,指向一个在线的 Microsoft 实验室,供开发人员练习负载测试。

Azure 现在提供完全托管的负载测试服务。Azure 负载测试服务目前处于公开预览阶段,允许你通过模拟高规模负载流量来进行应用程序负载测试。开发人员、测试人员和质量保证QA)工程师可以使用该服务来识别和修复应用程序的性能、可扩展性或容量问题。Azure 负载测试抽象了执行大规模负载测试所需的复杂性和基础设施。你可以在这里了解更多关于 Azure 负载测试服务的信息:azure.microsoft.com/en-us/services/load-testing/

可用性测试

另一种重要的测试类型是可用性测试。其他类型的测试侧重于验证实现是否具备产品团队所期望的行为,而可用性测试则侧重于验证用户的期望是否真正得到满足。这意味着测试范围更大,这些测试能够识别笨拙的用户界面,并帮助找到模糊不清的文本或被误解的用户请求。

可用性测试通过让用户在一个或多个任务上与最终应用程序进行互动,并观察或询问他们如何与应用程序互动来进行。结果通常比通过未通过更加详细,结果通常会反馈给产品负责人,以便编写新的用户故事或更改需求。

启用可用性测试的一个极好技术是使用功能标志。功能标志使我们能够逐步将新功能暴露给更多用户。这个能力还可以用于最初仅将新功能暴露给一小部分用户,这些用户是可用性研究的一部分。这允许研究人员或产品负责人密切观察这些用户使用新功能,而其他用户尚无法访问。

重要提示

功能标志在第六章《实现持续部署和发布管理》中被讨论,作为渐进式曝光的策略。新功能的渐进式曝光本身就是一种可用性或用户接受度测试。

这种方法可以扩展到执行 A/B 测试。在这类测试中,一半的用户暴露于新功能,而另一半则没有。然后收集所有用户的数据,以查看新功能是否为用户带来了预期的好处——例如,用户是否每天使用应用程序的时间增加了。这一主题将在第十三章《收集用户反馈》中进一步探讨,内容涉及如何收集用户反馈。

这样做将可用性测试推向了发布过程的右侧。它也可以通过在最终应用程序之前,使用原型进行可用性测试,向左移动。

这就结束了对不同类型测试的讨论。在接下来的部分中,将使用度量和测试来自动衡量质量并实现质量门控。

在管道中执行测试

开发人员应该在为代码打开合并请求之前,在本地机器上执行测试。这样,他们可以确信所做的任何更改不会破坏代码的先前行为。从理论上讲,这可以保证所有合并到主分支的代码都能编译并且所有测试都通过。实际上,存在许多原因导致情况并非如此。以下是一些原因:

  • 一些测试可能无法在本地运行。它们依赖于机密的配置值,或者被配置为在完全配置的系统上运行。这两种情况常见于系统测试。有许多情况是无法从本地系统运行系统测试的。这些情况并不一定都是理想的或无法克服的——但这通常是事实。

  • 开发人员也是人。他们可能会忘记在做最后一个调整后运行本地机器上的测试,或者确信他们的更改没有破坏任何现有行为。特别是在压力下交付错误修复时,为了加快速度,跳过测试执行可能是很有诱惑力的。

为了防止这些情况使未经过充分测试的代码在流水线中传播,建议在流水线内执行所有测试。接下来的部分将展示如何为单元测试、集成测试以及通过其他系统运行的测试执行此操作。首先是单元测试。

运行单元测试

对于许多语言,Azure DevOps 已经内建了支持从流水线运行单元测试的功能。可以为 C#、TypeScript、Python、Maven、C++、Go 等语言执行单元测试。

对于其中一些语言,提供了一个现成的任务。例如,用 C#编写的测试。在执行.NET 测试时——例如在 C#中——测试结果会自动以 XML 格式存储,构建代理可以理解该格式。

这允许流水线代理解释测试结果并在构建结果中可视化它们,如下所示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_14.jpg

图 10.14 – 显示自动化测试执行结果的构建结果页面示例

对于某些语言,需要执行多个任务。例如,用 TypeScript 编写的测试通常通过 NPM 命令执行。以下 YAML 片段可以用来实现这一点:

- task: Npm@0
  displayName: 'Run unit tests - npm run tests' 
  inputs:
    cwd: src 
    command: run 
    arguments: test

这将执行package.json中指定的自定义 NPM 命令。不幸的是,这不会以流水线代理理解的格式存储测试结果。为了将结果转换为正确的格式,需要另一个任务。以下 YAML 片段可以用来实现这一点:

- task: PublishTestResults@2 
  displayName: 'Publish Test Results' 
  inputs:
    testResultsFiles: '**\reportTests\TEST-*.xml' mergeTestResults: true
  condition: succeededOrFailed()

测试结果是否可以直接获得或需要转换,因编程语言而异。除了发布测试结果外,还建议收集测试覆盖率结果。

记录单元测试代码覆盖率

最佳实践是,在构建过程中不仅运行所有单元测试,还要确定在这些测试中执行的代码基础的百分比。这被称为单元测试代码覆盖率,它表示测试的全面程度。构建也可以配置为发布单元测试获得的代码覆盖率。

要配置构建以发布.NET Core 单元测试的测试覆盖率,必须执行以下步骤:

  1. 在单元测试项目中安装coverlet.msbuild NuGet 包。

  2. 使用.NET Core 任务执行测试,并添加两个参数以生成覆盖率报告,/p:CollectCoverage=true/p:CoverletOutputFormat=cobertura

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_15.jpg

图 10.15 – 配置单元测试代码覆盖率

  1. 添加Cobertura

  2. 配置$(System.DefaultWorkingDirectory)/**/coverage.cobertura.xml作为汇总文件。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_16.jpg

图 10.16 – 发布单元测试代码覆盖率

  1. 构建的运行详情现在将包含代码覆盖率报告。

这是生成详细代码覆盖率报告所需的所有配置。生成的报告包含已覆盖和未覆盖的代码块数量以及计算出的覆盖率百分比。这些报告是构建结果页面的一部分。

除了单元测试,集成测试也可以作为管道的一部分运行,并且它们通常面临处理配置设置管理的挑战。

运行集成测试

集成测试通常与单元测试使用相同的框架编写。不过,它们有自己独特的挑战。通常,它们需要一个或多个设置,指定如何与测试中涉及的一个或多个其他组件进行集成。回顾之前讨论的MessageSender类的集成测试,这是这个问题的一个例子。

记得这个测试有一个.runsettings文件,在其中你应该指定connectionString,该连接字符串是MessageSender类将使用的队列。这个connectionString设置不能提交到源代码控制中。相反,可以将占位符提交到源代码控制中,并在管道执行过程中用实际的密钥替换它。

在这种情况下,这意味着以下pipeline.runsettings文件将提交到源代码控制中:

<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
  <TestRunParameters>
    <Parameter name="MessageSenderConnectionString" value="#{MessageSenderConnectionString}#" />
 </TestRunParameters>
</RunSettings>

在开始实际测试执行之前,另一个任务将被运行,用实际值替换占位符。正如在第五章《迁移到持续集成》中讨论的那样,这些值可以从变量组、密钥保管库或管道变量中安全地获取。Azure DevOps 有多个扩展可以用于将占位符替换为实际值。以下 YAML 代码片段是如何操作的示例:

- task: qetza.replacetokens.replacetokens-task.replacetokens@3 
  displayName: 'Replace tokens in pipeline.runsettings' 
  inputs:
    targetFiles: $(System.DefaultWorkingDirectory)/integrationtests- location/pipeline.runsettings

在替换令牌任务执行后,可以像单元测试一样调用测试运行器。这个Replace Tokens扩展可以在 Azure DevOps Marketplace 上找到:marketplace.visualstudio.com/items?itemName=qetza.replacetokens

运行外部测试

除了单元测试和集成测试,你可能还希望使用其他系统执行测试。例如,Azure DevOps 没有内置的支持来执行负载测试或自动化 UI 测试。对于这些类型的测试,必须从管道中调用其他系统。许多系统可以通过这种方式集成。

如何操作因系统而异,但大多数情况下,以下步骤将适用:

  1. 配置外部系统中的测试。

  2. 为 Azure DevOps 安装一个扩展,使新任务能够从管道调用外部系统。

  3. 创建到外部系统的服务连接。

  4. 将任务添加到管道中。

要了解配置集成的详细信息,一个好的起点通常是第三方产品供应商的网站。

维护质量

前面的章节详细介绍了可以用来描述应用程序质量的各种测试和指标。有了这些考虑,接下来是时候开始思考可以用于维持高质量甚至提高质量的工具了。

代码审查

保护代码质量的最强大工具之一就是代码审查。当使用 Git 时,必须执行拉取请求(pull request)将开发者的更改合并回主分支。拉取请求允许一个或多个开发者审查所有更改并对此进行评论。发起拉取请求的开发者可以查看评论并据此进行修改,在继续工作的同时提高更改的质量。

为了使代码审查发挥最大作用,重要的是不要将其视为一个必须尽量轻松通过的关卡。采取一种更为开放的态度,假设每个人都在努力编写高质量的代码,并将代码审查视为有关代码质量的讨论的开始,这样会更加有益。改变视角,把代码审查从软件开发中令人烦恼的仪式转变为一个欢迎他人对你的代码提出意见并帮助你编写更高质量代码的机会。

一旦有了这样的心态,代码审查将成为学习的源泉。它们将促使同行之间展开讨论,寻找解决问题的最佳方式:不仅仅是现在的最佳方法,还要考虑未来,不留下技术债务,并确保与要合并的代码一起有足够的单元测试和集成测试。代码审查也是辅导初级开发者的绝佳工具,允许他们获得对其工作的反馈。让初级开发者审查高级开发者的代码甚至更有价值。通过这种方式,他们可以提出自己尚未掌握的问题,并且通常会指出那些可能随着时间推移成为技术债务的过于复杂的解决方案。

自动收集质量指标

除了手动审查外,还有许多工具可以自动评估代码库的质量。有些工具内置于 Azure Pipelines 中,但更复杂的功能来自于独立的代码扫描工具。通过数学方法来衡量技术债务,使用工具来进行此类衡量不仅能为应用的质量提供有价值的洞察,还能帮助了解代码随时间变化的情况。

衡量应用程序质量的一种可能工具是 SonarCloud。SonarCloud 是基于 SonarCube 的 SaaS 产品。此工具可以自动扫描代码库,查找潜在的漏洞、安全风险、技术债务和其他质量指标。这是一个付费的独立产品,能够与 Azure DevOps 管道集成。要使用 SonarCloud,你必须创建一个帐户并获取项目密钥,以便从 Azure DevOps 调用 SonarCloud 扫描。

为了调用 SonarCloud,使用一组三项任务,这些任务是 Azure DevOps 扩展的一部分。在安装扩展并配置 SonarCloud 服务连接后,三个任务会被添加到管道中,以设置分析、执行分析并(可选地)在质量下降时使构建失败。第一个任务是唯一需要配置的任务,配置过程如以下截图所示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_17.jpg

图 10.17 – 配置 SonarCloud – 静态代码分析器

每次执行的构建都会自动扫描其代码,由 SonarCloud 提供关于质量的详细报告。在这些报告的基础上,还会生成一个仪表盘,快速概览一些关键的质量指标。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_18.jpg

图 10.18 – SonarCloud 质量指标概览

这是仪表盘的另一个视图,展示了质量指标:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_19.jpg

图 10.19 – SonarCloud 质量门控仪表盘

代码扫描工具可以用于报告代码的质量,同时也可以作为质量门控,阻止合并更改或将更改部署到特定环境中,如果检测到质量不足。

可视化质量

持续衡量应用程序的质量是没有意义的,除非采取了相应的措施。仪表盘可以成为一个强大的工具,帮助持续洞察当前的质量水平以及质量随时间的变化。

大多数代码质量工具都内置了报告选项,它们对 QA 工程师非常有价值。它们提供了详细的洞察,帮助了解应用程序哪些部分的质量较高,哪些类型的问题最近发生得更频繁。

这种类型的仪表盘的缺点是,它们通常很难阅读和关联,因为它们可能存在于与开发人员执行大部分工作所在的 Azure DevOps 不同的其他工具中。因此,创建 Azure DevOps 中的仪表盘来报告质量可能会更有益。以下截图展示了这样的仪表盘示例:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_20.jpg

图 10.20 – Azure DevOps 仪表盘质量概览

该仪表盘显示了当前质量和应用程序代码的概览,以及一些最近的历史记录。在这里,你可以找到以下信息:

  • 在顶部显示最近更改的数量,以及最新的 SonarCloud 质量 gate 结果,当前显示为 通过。该项目中两次不同构建的结果显示在第二行。

  • 第三行和第四行显示项目中所有构建和发布的聚合结果。使用符号表示构建和发布的状态:成功、失败或仍在运行。

  • 在右侧,使用两个小部件显示过去 10 个构建中的失败测试的百分比和相应的失败测试数量。

  • 每个环境下最新发布运行的结果显示在下方。

可以使用内置小部件或扩展根据团队或项目创建这样的仪表板。Azure DevOps 市场中有许多扩展。例如,在前面的仪表板中,使用了 Team Project Health 扩展。此扩展可在 Azure DevOps 上找到:marketplace.visualstudio.com/items?itemName=ms-devlabs.TeamProjectHealth

Azure DevOps 仪表板可以配置为每 5 分钟自动刷新,从而也能作为墙板使用。

质量 gates

衡量、报告甚至可视化质量是重要且有价值的;然而,如果没有人基于这些指标采取行动,那么对开发团队来说这些指标就没有价值。为了防止这种情况,可以引入自动质量 gates 或检查。

实现质量 gates 的一种方法是,当测试失败、测试覆盖率过低或代码扫描工具设定的阈值不再满足时,使持续集成构建失败。这些都是之前讨论过的内容。另一个强制执行标准的选项是向管道中添加 gates 或检查点。通过这种方式,必须满足某些条件,管道才能继续执行。

如何实现这一点在经典发布和 YAML 多阶段管道之间有所不同。

经典发布

另一个选项是使用 Azure 发布管道中的 gates。在这里,可以指定一个或多个条件,必须满足这些条件才能允许将发布部署到特定环境中。gates 还可以是扩展的一部分,例如之前讨论过的 SonarCloud 扩展。

可以通过选择发布管道中的任何阶段并编辑预部署条件来添加 gates。启用 gates 后,可以添加一个或多个 gates。以下是发布管道的截图,展示了如何禁止将任何质量不合格的构建部署到环境中:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_21.jpg

图 10.21 – Azure DevOps 配置部署 gates

部署审批和 gates 的使用并不相互排斥,因此可以同时使用两者。

多阶段管道

Gates(如在经典发布中可用)也可以在多阶段的 YAML 流水线中使用。在 YAML 流水线中,还有另一种机制:检查。检查被配置为在允许流水线继续之前自动验证一个或多个条件是否满足。检查可以添加到在某个阶段使用的资源上。如果在某个阶段的一个或多个资源上发现一个或多个检查,则所有检查必须通过,流水线才可以继续到该阶段。检查可以添加到环境和服务连接中。

要向环境添加检查,请导航到该环境。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_22.jpg

图 10.22 – 配置 Azure DevOps 环境

现在,执行以下步骤:

  1. 在右上角,展开菜单并选择审批和检查

  2. 在打开的新视图中,点击查看所有以查看所有可用的检查类型。

  3. 选择调用 Azure 函数

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_23.jpg

图 10.23 – 配置 Azure DevOps 环境审批和检查

  1. 在弹出的窗口中,配置要调用的 Azure 函数。至少需要提供函数的 URL 和密钥。

  2. 点击创建

一旦检查创建完成,每个目标环境的部署任务(参见第六章实施持续部署和发布管理)都必须通过此检查。当被调用的函数返回成功响应代码时,检查通过。

支持以下类型的检查:

  • 评估工件:验证容器镜像类型的工件是否通过了自定义策略。这些策略是使用一种名为Rego的语言定义的。

  • 调用 REST API:将流水线的详细信息发布到 Azure 函数或 REST API,以执行自定义逻辑。如果 API 返回成功的 HTTP 状态码,则允许流水线继续。

  • 调用 Azure 函数:与调用 REST API检查相同,但具有一些 Azure 函数的默认设置。

  • 查询 Azure Monitor 警报:仅在指定的警报处于非活动状态时才继续。

  • 必需的模板:仅当当前的 YAML 流水线扩展了一个或多个配置的基础 YAML 模板时,才允许流水线继续。

检查可以是确保满足一个或多个条件后再允许流水线继续的强大机制。

总结

在这一章中,你学习了如何衡量和验证软件开发过程的质量。快速和频繁发布要求所编写的软件具有高质量。需要进行测试,以确保你编写的软件质量高,技术债务少。你了解了不同类型的测试,以及自动化和手动测试的优缺点。最后,你还学习了如何通过代码审查和工具帮助保持项目的高质量,通过报告质量并作为质量门控。

通过这些知识,你现在了解了测试和测试类型,帮助你决定哪些测试是应用程序所需的,哪些风险可以通过哪种测试来解决,以及哪些是你需要的,哪些可以省略。你现在还能够设置和配置代码扫描工具,确保低质量的更改不会合并到主分支。

在下一章,你将学习关于安全性和合规性这两个话题,它们在实践 DevOps 时同样重要。

问题

在我们总结时,这里有一份问题清单,供你测试自己对本章内容的理解。你将在附录评估部分找到答案:

  1. 判断对错:单元测试验证的是单个单元的独立工作情况。

  2. 判断对错:集成测试验证的是一个完全组装的系统的工作情况。

  3. 以下关于测试金字塔原则的说法哪个是正确的?

    1. 有很多集成测试,较少的单元测试,甚至更少的系统测试

    2. 有很多单元测试,较少的集成测试,甚至更少的系统测试

    3. 有很多系统测试,较少的集成测试,有很多单元测试

  4. 以下哪个不是非功能性测试类型?

    1. 负载测试

    2. 可用性测试

    3. 适用性测试

    4. 性能测试

  5. 测试是关于深入了解工作质量的。可以采用哪些技术来防止低质量的工作传播到生产环境?

自我练习

  • 打开我们之前在第六章《实施持续部署与发布管理,练习部分》中创建的packtbookslibrary-api解决方案,并添加一个新项目(选择NUnit 测试项目)。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_24.jpg

图 10.24 – 自我练习 – 添加新测试项目

  • 创建一个新测试项目。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_25.jpg

图 10.25 – 自我练习 – 创建新测试项目

  • 一旦创建了测试项目,在依赖项中添加对packtbookslibrary-api的引用。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_26.jpg

图 10.26 – 自我练习 – 配置依赖关系

  • 添加一个IBookService.cs接口和实现该接口的BookService.cs类。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_27.jpg

图 10.27 – 自我练习 – 添加 IBookService.cs 接口

  • IBookService.cs 将有如下代码:

    using packtbookslibrary.Shared.Models;
    using System.Text.Json;
    namespace packtbookslibrary_api.Services
    {
        public interface IBookService
        {
            List<Book> GetBooksList();
        }
    }
    
  • BookService.cs 将有如下实现:

    using packtbookslibrary.Shared.Models;
    using System.Text.Json;
    namespace packtbookslibrary_api.Services
    {
        public class BookService : IBookService
        {
            List<Book> IBookService.GetBooksList()
            {
                List<Book> books = new List<Book>();
                string jsonString = System.IO.File.ReadAllText("books-data.json");
                books = JsonSerializer.Deserialize<List<Book>>(jsonString);
                return books;
            }
        }
    }
    
  • 将以下代码添加到 BooksController.cs 中:

          private readonly IBookService bookService;
            List<Book> books = new List<Book>();
            public BooksController(IBookService bookService)
            {
                this.bookService = bookService;
                books = bookService.GetBooksList();
                //string jsonString = System.IO.File.ReadAllText("books-data.json");
                //books = JsonSerializer.Deserialize<List<Book>>(jsonString); 
            }
            // GET: api/<BooksController>
            [HttpGet]
            public IEnumerable<Book> Get()
            {
                return books;
     }
    
  • 添加 Moq 包引用:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_28.jpg

图 10.28 – 自我练习 – 添加包引用

你会注意到所有的测试用例都已成功通过。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_29.jpg

图 10.29 – 自我练习 – 执行 BookControllerUnitTest

  • 更新 nugget.config 以添加 Sources 包:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <packageSources>
            <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
             <!-- add an Azure Artifacts feed -->
               <add key="PacktBooksLibraryFeed" value="https://pkgs.dev.azure.com/aurigadev/PacktBookLibrary/_packaging/PacktBooksLibraryFeed/nuget/v3/index.json" />
        </packageSources>
    </configuration>
    
  • 向 YAML 管道中添加测试用例步骤,以便在构建过程中执行测试用例:

    # Run your tests
       task: DotNetCoreCLI@2
       displayName: 'Run Tests'
      inputs:
      command: test
      projects: '**/*Tests/*.csproj'
      arguments: '--configuration ${{ parameters.buildConfiguration }}'
    
  • 执行 main-ci-pipeline 以运行管道,并检查 Test 选项卡查看测试执行结果。

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_10_30.jpg

图 10.30 – 自我练习 – 执行持续集成管道以查看测试结果

进一步阅读

第十一章:管理安全性和合规性

确保你的应用程序执行所需功能同样重要的是,确保它不做任何不该做的事情。在上一章中,你了解了质量和测试,目的是不断衡量你的应用程序是否在按预期工作。在本章中,你将学习如何防止任何不必要的行为。这涉及到安全性和合规性问题。虽然通过更快的部署和缩短交付周期可以增加向最终用户提供的价值流,但你仍然需要确保交付的是安全和合规的软件。在本章中,你将学习如何在你的 DevOps 流程中解决这些问题。

为此,本章将从讨论速度与安全之间的感知权衡开始,并解释如何在拥抱 DevOps 时,安全性不会降低,反而可能会增加。接下来,讨论安全性的一个特定维度:如何安全地处理你的管道和应用程序所需的秘密,如密钥和密码。之后,介绍用于自动识别应用程序代码和依赖项中可能存在的安全风险的代码扫描工具。本章最后讨论如何保持你的基础设施和配置部署的合规性,以及如何使用 Azure 安全中心(现称为 Microsoft Defender for Cloud)检测运行时安全风险和威胁。

本章将涵盖以下主题:

  • 将 DevOps 原则应用于安全性和合规性

  • 处理秘密

  • 检测应用程序代码漏洞

  • 与依赖项一起工作

  • 确保基础设施合规性

  • 监控和检测运行时安全风险和威胁

  • 你可以使用的其他工具

技术要求

为了实验本章中描述的技术,你需要以下一种或多种工具:

  • 拥有访问构建和发布管道权限的 Azure DevOps 项目,并有权安装扩展

  • 一个 Azure 订阅(若你尚未拥有账户,可前往 portal.azure.com 并按照指南进行注册)

  • 安装了 Azure Az PowerShell 模块的 PowerShell(如何安装 PowerShell Azure 模块的说明可以在 docs.microsoft.com/en-us/powershell/azure/install-az-ps?view=azps-7.3.0 查阅)

  • 可选的 WhiteSource Bolt、SonarCloud 或类似产品的订阅

上述所有内容都可以免费或试用,以便学习或评估用途。

将 DevOps 原则应用于安全性和合规性

关于安全性和合规性的担忧,可能是公司不愿接受完全的 DevOps 思维方式的原因之一,因为这会妨碍它们频繁发布的能力。在过去,它们通常会减少发布频率,每次发布前都会进行安全或渗透测试。这给了它们信心,确保不会发布包含安全漏洞的软件。

这种减少发布频率、在最终发布之前进行一次大规模的安全测试的做法与 DevOps 的思维方式相冲突,这也是一些公司面临的难题。它们在寻找确保每次发布都能为用户提供业务价值的方法,但又不愿在此过程中妥协安全性。问题是,这样的取舍是否公平。难道不能在保证速度的同时保持安全性吗?或许实际上更频繁和更快速的发布,结合严格的自动化,反而能帮助提高软件开发中的安全性?为了回答这个问题,我们可以先探讨在非 DevOps 环境中安全性通常是如何实践的,并了解在采用 DevOps 时需要做出哪些改变。

将开发人员和安全工程师聚集在一起

在许多公司中,安全工程师与开发人员属于不同的部门。这样分开的思路是认为将编写代码的人(即开发人员)与检查代码的人分开会更加有利。

过去,软件开发人员与软件测试人员之间也常常存在相同的分隔。然而,最近的研究表明,将开发人员和测试人员放得更近并不会导致诸如“群体思维”、仅测试已知正常工作的内容,或通过仅为已知测试用例开发来作弊测试等不良行为。经验和研究表明,事实恰恰相反。将开发人员和测试人员放在一起可以产生更高质量的产品。正因如此,像敏捷开发这样的运动建议开发团队在开发过程中加入包括测试在内的各项纪律。

正是基于这一思路,越来越多的人呼吁将安全工程整合进 DevOps 开发团队。这一运动通常被称为DevSecOps强固的 DevOps。这两种运动都主张,运用 DevOps 原则,如向左推进(shift left)并尽可能自动化,可以帮助提高安全性。它们提倡,渗透测试或应用程序的漏洞审查不再由人工完成,而是完全自动化,并成为交付管道的一部分。这使得自动化、快速反馈循环以及持续交付和部署成为可能。

还有人提倡,更频繁地发布软件也有助于进一步提高安全性,原因如下:

  • 当可用的自动化软件发布机制可靠时,任何解决安全风险的更改都可以迅速部署。能够快速响应新的发现是一个重大的安全改进。

  • 速度本身也可以是一种安全措施。如果系统的工作状态每天变化多次,那么要弄清楚其内部工作原理并加以滥用就变得更加困难。应用不可变部署原则并使用基础设施即代码确保运行应用程序的基础设施经常得到刷新。这是有效减缓高级持续性威胁的良好措施。

本章将探讨的一个内容是如何配置交付管道以加入安全扫描。请注意,从管道中运行这些工具是一项不同的任务,它确保这些工具被正确配置并且应用正确的政策和要求。对于这些活动,拥有安全背景并与安全工程师密切合作仍然至关重要。这只是另一个密切合作能够带来变化的领域。特别是在安全问题上,需要与其他学科的协作——以自动化所有安全检查并避免(或最小化)任何手动验证过程。

安全问题

本章其余部分将介绍一些安全问题,但认识到一些前面的章节已经介绍了一些安全问题会有所帮助。正如你从软件开发中已经知道的,安全不仅仅是你在某一个地方添加的东西。安全应该无处不在。以下图表显示了与软件创建和交付相关的不同活动。在每个活动旁边,显示了适用的安全问题:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_11_01.jpg

图 11.1 – 软件开发活动与安全问题

让我们回顾一下这些阶段中的安全问题:

  • 分支-主分支合并:在这个阶段,通过拉取请求应用四眼原则。拉取请求允许其他工程师在合并到主分支之前审查更改。分支策略用于强制要求使用拉取请求,确保代码能够编译并且单元测试能够运行。这在第四章《一切从源代码管理开始》和第五章《迁移到持续集成》中已有讨论。

  • 构建:在这个阶段,通过向构建管道添加额外任务,执行所有源代码和第三方依赖的安全扫描。这可以防止安全风险在未经检查的情况下传播。我们将在本章的《处理机密》部分讨论如何做到这一点。

  • 发布:在发布过程中,可以配置批准人。批准人是指必须在部署到特定阶段之前提供批准的用户。此外,使用自动化发布门控确保(并进一步强制执行)在发布可以继续之前满足某些标准。我们在 第六章实施持续部署和发布管理 中讨论了如何做到这一点。

  • 部署环境(目标系统):所有应用程序都会在目标环境中运行。可以是本地部署;然而,本书重点介绍的是 Azure。对于运行时的安全性和合规性问题,本章将介绍 Azure Policy 和 Microsoft Defender for Cloud(前身为 Azure Security Center)。

  • 横向影响:前述所有要点只有在 Azure DevOps 环境中有足够的访问控制时才有用。尽管这不在本书的范围之内,但它是一个重要的角度。用户应该拥有足够的权限来完成他们的工作,但不应能够对政策、构建和部署过程做出未经授权的更改。此外,在整个交付过程中,需要进行适当的机密管理,以确保证书、密钥和密码等机密的安全。我们如何做到这一点,本章也会进行讨论。

现在,了解了软件和安全工程师如何协作开发应用程序,接下来是时候在以下各节中讨论这项工作的不同方面了。下一节将讨论如何处理机密。

与机密一起工作

一个重要的安全元素是机密的处理。在部署应用程序时,总是涉及到机密。尤其是在部署到云端时——即通过互联网——以安全的方式处理这些访问密钥至关重要。除了部署所需的机密外,还有一些机密需要插入到应用程序的运行时配置中。一个常见的例子是访问数据库时所需的机密。

第八章实现 基础设施和配置即代码 中,讨论了多种交付应用程序配置的机制,包括 Azure Resource ManagerARM)模板。然而,模板需要输入外部机密,因为它们不能存储在源代码控制中的参数文件中。

重要说明

不应将机密存储在源代码控制中。

如果机密不能存储在源代码控制中,那么应该将其存储在哪里呢?常见的选项包括将机密存储在服务连接或变量组中。

将机密存储在服务连接中

部署任何应用程序所需的第一组机密是连接到目标系统所需的机密。任何个人都不应访问这些机密,因为它们仅在部署期间使用。这也是为什么 Azure Pipelines 允许你将它们安全地存储在服务连接中的原因。

服务连接是另一个系统的抽象,可以用于执行 Azure Pipelines 中的任务。服务连接有特定类型——即指定它们可以连接的系统类型。Azure、GitHub、Jira、npm、NuGet 和其他十多种系统都有现成的服务连接类型。也可以通过 Azure DevOps 扩展机制添加新的服务连接类型。

服务连接可以包含指向另一个系统位置的引用——通常是一个网址。在该位置旁边,它们可以包含授权令牌、用户名和/或密码,具体取决于服务连接的类型。存储在服务连接中的机密不能再被检索,甚至管理员也无法访问。此外,每当服务连接的任何细节发生更改时,必须重新输入机密。这是为了防止之前输入的机密被滥用以访问其他位置。这些细节表明,服务连接被设计为提供一个安全的位置来存储连接凭证。

服务连接可以在每个 Azure DevOps 项目的中心位置进行管理。你可以创建新的连接、编辑现有的连接、修改用户权限等等。按照以下步骤练习:

  1. 要打开此视图,请导航至项目设置。将打开一个包含各种设置选项的垂直列表。

  2. 从列表中点击服务连接。你将能够查看各种连接,如下图所示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_11_02.jpg

图 11.2 – 创建新的服务连接

  1. 如果你希望创建新的服务连接,点击屏幕右上方的新建服务连接按钮。

  2. 要修改权限,请点击安全下的更多操作子菜单。这将带你到一个类似于下图的屏幕:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_11_03.jpg

图 11.3 – 服务连接安全设置

编辑和安全视图中,你现在可以执行以下操作:

  • 编辑服务连接详情。

  • 修改用户权限。

  • 限制权限。

  • 添加更多用户或组,并为每个用户或组指定是否可以使用或管理该端点。

  • 指定哪些管道可以使用此服务连接。

项目中的每个管道默认不应有权限使用服务连接。相反,每个希望使用服务连接的管道必须首先获得服务连接管理员的授权。

在变量组中存储机密

在应用开发中涉及的机密比仅用于连接其他系统的机密更多。例如,包括在应用编译过程中需要的许可证密钥,或在部署后需要传递给应用的数据库用户名和密码,或作为 ARM 模板部署的一部分传递的数据库信息。

这些机密可以存储在管道变量或变量组中,关于这一点我们在第三章,“优化 DevOps 工具使用效果”部分中,讲解了在Azure DevOps 中创建构建定义时的相关内容。微软会安全地存储所有标记为机密的变量,并使其无法通过用户界面进行检索。

然而,可能有一些原因不希望将机密存储在 Azure DevOps 中,而是存储在专门的密钥存储中,例如 Azure Key Vault。这样做将提供与 Key Vault 一起的额外保障,并能够使用Azure 基于角色的访问控制Azure RBAC)和密钥库访问策略进一步控制访问策略。

当将机密存储在 Azure 密钥库中时,它们仍然可以作为变量组使用,通过通过服务连接将空的变量组连接到密钥库,如下图所示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_11_04.jpg

图 11.4 – 将 Key Vault 用作变量组的存储

要将密钥库用作变量组的存储,请执行以下操作:

  1. 启用从 Azure 密钥库链接机密作为变量的第二个滑块,以从密钥库加载机密。

  2. 从下拉菜单中选择一个已存在的 ARM 服务连接,或者通过从列表中选择一个 Azure 订阅,动态创建一个新的 Azure 管理身份服务连接。

  3. 输入要加载机密的密钥库名称。你也可以从下拉菜单中选择一个。在此情况下,仅显示可通过选定的服务连接访问的密钥库。

  4. 可以使用安全性选项卡配置特定用户的访问权限。

也可以自动创建正确的权限,以便访问 Azure 和密钥库的服务连接。请注意,这两个操作会对 Azure 安全设置进行更改,因此请确保这些设置(仍然)是正确的。

检测应用代码漏洞

在 DevOps 时代之前定期进行的安全评估,在转向 DevOps 文化时并不能完全省略。这意味着,必须以某种方式继续进行这些评估,而不是简单地放弃。可以通过两种方式来进行。

第一种方法是像以前一样,定期进行渗透测试、安全审查和其他安全检查。然而,代码不是等到测试通过后才进入生产环境,而是在与安全评估分开的情况下直接部署到生产环境。这意味着接受存在风险的假设,即可能会有一些漏洞在下次安全扫描时被发现,并会在下一个版本中解决。使用这种方法可以实现速度,但也需要接受某些漏洞可能会存在一段时间。

第二种方法是将应用程序安全扫描作为常规工作流程的一部分,纳入到将代码提交到源代码库的过程中。例如,安全代码审查不必每个增量或每两个月进行一次。它们也可以在每次拉取请求时进行——在代码合并之前。这样,你突然间不再只是检测漏洞,而是改为防止漏洞的出现。安全漏洞扫描也可以采用相同的方式。它们可以成为交付流水线的一部分,或者成为一个完整的每晚质量保证QA)构建,每天早晨报告开发质量。

当然,实际情况通常并不像黑白分明那样,很多公司会结合使用这些方法。它们使用自动化反馈机制来检测可以发现的问题,将安全代码审查作为拉取请求工作流程的一部分,然后结合定期的手动渗透测试。通过这种方式,交付速度提高的同时,安全风险没有增加,甚至可能减少,后者是漏洞修复速度提高的结果。

OWASP Top 10

在 Web 应用程序安全方面,有几种常见的安全问题,负责编制大部分安全问题。这些问题类型包括 OWASP Top 10。这是一个列出十大最常见安全问题的清单,由开放 Web 应用程序安全平台OWASP)发布。该清单每隔几年会进行一次审查,但在过去几年里保持了相对稳定。

OWASP Top 10 中的大部分错误都可以通过实施自动化安全测试来预防,方法可以是使用静态代码分析来检查安全漏洞,或者使用OWASP Zed 攻击代理OWASP ZAP)进行动态测试。

实施自动化漏洞扫描

在前一章中,讨论了持续测试,并介绍了 SonarCloud 作为用于技术债务和代码质量的代码扫描工具。除了评估应用程序代码的质量外,SonarCloud 还可以用于扫描安全漏洞。在第十章《集成持续测试》中,您学习了如何将 SonarCloud 扫描添加到您的管道中。还有其他更多专业化的工具可供使用,我们将在本章的最后一部分讨论这些工具。

这些工具通过静态测试评估应用程序。它们扫描代码以识别任何有风险的代码。这被称为白盒方法,因为它们可以看到、检查和扫描所有代码。换句话说,一切都是可见的。这与黑盒方法相反,黑盒方法将运行中的应用程序视为一个封闭的整体,只通过调用它并观察其响应来进行测试。OWASP ZAP 就是能够执行这种测试的工具之一。

OWASP ZAP

OWASP ZAP 是一款可以执行应用程序自动化渗透测试的工具。该工具可以在两种模式下运行:

  • 基准扫描:基准扫描只需几分钟,并且经过优化,可以在这几分钟内尽可能多地扫描安全风险。这使得基准扫描足够快速,能够在部署管道的早期阶段运行。甚至可以在每次部署到第一个测试环境后运行安全扫描,从而为开发人员提供快速反馈。

  • 完整主动扫描:完整的主动扫描需要更多时间。在这种类型的扫描中,代理会检查来自应用程序的每个响应,以识别应用程序的其他 URL,并对它们进行扫描。通过这种方式,完整的应用程序会在运行时被发现,采用蜘蛛抓取的方式。这种扫描方式更加全面,但也需要更多时间。因此,完整扫描通常会在间隔时间内进行,例如每晚一次。

OWASP ZAP 尝试识别任何可能的安全风险。最显著的风险包括 SQL 注入、JavaScript 反射和路径遍历。

OWASP ZAP 是一款可以安装在任何虚拟机上的应用程序。其缺点是,即使没有正在运行的扫描,虚拟机也会一直运行。这会增加成本,当然,虚拟机本身也需要进行补丁更新和安全加固。最近,还推出了该代理的容器化版本。该容器可以在 Azure 容器实例中运行,只在需要时启动代理,执行完毕后立即销毁。

这完成了我们对代码扫描工具及其实现的介绍。在这些工具的帮助下,您可以检测应用程序中的漏洞并防止任何安全问题。下一部分将探讨如何扫描应用程序的依赖项。

处理依赖项

除了应用程序代码本身可能带来的安全风险外,还存在与重用组件相关的风险。现代应用程序代码中有 50% 到 80% 不是内部开发的,而是来自其他方的包或依赖项。一些可能是开源的,但不一定如此。也可能是从其他开发公司购买的组件或从如 NuGet 等库中获取的二进制文件。

依赖项不仅带来安全风险,还可能带来许可风险。如果一个团队开始使用一个以 GPL 许可发布的组件作为封闭源组件,会发生什么?如果有人发现,他们可能被迫将产品开源,或者至少会因为未根据许可使用他人的工作而遭受公开的耻辱。

为了降低这些风险,可以使用多种工具来检测和扫描构建应用程序时使用的所有依赖项。其中一个可用的工具是 WhiteSource Bolt,它作为扩展可从 Azure DevOps 市场获取。

使用 WhiteSource Bolt

要开始使用 WhiteSource Bolt 执行扫描,请执行以下操作:

  1. 从 Azure DevOps 市场安装 WhiteSource Bolt 扩展。

  2. 转到Pipelines下的WhiteSource Bolt菜单。

  3. 注册并接受许可条款。

  4. 如下图所示,将WhiteSource Bolt扫描任务添加到构建或发布定义中:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_11_05.jpg

图 11.5 – 一个 WhiteSource Bolt 管道任务

  1. 一旦安装了 WhiteSource Bolt 任务的管道运行完成,构建结果页面将包含一个额外的标签,名为WhiteSource,显示类似的结果,如下图所示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_11_06.jpg

图 11.6 – WhiteSource 报告

这完成了我们关于依赖项扫描的讨论。如前所述,您可以利用这些工具检测和扫描在构建应用程序时使用的所有依赖项。在下一节中,将介绍基础设施合规性。

确保基础设施合规性

另一个重要话题是合规性。在许多国家或市场中,创建软件时必须实施或遵守一系列规则和政策。其中很多政策与应用程序运行的基础设施相关。如果这些基础设施部署并管理在 Azure 平台上,Azure Policy 可以成为确保基础设施符合规定的强大工具。

第八章《将基础设施和配置实现为代码》中,讨论了 ARM 模板的相关内容。ARM 模板可以被视为一种技术,用于将完整的 Azure 环境描述为一个 JSON 数组,数组中的每个对象描述了应用程序基础设施中的一个资源。

Azure 策略允许您编写查询该文档以及通过任何 API 或 ARM 模板进行的更改的策略。每当找到一个与查询匹配的资源时,可以阻止其创建,或者将该匹配项添加到审核结果列表中。Azure 策略可以修复或修改不安全的配置,防止出现错误。

除了编写自定义策略外,还有许多现成的策略可供所有 Azure 用户使用。这些策略可以用来审核不符合最佳实践或通用建议的资源。还有一组组的策略,称为计划(Initiatives),它们描述了市场标准的适用部分。

分配 Azure 策略或计划

策略可以在 Azure 中的不同级别进行分配,具体可以是在资源组级别、订阅级别或管理组级别。可以通过门户、ARM 模板或蓝图,或者 PowerShell 来完成此操作。

要使用 PowerShell,可以使用以下一系列命令:

  1. 要检索资源组和策略的引用,请使用以下命令:

    $rg = Get-AzResourceGroup -Name myResourceGroupName
    $definition = Get-AzPolicyDefinition | Where-Object {
    $_.Properties.DisplayName -eq 'Audit VMs that do not use managed disks' }
    

这里选择的策略是一个内置策略,将审核所有未使用托管磁盘但在存储账户中有自定义磁盘的虚拟机。此策略定义将在以下任务分配的命令中使用。

  1. 要将策略分配给资源组,请使用以下命令:

    New-AzPolicyAssignment -Name 'audit-vm-manageddisks' - DisplayName 'Audit VMs without managed disks Assignment' -Scope
    $rg.ResourceId -PolicyDefinition $definition
    

在该任务分配后的 30 分钟内,新策略将生效。此时,会启动策略评估周期,所有在任务范围内的资源将会依据该策略进行评估。在撰写时,尚未发布有关此类评估周期所需时间的服务水平协议(SLA)。经验表明,评估周期的时间可以从 15 分钟到几个小时不等,具体取决于任务范围的大小。

编写 Azure 策略

虽然有许多内置的策略可供使用,但在许多用例中,仍然需要创建自定义策略。与任何其他 Azure 资源一样,策略是以 JSON 文档的形式编写的。适当的 ARM 资源类型为 policyDefinitions,其结构如下:

{
  "name": "string",
  "type": "Microsoft.Authorization/policyDefinitions", 
  "apiVersion": "2019-01-01",
   "properties": { 
    "parameters": {
     "location": { …}
   },
     "displayName": "…",
     "description": "…", 
     "policyRule": {
     "if": {
      "field": "location",
      "equals": "[parameters('location')]",
     },
     "then": {
     "effect": "<audit|deny >"
    }
  }
 }
}

parameters 对象可以用来指定在稍后分配策略时需要指定的一个或多个参数。这些参数遵循与 ARM 模板参数相同的语法,并且工作方式也相同。

displayNamedescription 属性可以用来为策略定义提供有意义的名称和描述,方便后续参考。

定义的主体包含以下两个元素:

  • if 语句用于指定一个查询,选择此策略应适用的 Azure 资源。JSON 中编写复杂查询的具体语法已在 ARM 模板参考中详细说明,链接在本章末尾。

  • then 语句用于描述需要对符合条件的任何资源采取的操作。这可以是拒绝——即自动拒绝任何不符合要求的资源的创建。另一种方法是并非拒绝不合规的部署,而是对其进行审计。虽然在理论上拒绝不合规的部署非常直接,但暂时允许不合规部署也有其合理的原因。在这种情况下,审计策略可以帮助跟踪这些资源。所有不合规的部署将在其 Azure 活动日志中记录审计记录,并可以在 Azure 门户的Azure 策略下的合规性标签页中查看。具体如下:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_11_07.jpg

图 11.7 – Azure 策略合规性详情

在编写策略定义之后,我们需要在 Azure 订阅中创建它,以便使其可用。这可以通过 ARM 模板完成,或者在门户中手动完成。从 DevOps 角度来看,建议将策略编写在源代码管理中,并通过管道作为 ARM 模板的一部分进行交付。这样,Azure 策略与应用程序的编写方式相同,可以进行审查并作为 DevOps 管道的一部分自动部署到 Azure。

倡议

在使用 Azure 策略时,许多公司发现需要创建大量策略来定义他们希望软件开发人员遵循的所有规则。为此,将策略进行分组可能会带来好处。这样的分组被称为倡议,这些也是通过 JSON 定义的:

{
  "name": "string",
  "type": "Microsoft.Authorization/policySetDefinitions",  
  "apiVersion": "2019-01-01",
  "properties": { 
   "displayName": "string", 
   "description":  "string", 
   "parameters": { … }, 
   "policyDefinitions": [
   {
     "policyDefinitionId": "string", 
     "parameters": {}
   }
  ]
 }
}

一项倡议的主体是一个对象数组。每个对象必须包含一个 policyDefinitionId 属性,并且可以选择性地包含一个带有 parameters 的对象。policyDefinitionId 属性必须通过其 Azure 资源 ID 引用有效的 policyDefinitions 条件。parameters 数组应指定策略所需的所有参数。通常,这通过让倡议指定所有策略的所有参数的组合集作为倡议参数来实现。然后,个别策略的参数通过引用倡议参数来指定。

获取审计结果

在分配了具有审计效果的策略后,该策略将在激活后自动评估分配范围内的所有资源。无法保证这个过程需要多长时间。对于新资源,策略评估结果通常会在 15 分钟内显示,但通常会更快。

一旦结果出来后,可以在门户中查看每个政策或计划的合规性状态,从而获得概览,如下所示的截图所示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_11_08.jpg

图 11.8 – Azure 政策合规状态

这份报告与其他手动审计报告的不同之处在于,这份概览会持续更新,反映出实际的当前合规状态——它不是某一特定时间点的合规快照。

这种合规性类型的一个重要好处是规则或政策持续应用于所有现有资源和任何即将发生的变化。这意味着可以确保应用环境始终符合要求,并始终遵守适用的规则和政策。

将其与通常每两个月进行一次的安全和合规审计的做法进行对比。通常,这会导致环境在审计前才符合合规要求,且合规性在审计后逐渐下降——直到下次审计时间到来,此时合规性又会接近 100%。在许多公司中,这会导致如下的合规性图表:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_11_09.jpg

图 11.9 – 合规性水平随时间变化的成熟度

到此为止,我们已经讨论了 DevOps 实践如何通过确保基础设施合规性来帮助提高安全性和合规性的另一个例子。在下一部分,我们将讨论本章之前提到的几种替代工具,如 Defender for Cloud、Sonar Cloud 和 WhiteSource。

监控和检测运行时安全风险和威胁

到目前为止,我们讨论的所有安全工具都集中在防止将有漏洞的代码推送到生产环境。然而,一个完整的、已部署的软件解决方案,包括其所有支持基础设施,远不仅仅是代码。除此之外,解决方案的许多交互可能是意料之外或未经计划的。持续在生产环境中监控所有这些内容是必要的,不仅是为了防止安全问题的发生,还为了检测任何出现的安全问题。在 Azure 中,可用于执行此操作的工具之一是 Azure 安全中心。这个工具和 Azure Defender 现在被称为 Microsoft Defender for Cloud。

Defender for Cloud 工具提供安全态势管理和威胁防护,保护在 Azure、混合云和其他云平台上运行的工作负载。

Defender for Cloud 在管理资源和工作负载的安全性时满足以下三个需求:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_11_10.jpg

图 11.10 – Defender for Cloud

  • 持续评估 – 该解决方案将提供当前安全态势的简要概览。

  • Security recommendation – 该解决方案将使用 Azure 安全基准加强资源和服务的安全性,并推荐优先级较高的加固任务以及详细的修复步骤,以改善安全态势。

  • Defend – 该解决方案将检测并解决对资源、工作负载和服务的威胁。这些警报会出现在 Azure 门户中,也可以通过电子邮件发送。

以下示例展示了针对资源加强安全性并提高整体安全态势的推荐:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_11_11.jpg

图 11.11 – Microsoft Defender 推荐

Microsoft Defender for Cloud 具有更多功能,并且不断在增加新功能。在 Azure 中部署时,这是识别和管理安全风险的地方。

这部分讨论了用于监控运行时环境中的安全风险的各种技术。下一部分将介绍几种替代工具,用于执行前面提到的一些扫描任务。

其他工具

市场上有许多工具可以用于对应用程序代码和依赖项进行安全扫描。一些示例包括 WhiteSource、Black Duck、Veracode 和 Checkmarx:

  • WhiteSource 是 WhiteSource Bolt 的付费版本。它提供相同的服务以及更多功能。例如,它不仅在依赖项扫描时报告风险,还会在依赖项的最新扫描中出现新风险时发出警报。

  • Black Duck 是一款帮助团队管理使用开源软件相关风险的产品。它提供的服务与 WhiteSource 类似。

  • VeracodeCheckmarx 是代码扫描工具,用于识别易受攻击的代码。而 SonarQube 检查代码质量和安全风险,这两款产品则专注于安全风险。通常来说,它们在安全扫描方面更为出色,但缺点是价格较高。

  • Sonar Cloud 是 SonarQube 的托管环境,提供与 SonarQube 类似的功能。

  • CodeQL 是一种安全扫描工具,用于自动化安全检查。CodeQL 将代码视为可以查询的数据,并执行变种分析。变种分析是一种利用已知的安全漏洞作为种子,查找代码中类似问题的过程。Code scanning 是一种功能,允许您扫描 GitHub 仓库中的代码,以检测安全漏洞和编程错误。如果代码扫描检测到代码中的潜在漏洞或错误,GitHub 会通知开发者,并禁止他们提交额外的问题。

摘要

在本章中,您学习到 DevOps 和安全并不是两个相互冲突的目标,且 DevOps 实践可以帮助您加强安全性。首先,您学习了如何在持续部署流水线中处理密码和其他机密信息。接着,您学习了如何通过代码和依赖扫描工具增强流水线,同时将安全的“左移”原则应用其中。最后,您学习了如何使用 Azure Policy 来定义基础设施的约束和规则,以及如何自动应用这些规则,或对不合规的部署进行审核或自动拒绝。

通过您所获得的知识,您现在可以在公司内部与团队讨论如何解决 DevOps 团队中的安全问题。您可以与安全工程师合作,配置所使用的工具,并收到关于工作安全影响的自动反馈。

在下一章中,您将学习应用程序监控。此外,您将了解如何监控您的应用程序是否顺利运行,并收集运行时指标。

问题

以下是一些问题,供您测试对本章内容的理解。您可以在附录中的评估部分找到答案:

  1. 对还是错——确保软件交付的安全仅仅是部署流水线中的一个步骤。

  2. 哪种工具可以用于安全测试,通过代理识别有效的应用程序 URL,然后对应用程序进行各种攻击,例如注入?

  3. 对还是错——在大多数现代应用程序中,超过 50% 的代码库来自开源库。

  4. 在部署过程中或运行应用程序时,存储所需的机密信息的安全位置有哪些?(您可以选择多个答案。)

    1. 标记为机密的 Azure Pipelines 变量

    2. Azure Key Vault

    3. Azure DevOps Key Vault

    4. Azure 变量组

    5. Azure DevOps 安全变量

    6. Azure DevOps 服务连接

  5. 哪两种 Azure 产品可以用来在运行时检测安全风险?

进一步阅读

第四部分 – 闭环

DevOps 不仅仅是加速将优质产品交付到生产环境的能力。另一个非常重要的方面是观察和衡量使用情况以及其他关键性能指标。来自分析的洞察提供了至关重要的反馈,以塑造产品的未来,甚至帮助优先考虑其他质量举措,这些举措对于提高服务的整体可靠性至关重要。

本部分将介绍有效地为应用程序添加监控,以便收集可以更好地理解应用程序使用情况和用户行为的度量数据。持续学习的另一种方法是明确地从产品内请求反馈,以便用户在使用软件时可以分享宝贵的建议。通过这种方式,可以规划未来对最终用户体验的改进。

本书的这一部分包括以下章节:

  • 第十二章应用程序监控

  • 第十三章收集用户反馈

第十二章:应用程序监控

在前几章中,你了解了如何将 DevOps 原则应用于软件交付。你学会了如何从源代码管理到生产环境创建一条流水线。你还学会了如何确保交付符合要求并且安全,同时不牺牲速度或对业务价值交付的关注。本章中,你将学习如何将这条流水线转变为 DevOps 循环——一个持续交付新软件的过程,然后衡量你的应用程序的表现。这是一个持续的过程,因为你将评估应用程序在生产中的表现,并学习如何进行下一步。

为了实现这一目标,本章首先介绍了一种收集应用程序崩溃的方法。几乎所有应用程序都会在某个时刻抛出未处理的异常并崩溃。确保收集并报告应用程序崩溃,将帮助你调查其原因并进行修复。接下来,注意力将转向对应用程序进行仪器化。

仪器化是收集日志和指标的实践,帮助你了解应用程序在生产环境中的表现。你可以利用它们在出现问题时触发警报,或者希望在问题发生之前就能发现它们。本章最后探讨了与其他工具集成的几种选项。

本章涵盖的主题包括:

  • 调查应用程序崩溃

  • 仪器化 Web 应用程序

  • 与其他工具的集成

技术要求

为了实验本章中描述的技术,你将需要以下工具之一或多个:

  • 用于收集移动应用程序崩溃报告的 App Center 帐户

  • 用于收集桌面应用程序崩溃报告的 Raygun 订阅

  • 用于仪器化 Web 应用程序的 Azure 订阅

所有这些工具都提供免费试用选项。

调查应用程序崩溃

无论一个应用程序设计得多么完美,它最终都会因为某种意外情况而崩溃。为了从这些崩溃中吸取教训并尽量避免将来的崩溃,向应用程序添加代码以收集崩溃报告并将其发送到一个中心位置会有帮助。在那里,这些报告可以被分析和归类,以识别应用程序的改进方向。如何做到这一点取决于应用程序的类型。

以下章节讨论了移动和桌面应用程序如何工作。关于 Web 应用程序,收集崩溃报告可以使用与仪器化相同的工具;我们将在后面的仪器化 Web 应用程序部分讨论这一点。

收集移动应用程序的崩溃报告

用于收集移动应用程序崩溃报告和错误的众多工具之一是 Visual Studio App Center。除了分发移动应用程序,App Center还允许应用程序提交其崩溃和错误以供分析。

要开始使用 App Center 进行崩溃报告,首先需要定义应用程序。这被称为应用程序定义,如何处理它在第六章实现持续部署和发布管理中已经讨论过。通过这个应用程序定义,会创建一个应用密钥,用于配置应用程序发送崩溃报告。除了崩溃报告,还可以跟踪开发者感兴趣的其他错误和异常。要开始发送崩溃报告,需要执行以下步骤:

  1. 在项目中安装 Microsoft.AppCenter.Crashes NuGet 包。

  2. 将以下代码添加到应用程序初始化中:

AppCenter.Start("ios={appSecret};android={appSecret
};uwp={appSecret}", typeof(Crashes));

除了崩溃之外,还可以跟踪开发者感兴趣的其他错误。可以使用以下代码来实现:

Crashes.TrackError(ex);

所有未处理的异常都会被自动捕获并发送回 App Center。在这里,它们会变得可供分析,如下图所示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_01.jpg

图 12.1 – App Center 诊断概览

点击报告的错误或崩溃项以打开详细视图,如下所示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_02.jpg

图 12.2 – App Center 诊断详细视图

每个崩溃或错误会显示一个包含最重要信息的仪表板。这些信息包括报告数量和受影响用户的数量,还会显示受影响的设备类型和操作系统。在页面顶部,显示堆栈跟踪,开发者可以使用这些信息来调查并希望能修复该问题。

App Center 与 Azure DevOps、Jira 和 GitHub 集成,供 bug 跟踪使用。有关更多信息,请参考此链接:docs.microsoft.com/en-us/appcenter/dashboard/bugtracker/

对于任何关键事件,App Center 可以直接创建一个 bug 并发送电子邮件通知。

这部分涵盖了从移动应用程序收集崩溃报告和错误的内容。接下来的部分将介绍桌面应用程序中的相同概念。

收集桌面应用程序的崩溃报告

桌面应用程序也可以进行崩溃报告。对于桌面应用程序,有许多可用的解决方案,而且大多数的工作方式大致相同。其中一个解决方案是 Raygun。Raygun 是一个商业产品,适用于 .NET 应用程序,但也可以用于其他许多语言和平台。

使用 Raygun 收集崩溃的步骤如下:

  1. 注册一个 Raygun 账户。

  2. 在解决方案中安装 Mindscape.Raygun4Net NuGet 包。

  3. 捕获未处理的异常并将其转发到 Raygun。

以下示例演示了如何捕获并转发未处理的异常到 Raygun:

class Program
  {
    private static readonly RaygunClient _raygunClient = new RaygunClient("myKey");
    static void Main(string[] args)
    {
      AppDomain.CurrentDomain.UnhandledException += HandleEx; throw new Exception("Boom!");
    }
    private static void HandleEx(object sender, UnhandledExceptionEventArgs e)
    {
      _raygunClient.Send(e.ExceptionObject as Exception);
    }
  }

所有异常都可以在 Raygun 的 Web 界面中进行探索。在这里,如果堆栈跟踪足够相似,异常会自动分组。它们也可以被分组并单独浏览,但在大多数情况下,专注于较大的异常组更有意义。

以下截图展示了如何在 Raygun 中浏览这些组:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_03.jpg

图 12.3 – 桌面应用程序异常的 Raygun 视图

在此界面中点击异常消息将显示完整的堆栈跟踪以及任何发生的异常实例的所有共享属性。

这完成了我们对从移动和桌面应用程序收集崩溃报告的讨论。这样做可以让你发现并调查客户在生产环境中遇到的问题。接下来的部分将介绍 Web 应用程序的监控,以进一步增强我们对应用程序在生产环境中行为的洞察。

Web 应用程序的监控

Web 应用程序与移动应用程序和桌面应用程序在许多方面不同,其中之一是大部分应用程序的运行是由服务器而非客户端执行的。这使得开发人员比其他类型的应用程序更容易收集 Web 应用程序的运行信息。这就是为应用程序添加监控的过程。

日志是系统保存的文本消息,用于描述服务器执行的路径。这有助于开发人员回溯并通过检查日志输出来探索发生过的事件。结构化日志正迅速成为跟踪日志的标准。结构化日志是一种技术,其中日志不再仅仅是文本消息,而是带有每个参数值集的参数化文本消息。这有两个优势——日志可以更好地压缩,而且可以更快速地进行搜索。

度量指标是为应用程序记录的值。它们通常由时间戳、指标名称和值组成。一个例子是每秒记录一次 CPU 使用率的百分比。

在为应用程序添加监控时,容易专注于许多服务器级别的日志和度量指标。例如,许多操作员默认会开始收集诸如 CPU 使用率、内存压力和 I/O 操作等度量指标。虽然这些度量指标本身没有问题,但它们不一定能从用户的角度反映应用程序的性能。其他度量指标,如响应时间或队列消息处理延迟,可能会更好地提供关于用户体验的见解。虽然测量系统指标没有错(它们通常是未来问题的良好指示),但你也应该尝试收集以用户为中心的度量指标。

Azure 提供了 Application Insights 服务,用于对应用程序进行监控,重点是 Web 应用程序。可以通过 Azure 门户创建一个 Application Insights 工作区,该工作区会打开一个工作空间,如下图所示。在 Azure 门户的概述部分,监控密钥字段清晰显示,建议将其视为应用程序机密:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_04.jpg

图 12.4 – Azure Application Insights 概述

以下小节将详细介绍日志记录、度量和单个请求的调查。

日志记录

最基本的监控方式之一就是在应用程序代码中添加日志语句。过去,这些日志会保存到运行应用程序的服务器磁盘中。因此,获取和调查这些日志需要大量的时间和精力。

在现代托管环境中,日志不再保存在本地文件系统上,而是远程存储。由于基础设施的临时性,服务器可以随时增加或移除,因此无法再将日志保存在服务器上,并确保以后可以检索到。因此,这些日志会通过 HTTP 传输到专用的日志存储中,如 Application Insights。

生成日志

要从 ASP.NET 应用程序将日志条目写入日志存储(例如 Application Insights),必须执行以下两项操作:

  1. 需要在应用程序代码中使用 ILogger 接口生成日志条目(如适用)。该接口可以通过 Microsoft.Extensions.Logging.Abstractions NuGet 包使用。

  2. 需要安装 Application Insights NuGet 包(Microsoft.ApplicationInsights.AspNetCore),并将 Application Insights 注册为 LoggingProvider。这样,所有发送到前述接口的日志都会转发到 Application Insights 代码中。反过来,这段代码会将所有日志转发到 Application Insights 服务。

以下示例代码展示了如何使用类中的 ILogger 接口来生成结构化日志条目:

public class Example
{
private readonly ILogger<Example> _logger;public Example(ILogger<Example> logger)
  {
    _logger = logger;
  }
  public void DoSomething(User user)
  {
    _logger.LogWarning(
      "Doing something for user with id '{userId}' and username '{username}'",
      user.Id, user.Username);
    }
}

重要提示

日志条目开头不应有美元符号($)。这里没有使用字符串插值,但有两个占位符被插入到文本消息中。结构化日志条目会识别这些占位符,并在显示条目时插入提供的值。

在生成日志条目后,应注册一个日志提供程序来捕获这些日志。这个过程是通过 .NET Core 内建的依赖注入实现的。

启动应用程序后,所有级别为警告及以上的日志条目会自动转发到 Application Insights。要更改转发哪些条目以及哪些不转发,可以配置过滤器。本章末尾提供了有关如何详细配置 Application Insights 的链接。

搜索日志

在将日志条目发送到 Application Insights 后的几分钟内,它将出现在界面上供查询。为此,请打开 Application Insights 实例,并在左侧菜单中导航至 日志 (1)。这将打开如下所示的视图:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_05.jpg

图 12.5 – Application Insights 日志视图

在这里,可以编写查询 (2) 来搜索以 Kusto 查询语言 (KQL) 记录的日志。Application Insights 被优化用于处理大量数据,大多数查询能在一秒钟或更短时间内返回结果,即使是在搜索数百万条日志条目时。

针对日志设置警报

收集和搜索日志在排查特定情况或响应用户投诉时非常有用。然而,在某些情况下,当某个条件出现时,自动通知比手动搜索更为有效。这就是警报的作用。

在 Azure 中,可以创建警报规则,当满足某个条件时通知开发人员。警报功能由 Azure Monitor 提供,并与许多 Azure 服务(包括 Application Insights)集成。

要创建一个新的警报规则,请按照以下步骤操作:

  1. 使用门户导航到 Azure Monitor。

  2. 现在,选择 警报。这将打开如下所示的视图:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_06.jpg

图 12.6 – Azure Monitor 警报视图

如果有需要注意的警报,它们将在此处显示:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_07.jpg

图 12.7 – Azure Monitor 警报创建视图

使用屏幕左上角的 创建 按钮来添加新的警报规则。这样会打开另一个视图,如前面的截图所示。在这里,可以配置警报条件:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_08.jpg

图 12.8 – Azure Monitor 警报审查 + 创建视图

在前面的截图中,打开用于配置警报的视图——范围——如图所示。在这里,需要选择资源以创建警报。

  1. 这里的 (1) 是警报的资源主题。这可以是任何类型的资源,在这个实例中,警报将针对一个 Application Insights 工作区。

  2. 这些 (404 代码结果:

    requests
    | where success == False and resultCode == 404
    
  3. 400 代码结果。

  4. 评估警报条件的时间间隔 (2c):当指定一个匹配特定数字的查询时,这将决定必须满足该数量的时间间隔。

  5. 评估警报条件的频率 (2d):过于频繁地评估警报条件可能会导致警报频繁开闭,产生快速的警报序列。过于不频繁地评估警报条件可能会导致警报反应过迟。实验将帮助你了解如何配置这个参数。

  6. 这是在满足警报条件时执行的操作。由于可能有许多警报必须调用相同的动作组,因此可以将操作分组,并在此处引用这些操作组。一些操作的示例包括调用 Webhook 或发送短信或电子邮件。

  7. 警报配置通过输入名称和描述(3)来完成。

  8. 最后,警报可以保存。

在按前面的截图回顾并创建警报后,激活会自动完成,几分钟内,警报就可以开始检查应用程序日志并在满足警报条件时发出信号。

日志记录是深入了解请求发生了什么以及错误如何发生的绝佳方法。另一种了解应用程序行为的技术是使用度量。

度量

除了日志外,应用程序还可以发出一个或多个度量。度量是随时间变化的一系列值,描述系统的一个或多个方面。以下是一些度量的示例:

  • 当前登录的用户数量

  • 用户查看的产品数量

  • 数据库事务的数量

收集此类度量可以提供有关系统使用情况和当前操作方式的洞察。度量通常用于创建仪表板和警报。

发出度量

要开始使用度量,首先必须由应用程序发出度量并将其存储在集中位置。除了日志记录外,还可以使用 Application Insights 进行度量。

使用 Application Insights 进行度量时,需要采取以下步骤:

  1. 度量需要在应用程序代码中发出,使用TelemetryClient类。在Microsoft.Extensions.Logging.Abstractions NuGet 包中可以找到此接口。

  2. 安装Microsoft.ApplicationInsights.AspNetCore应用程序 Insights NuGet 包。

  3. 使用Dependency容器注册TelemetryClient。通过在容器构建器上使用扩展方法来完成此操作,如下代码片段所示:

    builder.RegisterType<TelemetryClient>().SingleInstance();
    
  4. 完成此操作后,应用程序即可开始发出度量。这是通过使用TelemetryClient类来完成的:

    public class Example
    {
    private readonly TelemetryClient _telemetryClient;
    public Example(TelemetryClient telemetryClient)
    {
    _telemetryClient = telemetryClient;
    }
    public void DoSomething()
    {
    _telemetryClient.GetMetric("doSomethingCalledCounter").TrackValue(1.0);
     }
    }
    

发出度量涉及两个步骤。首先,使用GetMetric()方法检索度量的引用。接下来,使用TrackValue方法提交一个值。提交的值应该是双精度浮点数或允许隐式转换为双精度浮点数的类型。

一旦度量被发出,它们可以用于创建图表和度量。然而,在继续这些话题之前,首先需要讨论另一种类型的度量——即 Azure 平台度量。

除了应用程序发出的度量外,还有许多可以从系统运行所在的 Azure 平台记录的度量。以下是一些示例:

  • CPU 使用百分比

  • 服务总线上的消息数量

  • 每秒数据库事务数量

  • 可用的磁盘空间量

这些指标通常与应用程序的性能密切相关,甚至可能是领先指标。例如,当可用磁盘空间达到 0 时,大多数 Web 服务器会停止工作。

在 Azure 中,每个服务默认会发出一系列指标,这些被称为平台指标。发出哪些指标因服务而异,且无法由用户影响。这些指标也会自动被 Azure Monitor 收集,并可以像应用程序发出的指标一样用于绘图和告警。

平台指标是集成的、免费的,并且大多数资源的指标会保留 93 天。

绘制指标图

所有收集到的指标,无论是在 Application Insights 还是 Azure Monitor 中,都可以用来构建图表和仪表板以可视化指标。可以使用每个 Azure 资源上都可以访问的指标选项卡来创建图表。也可以使用 Azure Monitor 来创建图表,这样就可以将多个资源的图表合并到一个画布中。操作步骤如下:

  1. 打开 Azure Monitor,它可以从左侧菜单中访问。

  2. 导航到指标菜单。这将打开如下所示的视图:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_09.jpg

图 12.9 – Azure Monitor – 指标

  1. 打开画布后,可以向其中添加一个或多个图表。图表是使用顶部的图表构建器构建的。在这里必须做出四个选择:

    • 需要为其绘制图表的资源。

    • TelemetryClient

    • 来自上一节的GetMetric()方法。

    • 将多个测量值合并为图表中的一个点的数学操作:可以选择最小值、最大值、平均值、总和或计数。

    • 要在同一个图表中添加多条指标线,请选择顶部的添加指标。重复前面的四个选择来配置新图表。

  2. 若要将此图表作为仪表板的一部分以便于重复使用,请点击顶部的固定到仪表板按钮。

  3. 然后可以通过右侧菜单直接访问仪表板:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_10.jpg

图 12.10 – App Service Http400 指标图

拥有某个指标的图表,或者在仪表板中拥有多个图表,对于调查问题非常有帮助。然而,没人喜欢一直盯着仪表板看事态进展。因此,也可以配置指标告警。

告警指标

就像日志条目一样,当某个指标超过或低于某个阈值时,可以通过 Azure Monitor 设置告警。需要后续跟进的日志条目可能仅与遇到问题的某个用户或客户相关。而指标则有助于检测所有用户都受某个问题影响的情况,或检测基础设施停止工作或即将停止工作的情况。

对指标创建警报的工作方式与从日志创建警报非常相似。要创建新的警报规则,请使用门户导航到 Azure Monitor,然后选择警报

调查请求

在使用应用洞察进行日志记录和度量时,您可以使用应用洞察的许多内置功能。其中一项功能是从一个称为搜索的视图执行针对应用洞察收集的所有类型数据的搜索查询。

在此处,可以搜索应用洞察收集的所有信息,包括以下内容:

  • 应用程序代码发出的日志,其中包括 NuGet 包和 .NET Framework。

  • 所有依赖调用:这些是对数据库和其他系统的调用,由应用洞察自动检测到。应用洞察记录目标系统和持续时间。

  • 所有异常:应用程序中发生的所有异常都会被应用洞察记录,即使应用程序代码已正确处理。

  • 请求:所有通过 HTTP 进入的用户请求都会被记录。还包括重要属性,如 URL、持续时间和 HTTP 动词。

要使用搜索视图搜索特定事务,请在 Azure 门户中打开正确的应用洞察实例,然后导航到事务搜索菜单(1),以获取以下截图显示的视图:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_11.jpg

图 12.11 – 应用洞察 – 事务搜索

事务搜索视图中,可以配置几个搜索参数(2):

  • 要搜索的时间间隔:默认为最近 24 小时。

  • 要搜索的事件类型:可以是请求、日志条目、页面查看、异常、依赖调用等。

  • 任何要搜索的文本。

几秒钟内,条形图显示所有匹配的结果。每个条形代表一个时间段,并显示在该时间段内有多少匹配项。在此图表下方显示所有单个匹配项。这些是所有可用事件类型的混合。

点击任何结果会打开一个新视图,显示选定的记录与所有其他类型的请求分组相关联的情况。这使您可以快速导航到应用洞察在单个用户请求执行期间收集的所有日志、依赖调用和异常。结果可以显示为列表和时间轴。

这使您能够快速查看服务器在执行用户请求时的操作:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_12.jpg

图 12.12 – 应用洞察 – 端到端交易详细信息

在所有这些用于调查应用程序并接收事件通知的手段下,决定创建哪些告警、哪些不创建是非常重要的,这不仅是为了创建一个健康的工作环境,也是为了平衡监控与新工作的关系。这是下一节的主题。

优化告警

一旦团队开始为应用程序添加指标并设置告警,首批告警就很快会出现。在这一点上,重要的不是仅仅响应告警,还要调查它们并关闭它们。告警还应当被评估,并视为学习的机会。

优化告警

创建一系列告警后,重要的是定期重新评估它们。通过这种评估,可能得出的两点结论如下:

  • 告警阈值变化:定期评估告警涉及查看一段时间内的指标,并观察当前告警阈值的情况。这可能导致得出结论,阈值设得太低或太高。

  • 消除重复项:查看一个月(或几个月)内触发的告警,很可能你会发现一个或多个告警组总是同时触发。例如,针对特定 Web 服务器设置的一组告警,可能是如此相关,以至于它们总是同时触发。一个常见的例子是 CPU 使用率和 HTTP 请求的平均响应时间,这两个通常会同时上升。如果是这种情况,值得考虑删除其中一个告警,或者将其中一个降级为仅警告。重复的告警增加了需要立即响应的项目数量,导致团队在没有明确好处的情况下承受更大的压力。

不断优化告警集不仅有助于减少浪费,还能防止所谓的告警疲劳。

告警疲劳

如果告警规则不不断地审查和更新,它们可能会对团队产生负面影响,尤其是当告警规则触发过于容易或过于频繁时,人们将不再正确响应它们。如果告警过多,团队成员会感到疲劳,对告警的反应变得麻木。无论这些告警是虚假告警还是实际告警,单纯的告警数量足以让人们进入一种不再关心的状态。

如果在团队中观察到这种情况,便是时候彻底改变告警的生成和响应方式了。如果不这样做,团队成员可能会生病或完全离开公司。

防止这种情况发生的一种方式是实施健康的值班安排。

捕获哪些指标

在讨论指标时,常常会有一个问题:应该发送和监控哪些指标?有许多可能的指标,关于这个问题也有更多的看法。作为一个良好的起点,以下是通常会为 Web 应用程序收集的一些指标:

  • 每分钟请求数、每分钟事务数或类似的指标:这是一个旨在捕获 Web 应用程序当前负载或吞吐量的指标。

  • 平均响应时间:这个指标捕获时间窗口内所有请求的响应时间。

  • 400 及以上的状态码通常会被记录。

当这三个指标被捕获并一起绘制成一个图表时,它提供了理解应用程序行为的第一步。让我们探索几个例子:

  • 当平均响应时间上升,但吞吐量(每分钟请求数)保持不变时,这可能表明托管应用程序的基础设施出现了问题。

  • 当吞吐量和平均响应时间同时上升时,这可能表明流量增加,当前的基础设施无法在相同的响应时间下承受如此高的吞吐量。

  • 当错误率上升,而其他指标保持不变时,这可能表明部署出现了问题,或者某个特定的代码路径开始产生(更多)错误。

当然,这些仅仅是例子,还有许多可能的场景。其他指标可以帮助排除某些特定场景或避免它们。例如,开始监控数据库负载百分比也可以帮助检测这三种场景的具体实例。如果数据库负载接近 100%,可能是时候将数据库升级到更高性能的层级,以便在相同响应时间下支持更高的吞吐量。

总结这一部分时,有一个最终的建议——在开始监控时,通常有一种倾向是专注于托管应用程序的系统。作为替代方案,也可以考虑监控那些对业务有直接影响的指标,或者反映用户满意度的指标,这些指标与应用程序的可用性相关。与仅仅监控系统相比,这种方法更接近于衡量业务价值。

以下是一些例子:

  • 在一个在线商店中,每分钟销售的书籍数量可以是一个非常有价值的业务指标。试想一下,如果通过 Azure Monitor 和应用程序代码中的自定义指标,能够几乎实时地获取该指标,这对业务的影响将有多大。

  • 对于一个在线阅读平台,虚拟翻页次数可以是一个有价值的指标,能够反映用户是否愉快地使用该服务。一旦该数字出现急剧下降或快速增长,可能表明出现了问题。

要找出在特定场景下哪些指标是有意义的,可能需要与业务或领域专家进行交流。

制定待命排班表

一旦配置了警报并开始触发,就没有必要设置警报在早上 8 点之前或下午 5 点之后不触发。换句话说,必须确保一定严重程度的警报即使在非工作时间也能得到跟进。

在许多引入警报的新公司中,存在一种隐性预期,即某些人在正常工作时间以外(除了完成常规工作任务)需要处理这些警报。有时,如果警报每年只触发一次或两次,而且没有关于响应时间的协议,这可能根本不会成为问题。

然而,在许多组织中——尤其是随着时间的推移——存在一种期望,即这些警报需要在一定时间内得到响应。此外,随着系统规模的扩大和复杂性增加,或者系统数量的增加,警报的数量也可能会增加。

应对这一问题的方式是制定待命排班表,并与工程师达成正式协议,明确他们的期望以及组织如何奖励他们的努力。这使得组织能够设定清晰的期望,并且工程师可以根据这些协议来管理自己的空闲时间。足够的系统停机时间可以帮助工程师在高压期之间放松,从而确保他们在待命时保持警觉,随时准备响应。

有很多资料讨论什么构成健康的待命排班表,什么不构成,而这里的关键词是健康。一些常见的建议如下:

  • 在非工作时间待命的人员不应在工作时间也待命。

  • 为待命的工程师提供合理的补偿,以奖励他们保持电话畅通、不受干扰等。什么是合理的补偿因情况而异,但待命的要求越高,补偿就应该越高。

  • 为待命人员提供合适的工具。例如,当期望响应时间为 30 分钟或更短时,为待命人员提供一个背包,里面装有笔记本电脑、电话和上网工具。

  • 确保每个员工在至少 75% 的时间内不需要待命。

  • 允许员工在换休时休假,这样如果他们需要在晚上响应警报,第二天上班时可以迟到。

每次系统正常运行被打断后,无论是在工作时间还是工作时间外,都可以进行现场事故审查,了解发生了什么,并探讨如何降低再次发生的可能性。

现场审查

当警报触发后,团队响应并解决问题后,便是评估发生了什么的时候。这就是现场事故审查。在此,整个团队会聚集在一起,讨论以下内容:

  • 发生了什么——首先,应该从事件被发现的时间开始,构建一个时间线,直到正常操作恢复为止。接下来,时间线会扩展,加入导致触发事件的相关事件。

  • 接下来,将评估一系列事件,以了解响应中哪些方面做得很好。如果团队成员之一使用了新工具快速诊断了问题,这可以让团队的其他成员也受益。

  • 只有在此之后,才是审视可能改进的点,并将这些点转化为团队的高优先级任务的时候。可能的故障保护被识别并安排实施,或是识别出新的警报,这些警报会在类似问题再次发生之前发送预警。

  • 触发初步响应的警报或警报组会被评估,以确定它们是否足够充分或可能包含重复的警报。

最适合进行现场事件回顾的时机是事件发生后尽可能快的时间。实际上,这意味着给每个人足够的时间休息和恢复,并计划在下一个工作日召开会议。

这完成了我们对Application Insights和 Azure Monitor 在仪表化 Web 应用程序方面的概述。接下来的部分描述了几种将 Application Insights 和 Azure Monitor 与其他工具集成的方法。

与其他工具的集成

Azure Monitor 和 Application Insights 是收集应用日志和指标的出色工具,同时也能存储它们并使其可搜索。然而,开发团队或企业可能有理由更倾向于使用其他工具来可视化应用性能或响应警报。集成的一个重要驱动因素通常是某个人或团队主要使用的工具。如果一个团队主要在 ServiceNow 或 Grafana 中工作,通常将这些工具与 Azure Monitor 集成,而不是强迫这些团队使用多个工具,是一种更有用的做法。

存在许多可能的集成,以下子部分详细介绍了一些例子。

IT 服务管理应用程序

在上一部分中,我们讨论了如何对 Web 应用程序进行仪表化时引入了操作组。操作组是执行响应警报时需要进行的一组操作。

除了丰富的内置功能外,还可以在现有的IT 服务管理ITSM)解决方案中自动生成警报。如果公司内已有 ITSM 解决方案,那么使用 Azure Monitor 时不需要创建独立的警报渠道。相反,使用 Azure Monitor 的 ITSM 连接器可以让你通过一个解决方案来管理全公司范围的所有警报。

目前,已有与 ServiceNow、Provance、System Center Service Manager 等工具的集成。这些连接是通过 ITSM 连接器创建的。

Azure Boards

在许多开发团队中,Azure DevOps 是开发人员花费大部分时间使用的工具。它也是他们通过 Azure Boards 进行待办事项管理的地方。

与此同时,运维人员(希望开发人员也能参与)在 Application Insights 中进行调查工作,以确定用户错误的原因并深入分析故障原因。这项调查工作可能会产生新的任务,需要在 Azure DevOps 中加入待办事项。

为了便于操作,可以通过以下步骤在 Application Insights 中配置与 Azure DevOps 的集成:

  1. 在左侧菜单中导航到工作项选项(1)。这将打开以下截图中显示的视图。在这里,可以配置与 Azure Boards 的连接:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_12_13.jpg

图 12.13 – Application Insights – 工作项集成

  1. 要配置连接,需要填写以下详细信息:

    • 输入 Azure DevOps 链接。在此,需附加组织的名称。

    • 选择要使用的 Azure DevOps 项目。可以从下拉菜单中选择。

    • 选择一个将创建新项的产品区域。默认情况下,这与项目名称相同,除非你更改它。

    • 提供用户名称作为新工作项的默认所有者。

配置此连接后,在 Application Insights 的相关页面上将显示一个新的**+ 创建工作项**按钮。此按钮允许你在待办事项中直接创建一个包含所有相关信息的缺陷。

Grafana

Azure Monitor 允许你构建简单、易于使用的仪表板。使用 Azure Monitor 仪表板的优势在于它们与所有其他 Azure 实践(如基于角色的访问控制RBAC)和 Azure 资源管理器模板)完美集成。

然而,团队可能已经采用了其他可视化工具,如 Grafana。Grafana 是一个著名的平台,适用于操作仪表板。Grafana 可以配置为使用 Azure Monitor 连接,并查询指标以进行图表绘制。Grafana 还具备告警功能。

要将 Grafana 连接到 Azure Monitor,需要执行以下步骤:

  1. 在你的 Azure 订阅所使用的 Azure Active Directory 帐户中创建一个新的应用程序注册。记下此应用程序注册的租户 ID客户端 ID订阅 ID客户端机密属性。

  2. 为应用程序注册创建一个新的 RBAC 角色分配,并至少在要监视的资源上设置Reader权限。

  3. 在 Grafana 中配置一个新的Azure Monitor类型的数据源。插入在步骤 1中收集的用于 Azure 身份验证的属性。

  4. 向仪表板添加一个新图表,选择Azure Monitor作为数据源。

通过执行前面的步骤,可以在几分钟内设置 Grafana 与 Azure Monitor 的连接。

总结

在本章中,您学习了如何开始完成 DevOps 循环。您还学会了如何处理崩溃报告,并从各种类型的应用程序中收集这些报告,以及如何为 Web 应用程序添加监控。您现在知道如何使用 Application Insights 集中日志和度量,并获取请求和依赖调用的洞察。您还学会了如何将 Azure Monitor 与其他工具集成,以进一步简化开发流程。

有了这些知识,您现在可以开始了解您的应用程序在生产环境中的运行情况。通过这样做,您不仅能更快地交付软件,还能从其使用情况中学习并开始改进。

在下一章中,您将学习如何收集用户反馈,以补充您从系统日志和度量中学到的内容。您还将学习如何衡量最终用户对您的应用程序和新功能的满意度。

问题

在我们总结时,这里有一份问题清单,供您测试自己对本章内容的理解。您可以在附录评估部分找到答案:

  1. 是否可以使用 Application Insights 从 Azure 平台服务中捕获自定义度量?——对还是错?

  2. 在 Azure Monitor 中,平台度量的保留时间是多少?

  3. 是否可以使用 Application Insights 从您自己的应用程序代码中捕获自定义度量?——对还是错?

  4. 当工程师因为收到过多警报而开始忽视这些警报时,这种情况被称为什么?

  5. 在 Azure 中,当警报触发时,是否可以调用 Webhook?——对还是错?

进一步阅读

第十三章:收集用户反馈

在前一章中,您学习了如何衡量应用程序在生产中的运行情况。您学会了如何收集崩溃报告和日志,以及如何对应用程序进行仪器化。然而,软件的目的不仅仅是交付完美运行的应用程序,而是创造业务价值。收集用户反馈是必要的,以确定您的应用程序是否也实现了这一更高的目标。在本章中,您将学习如何测量用户是否满意、他们使用哪些功能以及不使用哪些功能,以及如何利用这些信息来引导未来的开发。

为此,本章首先介绍了持续反馈的概念。接下来,它将介绍不同的方法来向用户请求反馈并记录他们的响应。这既可以是应用内的方式,也可以通过其他渠道进行。除了直接收集反馈之外,您还可以利用其他间接渠道。例如,在 Twitter 上对软件的反应和应用程序中功能的使用。最后,本章将介绍假设驱动开发,这是微软实践的一种软件开发方法。

本章将涵盖以下主题:

  • 理解持续反馈

  • 请求反馈

  • 收集间接反馈

  • 实施假设驱动开发

理解持续反馈

如在第一章中所解释的,DevOps 简介,DevOps 是一场文化运动,试图将开发人员和运维人员更紧密地联系在一起,以帮助他们更快速、更可靠地提供业务价值。反馈循环是实现这一目标的重要元素。在前一章中,我们看到了许多反馈循环:

  • 开发者可以在本地机器上运行单元测试,以验证他们的更改是否破坏了现有的行为。

  • 在源代码检入后,所有单元测试将再次运行,并启动更多测试的流水线。

  • 除了功能测试,还可以运行安全测试和依赖扫描。

  • 发布后,收集日志和指标以确定应用程序是否运行顺畅。

所有这些都提供了关于工作技术质量的反馈,现在是时候增加一个更多的反馈循环——一个旨在验证应用程序是否真正满足用户需求的循环。

尽管这听起来很明显,但比大多数开发者愿意承认的更容易被忽视。在许多公司中,对产品所有者或业务分析师有信心,他们被信任能预测用户需要哪些功能并按优先级排序。

我们知道软件开发是一项复杂的活动,其中变更的结果通常无法事先预测。在这种情况下,持续寻求用户反馈以确定功能是否提供了应有的价值是非常重要的。

持续寻求反馈将有助于做出如下决策:

  • 移除大多数用户未使用的功能;这样可以减少对这些功能的维护需求,从而降低成本,并释放开发时间。

  • 扩展用户最常使用的功能,使其在界面中更加突出。

  • 根据用户对应用程序的感知质量,增加或减少测试工作量。

进一步推理下去,我们可能会得出结论,无法预测一个功能是否会真正提供足够的商业价值来证明其存在的必要性。做此类工作的公司通常会采用假设驱动开发的做法,稍后将讨论这一点。

下一部分将介绍请求应用用户反馈的不同方法。

请求直接反馈

收集用户反馈的一个非常直接的方式就是直接向用户询问。近年来,越来越多的应用程序在其内部嵌入了反馈机制。其他常见的方法包括发布公开的产品路线图并直接与客户互动。

产品内反馈的优势

收集产品内反馈是获取直接用户反馈的好方法。产品内反馈的例子包括评分特定视图或操作,给出点赞或点踩,或发送开心或难过的表情符号。

收集产品内反馈具有以下优势:

  • 这是客户提供反馈最简单的方式,几乎不占用他们的时间。

  • 由于这种方法的非侵入性,许多终端用户可能会选择回应。

  • 记录的反馈可以是上下文感知的。

  • 在记录评分、表情符号或点赞和点踩反馈时,应用程序还可以记录当前状态和最近的用户活动,并将这些信息与用户反馈一起发送。这使得用户的一次点击比表面看起来更有价值。它能够快速洞察应用程序中最受欢迎和最不受欢迎的部分。

  • 最后,允许产品内反馈能让用户感到自己被听到和重视。

提示

当然,记录有关用户及其使用应用程序的数据需要获得他们的同意。你对收集用户信息的意图需要完全透明。同时,通常需要明确的内容选择加入(opt-in),并提供撤销先前同意的选项。具体要求因国家而异,是一个法律考虑因素。

这种反馈类型的缺点是,分析这些反馈可能会过于繁琐。此外,由于结果通常是匿名的,无法跟进反馈。这使得很难理解为什么用户对某个应用功能感到满意或不满意。有时,通过在反馈框下方添加一个复选框来反制这一点,复选框内容可能是我同意被联系讨论这个问题

如果你想理解用户反馈的原因,其他反馈机制,如访谈或焦点小组,可能更为合适。

拥有一个公开的路线图

另一种收集用户反馈的方法是公开分享当前待办事项中已完成的和未完成的任务。一个公开分享他们正在处理哪些功能的团队是 Azure DevOps 团队。当然,这个列表并不包含产品团队计划的所有功能。原因可能是为了保持竞争优势,或者为了保密一些新功能,直到重大公告发布。然而,他们的待办事项提供了一个关于当前正在开发的功能的良好洞察。

采用这种做法可以让产品的用户参与并评论这个公开的列表。用户可以请求将某些功能在优先级列表中上移或下移,并分享他们缺失哪些功能。

这能为公司带来以下好处:当用户参与反馈功能列表时,他们会被鼓励具体说明为什么提出某个请求。这可能提供关于客户需求的新见解,并可能导致优先级的调整。

这种方法也有一些缺点:

  • 并非所有用户都会参与并提供关于公开待办事项的反馈。这可能导致在提供反馈的群体中,偏向那些更为活跃或要求更多的客户。虽然这不一定是问题,但需要注意这一点。

  • 与用户就功能请求或他们希望在列表中上移或下移的功能进行互动可能非常耗时。尤其是与产品内反馈相比,这种方式需要更多的时间。

除了拥有公开的功能路线图外,还有其他方法可以让用户了解公司目前在做什么以及他们的计划。以下是一些例子:

  • UserVoice:UserVoice 是一个平台,允许用户提出新功能并对其他人提出的功能进行投票。它使得在不对用户开放实际待办事项的情况下收集用户的想法成为可能。

  • Bugtrackers:如果客户非常积极地报告应用程序中的错误和故障,开放一个 Bugtracker 可能会有所帮助。这允许用户查看哪些问题已知,并且是否以及何时可能被修复。

公开的待办事项和像 UserVoice 这样的反馈平台比开放的待办事项更为常见。公开的错误或问题列表更多地出现在开源开发中。

使用访谈或焦点小组

其他形式的用户反馈请求包括一对一面谈和焦点小组。尽管这些比开放式需求池和公开讨论更耗时,但它们也有利于选择更加平衡的用户。

例如,如果一个应用明显针对四个不同的市场段,那么有五个焦点小组可能是有利的——每个市场段一个,以及一个混合市场段的额外小组。前四个将使我们能够专注于每个群体的特定需求,而第五个将引发大量讨论,并揭示不同群体的不同愿望如何比较。

面谈和焦点小组还更适合不仅获取反馈,还了解用户的推理方式。面对面与用户交谈使我们能够探索他们的推理方式以及他们如何看待应用程序。

这里结束了对直接用户反馈的讨论。下一节将讨论间接用户反馈。

收集间接反馈

软件开发中一个众所周知的说法是用户不知道他们想要什么。虽然这听起来有些苛刻,但直接来自讨论、面谈和焦点小组的用户反馈并不一定导致良好的产品反馈的原因有几个:

  • 其中一个原因是每个人都想被喜欢。在进行面谈或与一群用户交谈时,他们可能只会说出他们认为面试官想听到的话。

  • 这需要很高的周转时间。安排面谈和焦点小组需要时间,找到每个人都能参加的时间可能需要数天甚至数周。

  • 每隔几周不断向同一组用户询问反馈是困难的。这在尝试确定功能质量是否随着最新更新而改善时尤为重要。

基于这些理由,减少请求反馈而是测量用户在功能级别上如何与应用程序互动,以及他们是否对应用程序所提供的价值感到满意可能更值得一试。

一种方法是通过测量应用程序中的用户行为,并基于此发出指标。在第十二章应用程序监控应用程序洞察引入了收集应用程序级指标的功能。虽然传统上用于发出有关应用程序性能的指标,但也可以用于发出有关应用程序使用情况的指标。以下是一些示例:

  • 每个页面访问频率有多高?

  • 特定操作执行多少次?

  • 完成某个视图需要多长时间?

  • 多少用户打开特定表单,却从未完成?

收集这些指标可以提供重要的见解,了解用户如何与应用程序互动以及他们使用或不使用的部分。

除了使用情况,用户满意度的另一个指标可以是 Twitter 情感或支持请求的数量。

情感分析

除了收集产品内的指标外,还有一些可以在产品外收集的指标。一个信息来源的例子是 Twitter。利用 Azure 云和机器学习算法,现在可以持续分析所有指向某个 Twitter 账号或话题标签的推文,并自动检测到突发的变化。

这甚至扩展到一个 Azure Pipelines 插件,它可以持续地衡量 Twitter 情感,并在情感过于负面时取消将发布进程推进到下一个阶段。这个插件作为一个管道门控实现,可以在Azure DevOps Marketplace中找到。

支持请求

就像 Twitter 情感一样,可能还有其他能够自动收集的用户满意度指标。持续收集每分钟的支持电话或电子邮件数量,并检测到某个突发的高峰,可能是用户出现问题的明确指示。利用机器学习和系统集成,这可以用于自动化响应或将用户引导到相关结果。

采纳这样的实践可以在发现生产问题时节省几分钟或几个小时。获取用户反馈并根据情感做出决策甚至可以走得更远。这就是假设驱动开发,接下来将进行讨论。

实施假设驱动开发

软件开发中的一个风险是,团队忙于创建越来越多的功能,以至于忘记了反思其业务价值,而大家都知道,并不是每个功能都是成功的。有些功能可能根本不会被使用,甚至可能会被用户讨厌。作为一个行业,我们已经意识到产品负责人很难预测哪些功能会受到用户喜欢,哪些不会。即使使用了之前讨论过的所有反馈机制,预测用户需求依然是困难的。

另一个需要认识到的重要问题是,产品中的每一个功能也都会带来未来的成本。每个功能都需要文档、支持和维护。这意味着不必要的功能也会推高成本。从这个角度来看,不仅要保留有价值的功能,甚至应尽早从产品中移除那些无价值的功能。

假设驱动开发是一种实践,它首先承认无法预测一个功能是否会增加价值、没有价值,甚至更糟的是,降低业务价值。接下来,它建议将待办功能转化为快速、轻量的实验,在产品中运行,以确定新功能是否会增加价值。

这样的实验可以以类似用户故事的形式写成,例如:我们相信用户希望通过一个新的单字段弹窗快速创建预约,而不是完整的对话框。我们确信这是事实,当我们看到超过 25%的预约是通过这个新对话框创建的,并且预约的平均批准率上升了 2 个百分点或更多时。第一部分被称为假设,第二部分是验证假设的确认标准。

一旦写下这些内容,就创建一个最小化实现的单字段弹窗,并使用指标监控它的使用情况以及原始表单的使用情况。根据测量结果,可能会发生以下情况:

  • 假设中提出的信念被确认是真实的,并且新特性增加了价值。更多与该特性相关的故事可以被添加到待办事项中,以增加产品提供的业务价值。

  • 假设中提出的信念尚未得到确认,且进一步的实验预计不会产生不同的结果。该特性已从待办事项中删除,当前的最小化实现甚至可能从产品中移除。

  • 假设中提出的信念尚未得到确认,但实验仍在继续。这种情况可能发生在有大量用户抱怨某个功能,而团队决心修复它时。如果一种方法不起作用,他们可能会尝试另一种方法。

采用之前提到的方法,团队可以通过减少在实验后确认不增加价值的特性上花费的时间,来提高他们对业务价值的影响,甚至将这些特性从产品中移除。

通常,假设驱动的开发会与分阶段发布机制如功能标志部署环结合使用。实验只会在一小部分用户中进行,这使得如果该功能未能增加足够的价值时,能够更容易地将其撤回。

这完成了关于收集和使用用户反馈以及用户反馈如何与 DevOps 目标(为最终用户提供业务价值)相关的讨论。

总结

在本章中,你学习了如何衡量软件开发活动的业务成果。首先,你了解了反馈的重要性,以及如何通过反馈帮助理解客户需求以及这些需求是否得到了满足。然后,介绍了多种请求反馈的方法,包括直接和间接的。

最后,你了解了假设驱动的开发以及实验心态如何帮助减少浪费。

通过这些知识,你现在可以选择并实施反馈机制,帮助你了解用户对你的应用程序的情感反馈。你现在能够采取基于实验的方法来创建软件,专注于增加价值的特性,忽略或甚至移除那些不增加价值的特性。

在接下来的章节中,你将学习容器的所有知识。容器正在迅速改变软件交付的方式,并且常常用于将 DevOps 原则应用于现有应用程序和新应用程序。

问题

在我们总结时,以下是一些问题,供你测试自己对本章内容的理解。你可以在附录中的评估部分找到答案:

  1. 判断题:公开共享路线图没有任何缺点。

  2. 在评估公共路线图上的用户反馈时,需牢记的一个重要问题是什么?

  3. 哪两个间接的用户满意度指标相对容易捕捉?

  4. 以下哪项不是假设的一部分,假设驱动开发中使用的假设?

    1. 假设

    2. 确认阈值

    3. 结论

  5. 面试或焦点小组相较于其他收集反馈的方式,具有哪两个优势?

进一步阅读

第五部分 – 高级话题

在本部分的最后,你将学习到在组织中采纳良好的 DevOps 文化的好处。你将探索一些可作为指导的情境,帮助你准备企业云采用计划,这可能会直接影响你的业务成果。在本书的最后,你可以通过参加模拟考试来测试自己是否为认证做好准备。

本书的这一部分包括以下章节:

  • 第十四章采纳持续改进文化

  • 第十五章通过 DevOps 加速云的采用

  • 第十六章容器

  • 第十七章规划你的 Azure DevOps 组织

  • 第十八章AZ-400 模拟考试

第十四章:采纳持续改进文化

团队部署的 DevOps 策略大多围绕着按照规定的一套实践不断地、重复地进行,每次发布迭代时都要执行这些实践。然而,高绩效团队以学习的心态来处理一切,并在过程中识别改进之处,以建立更好的纪律,并成为做事的高手,如有效的持续集成CI)/持续部署CD)实践以提高发布灵活性,监控部署以减少故障,并及时解决生产问题。

没有任何团队能够宣称他们在实施 DevOps 实践时是完美的。必须将持续学习的文化作为团队的必备要素。因此,聆听来自各方利益相关者的反馈是改善 DevOps 卫生状况的第一步。

此外,大多数 DevOps 工具供应商,包括微软,都会定期推出新的增强功能和产品创新。团队必须不断评估并规划采用这些最新的产品功能,以最大化生产力。采纳持续改进的文化对于在 DevOps 旅程中保持相关性至关重要。

本章重点介绍持续改进的概念,并讨论了组织可以利用的一些方法来不断学习。

本章将涵盖以下主要内容:

  • 衡量 DevOps 成功

  • 价值流映射

  • 数据驱动的方法

  • 将反馈循环落实为操作

衡量 DevOps 成功

如在第一章《DevOps 简介》中讨论的,定义有效的指标并根据这些指标衡量结果是确保 DevOps 投资成功的关键。这也为严格遵循 DevOps 实践并随着时间的推移改进提供了强有力的动力。

从这些指标中得出的见解,激励工程团队更加关注他们的不足之处。让我们通过一些例子来说明这一点:

  • 交付周期指标,如每次迭代交付的故事点数、整体生产力和每行代码交付的缺陷数量,为项目管理员提供了关于迭代进展和输出质量的见解。

  • 与自动化测试相关的指标,如测试通过率、代码覆盖率和未解决缺陷,为软件在发布和部署到生产环境之前的准备情况提供了洞察。

  • 在软件发布后,关于使用情况和用户活动的报告、健康监测指标以及错误数量会反映软件的采纳情况。

从分享的例子可以看出,仪表板和指标对团队的文化以及它所培养的习惯,如何实现更广泛的业务目标,具有重要影响。

关键绩效指标KPIs)分解为更小且更有意义的度量标准非常重要。以下是一些示例:

  • KPI – 交付时间:

    • 度量标准:冲刺速度,按严重程度划分的缺陷状态,静态代码分析结果等
  • KPI – 部署频率:

    • 度量标准:测试用例覆盖率,单元测试通过/失败率,构建自动化百分比,构建流水线数量,以及整体部署时间
  • KPI – 恢复服务的平均时间

    • 度量标准:事件解决时间,每日警报计数,服务响应时间等
  • KPI – 更改失败百分比

    • 度量标准:服务器异常,按严重程度统计的事件数量等

因此,我们可以得出结论:你计划衡量的 DevOps 指标越多,你将会在 DevOps 实践转型中观察到越显著的潜力和收益。

在下一部分,我们将讨论价值流映射的概念,以及它如何应用于减少你在 DevOps 生命周期中的浪费。

价值流映射

价值流映射VSM)是一个在制造业中非常流行的概念。它指的是创建精益流程的技术,即通过尽可能少的步骤为客户生产产品。这是一种改进任何业务工作流程或过程的重要方法,从而消除浪费和不必要的步骤,尤其是从客户的角度来看。

VSM 的主要目标是对任何给定的流程进行严格分析,减少不同团队成员之间所需的交接次数,从而提高整体效率和生产力。随着数字化转型的日益重视,组织正在重新定义其业务战略,并迅速调整现有的业务/IT 流程。整体目标是根据需要重新调整交付的价值的定义,以便更好地为客户服务。

在 DevOps 生命周期的背景下,这可以被视为识别一种精益方法,包含了仅为客户创造价值所需的步骤。DevOps 价值流作为优化驱动因素,进而影响人员、流程和产品。主要动机是最小化浪费,同时持续交付客户价值。

在开发生命周期的各个阶段中,工作流的可视化,包括产品构思、特性优先级排序、解决方案开发以及最终发布给客户,称为价值流图。

VSM 相关活动包括三个主要步骤:

  1. 首先,准备当前状态的基准。

  2. 其次,定义目标未来状态,并通过分析差距或改进区域重新设计流程。

  3. 最后,分析 VSM 带来的收益,以便进一步迭代。

受 VSM 活动影响的两个主要 KPI 如下:

  • 交付时间LT),也称为吞吐时间、响应时间和周转时间。基本上,这指的是从工作作为输入进入价值流的某个特定阶段开始,到完成并交付到价值流中的下一个阶段或团队的经过时间。

  • 处理时间PT),也称为加工时间、接触时间、工作时间和任务时间。基本上,这是一个人完成所有任务以将输入转化为输出所需的时间,适用于单个工作单位。

你可以在这里阅读更多关于如何将 VSM 应用于 DevOps 的内容:www.lucidchart.com/blog/value-stream-mapping-for-devops

在下一节中,我们将探讨管理团队如何通过将焦点集中在最需要关注的领域,显著受益于数据驱动的 DevOps。

数据驱动的方法

通过数据驱动的方法制定改进策略已被证明对大多数组织有效。通过采纳数据驱动的文化,提升 CI/CD 过程并加速软件交付和质量具有巨大的潜力。大多数高性能工程团队通过跟踪的各种仪表板和 KPI 获得见解,并利用这些见解识别改进的领域并进行相应的调整。

让我们来看一下数据驱动的 DevOps 的一些关键方面:

  • 客观地衡量重要事项:一切都从识别必须跟踪的重要指标和关键绩效指标(KPI)开始,所有的测量应该是定量的,而非定性的。有人说过,事实和数字不会说谎。测量项必须扩展到推导出具体可执行的项目。

  • 与基准对比报告:你使用的报告工具必须持续生成报告,以供各方利益相关者使用。必须定义一些初步的基准,并且报告应该跟踪与这些基准的偏差。任何偏差都必须突出显示以便采取措施。

报告和后续分析必须是一个定期的活动(至少每周一次,如果不是每天的话),以便尽早进行课程调整。

  • 自动化数据交付以便立即采取行动:及时获取数据以便采取纠正措施非常重要。因此,我们必须依赖现有的自动化工具,或探索更多机会以改进数据捕获和通知流程。如今大多数 DevOps 工具都具备丰富的自动化功能,使得决策更加容易。

例如,当拉取请求PR)提交时,构建运行会检查变更的质量,并且如果有任何自动化测试失败,它可以立即向开发者发送电子邮件。这样,开发者可以修复问题并重新提交他们的更改,而不是等待几个小时才能得到完整的结果。

  • 为决策者提供洞察:衡量数据驱动的 DevOps 流程的成功对于任何组织都至关重要。通常有两个关注领域——首先是提供有关工程生命周期健康状况的洞察的 KPI,其次是作为领导团队反馈的主要 DevOps 成熟度指标。

团队还必须定期进行数据审查和分析,以识别改进机会。使用因果分析与解决方案CAR)和鱼骨分析等技术可以帮助团队识别问题的根本原因,并采取相应的行动。你可以在文末的进一步阅读部分找到更多相关资源。

在下一节中,我们将探讨反馈循环如何有助于持续改进。

反馈循环的操作化

反馈循环的概念起源于系统思维。每个组织都可以被建模为一个系统,即指由人、流程和工具相互连接的生态系统,它有序协同运作以实现业务目标或结果。反馈是系统思维中的一个重要概念,其中刺激有助于控制系统的输出。

如果你对反馈循环这一术语不太熟悉,可以将其想象为实体或过程之间相互连接的关系,其中一个变化会导致第二个变化,最终再反作用于第一个变化。这就像是一个因果链,其中事件或活动的结果产生的数据被用来通过控制原始输入行为来调节结果。下面是反馈循环的简化视图:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_14_01.jpg

图 14.1 – 简单反馈循环

组织中的 DevOps 流程可以通过识别与持续改进目标相一致的适当反馈循环,进行系统思维分析。反馈循环有两种类型:

  • 强化反馈循环:第一个实体输出的正向变化或增加会导致第二个实体的增加(正反馈),最终导致第一个实体的进一步增加。

例如,随着团队生产力的提高,总体速度增加。然而,存在一个拉伸极限,超过这个限度,质量可能会受到影响。

  • 稳定/平衡反馈循环:第一个实体输出的正向变化或增加作为信号,促使第二个实体减少(负反馈),最终导致第一个实体的输出进行调整,将其重新带回平衡状态。

例如,当团队专注于 CI/CD 过程中的更多质量相关检查时,这会增加整体构建时间,从而减少发布的灵活性。因此,团队随后被迫优化步骤,以便将发布的灵活性恢复到最佳状态。

在下一部分,我们将探讨设计有效反馈循环的重要性。

实施有效的反馈循环

从之前研究的示例来看,很明显并非所有的反馈循环都是重要的。因此,组织必须设计更有效的反馈循环,并放大正确的循环,以在交付灵活性、产品质量和软件发布速度之间达到正确的平衡和取舍。以下是一些初步指导建议:

  • 确保自动通知能及时得到处理,并进行定期的根本原因分析,以减少其发生。

  • 利用 VSM 技术来发现任何没有增加价值的冗余反馈循环。

  • 在反馈系统中实现稳定性与积极变化之间的正确平衡。通常,稳定性比速度更为重要。

  • 让关键利益相关者参与到反馈循环中来。人际互动可以提供更具实践性和背景性的指导,这对你的团队可能非常有益。

  • 利用操作遥测和度量指标作为关键反馈,以改进你的 DevOps 实践。

有一句流行的说法,"一刀切"的做法在任何情况下都无法奏效。因此,需要谨慎规划,以识别对你的组织和团队背景重要的反馈循环。

总结

在本章中,我们回顾了一些促进持续改进过程的重要技术。为了获得 DevOps 的真正好处,组织应在最高水平的成熟度下运营。然而,由于许多有时超出控制的因素,这种情况很少发生。因此,通过建立持续改进的文化,团队可以确保流程、方法和实践尽可能高效和有效。

遵循系统化和结构化的持续改进方法对团队来说可能是相当有益的。这需要组织对持续学习的承诺,以及团队在审查和建议渐进改进方面的开放态度。必须指定专门的角色来定义、规划和监控持续改进的举措。

此外,必须为所有人员规划定期的 DevOps 相关主题培训,作为自驱动团队的刺激来源,以便他们保持对组织 DevOps 改进的承诺。团队文化是通过展示在各种 DevOps 实践中的专业知识来实现工程卓越的基础。

在下一章中,我们将探讨组织如何通过 DevOps 加速其云转型之旅。

活动

  • 组织你的团队并进行头脑风暴会议,最好使用白板工具。

  • 创建三个垂直泳道——保持改进,和丢弃

  • 使用便签纸,建议你的团队将他们的想法发布到白板上。基本上,识别现有的流程,并将它们分组到适当的泳道中。

  • 认真分析被归为“丢弃”类别的项目,然后验证它们在实现质量和效率的总体目标时,是否为其增加了任何价值,特别是从客户的角度来看。

  • 同时,识别现有流程的改进领域,可以通过简化流程或进行变更来实现。

  • 与管理团队发布你的发现总结。

进一步阅读

第十五章:15

通过 DevOps 加速云 adoption

数字化转型的计划侧重于利用现代和新兴技术在市场中提供竞争优势。采用基于云的技术已成为其中的重要组成部分。同样,DevOps 在加速云 adoption 旅程中也扮演着至关重要的角色。

然而,组织必须首先拥抱实验文化,摆脱过时的工作方式,转向精益且迭代的软件开发方法论。DevOps 提供了恰到好处的工具、实践和文化理念,使得组织能够采纳云平台并快速交付高质量的应用程序。

本章将涵盖以下主要内容:

  • DevOps 在数字化转型中的角色

  • 现代化与云 adoption

  • 管理软件交付的现代化

  • 敏捷转型与迭代规划

  • 将 DevOps 整合到云 adoption 计划中

DevOps 在数字化转型中的角色

对于任何企业来说,数字化转型就是利用现代和新兴技术为客户创造价值,并最终为更高的收入创造机会。为了在竞争激烈的市场中生存,别无选择。

DevOps 凭借其全面的理念,致力于最大化人、流程和工具的优势,从而增加组织成功的机会。随着对自动化的高度关注,现代云平台的发展消除了许多之前存在的瓶颈。高质量产品的上市时间大大缩短,同时所需的资金也减少了。DevOps 的核心是优化,能够在相同的资源和人员条件下实现更多。它旨在通过技术改善任何现有的业务流程。此外,开发和运维团队目标的融合为团队之间更好的协作提供了合适的合作氛围。

DevOps 在数字化转型中的角色包括以下内容:

  • 推动文化心态的变革,鼓励自动化的采纳

  • 通过打破组织的壁垒,促进团队之间的协作,从而提高整体劳动力的生产力

  • 减少与任何手工或低效过程相关的浪费和成本

  • 加速产品创新周期,从而缩短上市时间

  • 创造机会以最小的干扰现代化现有的 IT 资产

在接下来的章节中,我们将回顾 DevOps 在组织现代化和云 adoption 过程中所带来的好处。

现代化与云 adoption

尽管云技术已经存在了一段时间,但它们对企业的影响在 Covid 疫情爆发时(2020 年初)变得显而易见。那些已经投资于业务现代化的组织能够在最小或没有影响的情况下生存下来,而许多传统企业则遭受了巨大损失。这里有一篇有趣的文章,解释了疫情的影响以及未来工作将如何展开:www.mckinsey.com/featured-insights/future-of-work/from-surviving-to-thriving-reimagining-the-post-covid-19-return

IT 和业务领导者意识到,采用云计算技术是提供服务的前进方向。IT 不再仅仅被视为一种支持工具;相反,它成为了在市场中生存的重要工具。现代初创公司通过利用技术创造差异化的价值主张来吸引客户。企业也已经开始效仿,数字化转型旅程中的关键战略之一就是云计算的采用。

虽然云计算和 DevOps 是相互独立的概念,但后者对于通过云技术的采用来实现商业目标至关重要。因此,DevOps 已经成为企业确保业务持续性的核心优先事项。无论是优化 IT 支出、简化开发流程、团队间协作、提供更高的服务可靠性等,DevOps 都涵盖了您 IT 战略的方方面面。

DevOps 是现代化的基础

有一句流行的说法,任何结构都注定会在没有坚实基础的情况下崩溃。同样,在现代化旅程中,围绕您的 DevOps 实践建立严格的流程至关重要。

DevOps 在现代化中的关键好处如下:

  • 通过自动化提高敏捷性

  • 通过更好的内部协作提高生产力

  • 更高的客户和员工满意度

DevOps 推动云计算的采用

云计算及相关技术,如自动化、人工智能AI)、设备等,为您的业务开辟了广阔的可能性。生产力和敏捷性的提升带来了盈利,自动化降低了 IT 成本,实时监控和反馈循环改善了客户体验。

DevOps 在云计算采用中的关键好处如下:

  • 基础设施现代化的自动化、按需供应和扩展

  • 减少 IT 管理开销,将许多任务外包给云服务提供商

  • 与多种其他平台或产品的无缝集成

  • 增强的部署敏捷性,提高市场进入时间

在下一部分,我们将回顾 DevOps 如何影响企业内部任何软件现代化计划的路线图。

管理软件交付现代化

随着组织开始现代化旅程,它们需要准备一份具有明确目标和目的的路线图,以便衡量其成功和结果。通常,DevOps 实践影响软件交付现代化的四个主要支柱,即 软件生命周期管理解决方案架构自动化实践云平台采纳

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_15_01.jpg

图 15.1 – DevOps 对软件交付现代化的影响

让我们在接下来的部分中回顾 DevOps 在四个支柱中的角色。

软件生命周期管理

组织必须采用迭代开发方法论,以实现发布过程的更高敏捷性。敏捷和看板方法比传统的瀑布式软件开发生命周期方法更能提供灵活性和适应性。

解决方案架构

所有现代化旅程通常涉及两组行动:

  • 将遗留应用程序迁移到基于云的平台

  • 利用创新技术开发新软件产品

两者都需要将目标解决方案架构目标从传统的单体架构转向更加微服务化的架构。然而,对于遗留工作负载,将会面临影响其转型的挑战。

团队通常部署三种关键策略来支持云采纳旅程中 IT 资产的现代化:

  • 重新托管 – 识别属于提升和迁移类别的资产,并将其迁移到新的云平台基础设施。这些通常是独立应用程序,依赖关系最少。这为企业提供了从云端启动运营的即时能力。

  • 重构 – 这通过对应用程序进行小的结构性改动并重新包装,以充分利用云平台的功能。

  • 重建 – 某些应用程序(通常占现有资产的 10-15%)必须重新设计,以便充分利用云平台的功能。这些应用程序必须完全重新开发,并采用云原生架构。

DevOps 实践,如 基础设施即代码配置管理测试自动化应用性能监控,可以在提高迁移过程的整体效率中发挥重要作用。

自动化实践

自动化是更快交付市场的关键。在 DevOps 中,你将开发和运营流程合并成一个统一的自动化管道,使所有软件组件不断地构建、集成、测试和部署。你淘汰任何手动流程,目标是实现软件开发的 100%自动化。这确保了整体质量,并提高了发布软件的可靠性。

云平台采纳

使用云原生设计方法实施所有软件产品和解决方案。这提供了更高的效率,从而使组织能够专注于其核心业务优先事项,而不是管理基础设施。基于平台即服务PaaS)模型构建的解决方案提供更好的可扩展性和可管理性,能够快速适应不断变化的客户需求。平台供应商提供的现成监控能力使得检测故障和采取纠正措施相对容易。

在接下来的部分,我们将讨论如何在云转型过程中采纳迭代规划,以交付价值。

敏捷转型和迭代规划

敏捷转型指的是在组织内采用基于敏捷的项目规划策略,以实现其愿景。所有团队都按照敏捷方法论的核心价值观和原则进行工作。因此,你可以观察到团队整体文化和行为的显著变化。

敏捷项目管理的核心是逐步交付商业价值,同时保持应对变化的灵活性。像其他实践一样,规划也必须是持续进行的。将项目组合(或产品待办事项)与业务目标和计划对齐,并分配团队执行这些任务,同时根据客户需求或业务优先级的变化不断调整。

转型路线图

创建敏捷转型路线图从来都不容易,因为每个团队及其需求都是独特的。然而,通过遵循敏捷原则,你可以推导出一个敏捷转型路线图,作为团队的某种蓝图。

一个高层次的敏捷转型路线图示例大致如下:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_15_02.jpg

图 15.2 – 转型路线图

更详细的敏捷转型路线图应捕捉关键的里程碑,这些里程碑可以作为创建更详细计划的基础。详细计划将捕捉更多有关路线图项目和实现这些项目的行动计划的信息。这些计划有助于将团队的思维方式转向实现敏捷转型。

你可以在这里阅读更多关于迭代规划最佳实践的内容:www.scaledagileframework.com/iteration-planning/

在下一部分,我们将回顾如何通过案例研究准备云采用计划。

在您的云采用计划中整合 DevOps

DevOps 和云采用已经从根本上改变了团队构建和部署应用程序的方式。事实上,在过去的几年里,组织通过采用 DevOps 实践,真正意识到了云平台的强大潜力。

微软提供了云采用框架,其中列出了组织可以采用的某些原则和指导方针,以制定云采用计划。您可以在此处了解更多有关微软 Azure 云采用框架的内容:docs.microsoft.com/en-in/azure/cloud-adoption-framework/overview

微软还提供了有关使用微软良好架构框架在云端构建应用程序的优秀指导。您可以在此处阅读更多内容:docs.microsoft.com/en-us/azure/architecture/framework/

在下一部分,我们将考虑一个案例研究,并了解一些关键的 DevOps 策略,这些策略可以在组织的云采用过程中应用。

案例研究

作为本案例研究的一部分,我们将考虑一个情况,其中名为 Packt 保险公司的公司希望对其应用程序进行现代化,并将其部署到 Azure 云平台上。

重要提示

本案例研究旨在模拟现实世界中的场景。然而,它并非旨在全面覆盖所有业务需求或场景。

关于 Packt 保险公司

Packt 保险公司是一家在 10 多个国家(涵盖美洲和欧洲)有业务的公司,向客户提供广泛的保险产品和服务。

在过去的几年里,Packt 保险公司的年增长未能与市场机会相匹配。由于缺乏市场适应性、创新周期过长以及由于使用传统的业务线LOB)应用程序而导致的员工生产力低下和协作不畅,它逐渐在竞争中处于劣势。其云平台的使用非常有限,大多数应用程序仍然是本地部署解决方案。

在最近召开的董事会会议上,团队决定通过云采用计划加速数字化转型进程。Packt 保险公司希望通过云优先和移动优先的核心战略,甚至对其业务应用进行现代化。

在接下来的章节中,将提到关键的业务驱动因素和利益相关者的观点。对于这个案例研究,它旨在展示每个利益相关者如何看待业务问题及其对目标解决方案的要求。

关键的业务驱动因素

  • 在接下来的 2-3 年内,成为一个基于云的数字化企业

  • 提高推出新服务的速度,使其与市场趋势保持一致

  • 在新的地区和地理位置扩展业务

利益相关者的优先事项

  • 首席执行官

    • 实现超过 10-15%的增长,通过扩展产品供应、扩大分销渠道,并加强与渠道伙伴的整合。
  • 首席技术官(CTO)

    • 我不想预先投资于 IT 基础设施,而是随着业务扩展逐步增加支出。

    • 我想了解我们业务单元的盈利能力。我希望能获取能够帮助我做出决策的业务洞察。

    • 很高兴了解客户对我们喜欢和不喜欢的看法。

    • 我希望在这个领域被称为技术创新者/先锋,并吸引新一代技术精通的人才。

  • IT 运营

    • 采用现代实践,为企业的基于云的解决方案开发和部署。

    • 确保符合安全和数据隐私标准。

    • 新分支办事处的入职应快速且无缝。

  • 产品经理

    • 将新保险产品的周期时间从当前的 6-8 个月减少到最多 2-3 个月

    • 如果精算规则可以直接更新而无需任何 IT 干预,那将是非常好的。

现代化路线图

Packt 保险公司的高管们已将其核心 LOB 应用现代化的 IT 计划划分为三个阶段:

https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_15_03.jpg

图 15.3 – 现代化路线图中的阶段

在上述图中,您可以看到以下内容:

  • 第 1 阶段 – 在此阶段,将发布面向最小可行产品MVP)的优先能力列表。此阶段的目标是快速使平台的第一个版本运作起来。

  • 第 2 阶段 – 这是第 1 阶段的延续,团队将启动下一组优先级能力。通常在这个阶段,将发布首个版本的移动应用程序和 Web 门户。

  • 第 3 阶段 – 这将是持续创新阶段,其中利用 AI 和机器学习能力推动新的产品提供和改进整体部署的数字服务。

常见挑战及 DevOps 的解救

Packt 保险公司的团队采用了 DevOps 实践和习惯,激活了云转型旅程的潜力。

团队采取的各项行动的高级摘要在此处给出:

  • 云上线和治理 – 它建立了一个云卓越中心CCoE),整合了运营和开发团队,并为云基础设施建立了治理程序。

  • 组织变革管理 – 它组织了关于敏捷方法和现代 DevOps 实践的培训,更加专注于推动文化变革。

  • 项目组合管理 – 它定义了关键的业务目标,确定了产品和服务的列表,并创建了执行的敏捷团队。

  • 持续规划 – 它创建了高层次的发布里程碑,然后根据这些里程碑优先处理待办事项。团队计划在前 6 个月发布 MVP(最小可行产品),然后根据已识别的阶段计划每 3-6 个月发布一次增量的重大版本。

  • 自动化生命周期 – 它投资于自动化实践,以提高开发、测试和产品部署的可预测性。工程团队在不妥协质量的情况下达到了良好的开发速度。

  • 传统工作负载迁移 – 它最初部署了一个混合云设置,保留了一些本地应用程序。然而,在适当的时机,这些应用程序被淘汰并为云环境重建。

  • 衡量成功 – 它识别了关键的 DevOps 指标并有效地跟踪这些指标,以衡量其成功。

  • 使用的 DevOps 工具 – 它使用了 Azure DevOps、GitHub 和 Azure Monitor 作为实施各种 DevOps 实践的主要工具。

因此,我们可以观察到 DevOps 影响着软件开发生命周期的所有领域,并且影响着组织内的变更管理。

总结

在本章中,我们回顾了云平台的采用如何减少市场发布时间,并创造推动业务转型的机会。无论是通过自动化管理云基础设施,利用监控能力优化 IT 支出,还是规划和发布优质产品,DevOps 都涉及到云基础数字化转型过程的方方面面。

云技术还使得团队能够在远程地点工作,以支持混合工作环境。云技术使团队能够使用所需的工具进行协作,而不会浪费任何时间或功能。研究(DORA 报告)表明,随着时间的推移,DevOps 和云采用将在未来几年大幅增加,直到它们成为所有组织的常态。总的来说,我们可以得出结论,当执行得当时,DevOps 和云采用策略能够显著影响组织的盈利能力。

在下一章中,我们将探讨在构建可扩展应用程序时使用容器的方式。

额外阅读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值