2016 年 8 月

第 31 卷,第 8 期

DevOps - 将 DevOps 应用到软件开发项目

作者 Willy-Peter SchaubWouter de de | 2016 年 8 月

“DevOps 可将人员、过程和产品联合在一起,能够向我们的最终用户持续交付价值。”—Donovan Brown,《DevOps on the Microsoft Stack》(Microsoft 堆栈上的 DevOps)(Wouter de Kort,2016)。

每个 DevOps 历程始于想要根据学习区域性和持续交付价值来实现一种解决方案。本文的目标是共享我们在针对开发、用户验收测试和生产环境实施自动化发布管道探索过程中收集的学习内容。我们将为你演示自动发布管道,你可以“原样”采用或进行演变以满足自身需求。

那么我们为何决定使用 DevOps? 随着我们逐渐熟悉生成扩展的“原因”(目标)、“内容”(功能)和“方式”(技术、代码),我们需要一个区域和环境来生成、测试、发布和监视快速演变和增长的扩展系列。DevOps 的承诺鼓励我们探索和使用 Visual Studio Team Services(简称 Team Services)提供的进程和工具。我们自发组织的自治性团队能够改善区域性和管道以将可降低发布周期时间从混乱、容易出错且经常需要手动操作的数天变为数分钟。本期另一篇文章中讲述了一个类似的管理案例和说明(“从代码到客户: 探究移动 DevOps”)。

如果你不熟悉 Rangers,我们是由许多内部和外部工程师组成的社区,这些工程师与产品组协作来为开发者社区提供专业指南、实践经验和漏洞补充解决方案。正是漏洞让我们对扩展感到兴奋并乐于致力于扩展。

扩展可为你提供 Team Services 和 Team Foundation Server (TFS) 的集成和扩展性体验。扩展点包括工作项窗体、生成和发布任务、仪表板小组件、菜单操作、敏捷和其他中心。这些可使你提供漏洞补充解决方案、混合和改善产品、UX 和工作效率。

典型的扩展包括一组 JavaScript、HTML 和 CSS 文件,请参见 Willy P. Schaub 2015 年的博客“Extensions 101—Attempting to Visualize the Main Processing Flow”(bit.ly/28Yfj7A)(扩展 101:尝试可视化主处理流)。一个或多个 JSON 清单文件描述基本信息、包含的文件以及扩展提供的发布内容。请参见开源文件夹管理扩展示例,借此可从 Web 在 Team Services 源存储库中快速创建文件夹,无需本地克隆存储库或安装额外工具。

基于 JSON 的清单(默认称为 vss-extension.json)中描述了每个扩展。为了保持一致,我们选择所有将来的扩展均基于 Team Services 项目模板,所有 JavaScript 代码均基于 TypeScript。节点包管理器 (NPM) 用于下载外部依赖项,如 TypeScript IntelliSense 所需的类型化库。我们利用 NPM 功能来定义一组基本脚本以初始化开发环境。一致性可确保团队成员轻松在团队之间移动并可更方便地调查和解决问题。缩短周期时间!

手动发布扩展

如果将文件夹管理存储库克隆到本地开发计算机,可以快速手动将扩展打包并发布到应用商店帐户。以下是具体方式:

  • 使用 NPM 脚本任务运行程序 (bit.ly/28Qmktu) 或从命令行运行命令。
  • 打开解决方案并运行设置任务:npm run setup。这将下载 NPM 程序包,初始化 TypeScript 所需的类型化并将外部依赖项放入正确的位置。
  • 使用 Visual Studio 来编译 TypeScript 文件并生成输出 JavaScript。
  • 运行程序包 NPM 任务以根据项目中的清单创建输出 VSIX 文件。
  • 将生成的 VSIX 上载到应用商店或运行 npm run publish 以自动打包和发布扩展。

但首先是一些背景介绍。Team Services 由孤立的帐户组成。应用商店是全球性的且由发布者组成,并由库发布者(你)创建和管理。以私有形式发布扩展并由 Team Services 帐户显式共享。或者,经验证后以公有形式发布扩展,使其对所有人可见。我们强烈建议不要以公有形式发布此扩展或其他示例扩展以避免混淆或给 UX 带来不良影响。

要发布扩展,请确保清单中的发布者字段与应用商店发布者名称匹配。如果发布者未经 Microsoft 验证,仅可以私有形式发布扩展。要从命令行或 NPM 任务运行程序发布扩展,还需要个人访问令牌以授予管理应用商店发布服务器的权限。请参见文章“Publish an Extension to the Marketplace”(bit.ly/28SDsOM)(将扩展发布到应用商店),了解更多详细信息。

自动化生成和发布管道

随着扩展和修订系列的增长,这些看似简单的手动步骤将很快变得费力且容易出错。因此,我们开始使用自动化管道,即使用脚本和生成任务自动执行手动步骤。

可使用 Windows PowerShell 和命令行生成任务打包扩展清单并修订版本号,如图 1 所示。有关更全面的描述,请参见文章“Our First Steps of Embracing DevOps When Building Visual Studio Team Services Extensions”(aka.ms/t0wfh6)(生成 Visual Studio Team Services 扩展时使用 DevOps 的首要步骤)—简单高效!

图 1 Windows PowerShell 生成任务(顶部)和命令生成任务(底部)

工具 Windows PowerShell
Arguments cha -command "(Get-Content vss-extension.json).replace('0.0.1', ('%BUILD_BUILDNUMBER%').replace('SampleData ',"))  | Set-Content vss-extension.json" rt
 
工具 tfx
Arguments extension publish –token $(PublishExtToken) –overrides-file $(ManifestOverrideFile) –share-with $(SharedAccounts)

或者,可使用扩展的生成和发布任务优化生成-发布流程。本文其余部分均基于此扩展。

我们来探索下如何将使用扩展的生成和发布任务以及如何为所有其他扩展项目实施蓝图。每个扩展均在孤立的 Team Services 帐户中开始历程,这是部署扩展的第一个阶段。Release Management 将这些阶段称为环境;因此,我们将其称为开发 (DEV) 环境。然后是在单个用户和产品所有者验收 (BETA) 环境中进行一系列设计、代码、特性、UX 和性能验证。与开发环境类似,这是一个孤立的 Team Services 帐户且是部署扩展的第二个阶段。一旦扩展满足完成的定义 (bit.ly/28PLYyi),将部署到应用商店并对所有人可见。可识别发布管道成型的 DEV → BETA → PROD 阶段。

若要针对自动化管道准备扩展项目,我们建议对扩展清单进行以下更改,如图 2 所示:

  • 将版本设置为 0.0.0 并将发布者设置为空字符串 (“”)
  • 将扩展标记为私有(公有:false)
  • 删除 galleryFlags 属性

图 2 清单文件提取

{  "manifestVersion": 1,
  "id": "FolderManagement",
  "version": "0.0.0",
  "publisher": "",
  "name": "Folder Management",
  "description": "Quickly create a folder in your Visual Studio Team
    Services source repositories from the web. No need to clone the
    repository locally or install extra tools.",
  "public": false,
  "icons": {
    "default": "images/VSO-Folder-196x.png"
  },
  "categories": [
    "Code"
  ],
  snipped rest of manifest file ...
}

发布部署期间这些值将会更新,默认设置将确保扩展未部署或意外公有化。

 采用一致的命名约定将简化各种环境的可跟踪性。例如,如果发布期间使用环境作为 ID 后缀,FolderManagementBeta 将是在 BETA 环境中运行的文件夹管理扩展。

持续集成 (CI) 是这样一种做法:使你能够在源控件存储库中生成可立即投入生产的最新代码 (bit.ly/28OtZ8K)。这可通过在每次提交时运行自动化生成和测试实现。

我们的扩展项目通常存储在托管 Team Services 的 Git 存储库,或者对于开源项目(如文件夹管理扩展)存储在 GitHub 上。管道起始于对存储库执行每次提交时触发的生成定义,然后生成 VSIX 扩展包并触发发布定义以将其部署到 DEV、BETA 和 PROD 环境。

图 3 所示,确保你能够持续集成并可选择批量更改以减少运行生成的次数。

生成触发器
图 3 生成触发器

精明的读者可能会注意到我们的 CI 生成仅输出 VSIX 包,不会复制扩展源文件。我们之所以这么做,是基于交付管道的其中一个基本原则:生成一次,且仅一次。不同于在每个部署步骤中编译和打包扩展文件,我们仅在管道开始时根据每个环境的不同配置打包一次。我们这样做可绝对确定将相同的扩展精确部署到各个不同的环境。 

版本控制扩展和生成任务非常重要。在 Team Services 中,最新版本完胜。如果将同一扩展的公共版本和 beta 版本部署到 Team Services 帐户,必须清楚将激活哪个版本。

适用于版本控制的选项有哪些? 借助 Team Services 开发者工具,可使用任何第三方版本号作为你的扩展。最重要的是,为了实现简单化和清晰的可跟踪性,我们决定使用 Build.BuildNumber 作为我们的版本号,如图 4 所示。

生成号格式
图 4 生成号格式

或者,可使用查询扩展版本任务,通过从应用商店获取当前版本并在每次发布扩展时增加特定部件,可更好地控制版本号。在降低 Team Services 中应用商店版本和项目之间的可跟踪性时,它还为应用商店中你的客户提供了更好的顺序编号。

自测试如何? CI 生成也是运行单元测试等的很好位置。文件夹管理扩展不使用任何单元测试,因为所有逻辑位置都会调用 Team Services REST API。其他扩展(如倒计时小组件 (bit.ly/28PTCag))包括验证逻辑以用于计算时差的单元测试。这些单元测试作为生成过程的一部分运行。将来想要添加的其他自动测试是 Selenium Web 测试。这使我们不仅可以运行单元测试,还可以自动执行 UI 测试。

图 5 显示生成步骤。NPM 依赖项通过 npm 安装进行安装 (1),设置脚本通过 npm exec 任务进行处理。或者,你可以使用 NuGet 和 NuGet 还原活动。然后 Visual Studio 生成任务 (2) 生成解决方案,随后是程序包扩展任务 (3),它可生成 VSIX 扩展包。

生成定义
图 5 生成定义

或者,可配置发布服务器和扩展 ID、标记和名称以替代清单值。管道仅配置版本号 (4) 作为生成的一部分,将其设置为生成号以确保管道的每个实例均可被唯一识别和跟踪。

PowerShell 脚本任务的用途是什么? 在编写本文时,需要以下脚本来提取版本信息(扩展开发者工具的将来版本—生成任务 [bit.ly/28R0oMh] 将使脚本过时):

$bldVerD =("$env:BUILD_BUILDNUMBER").replace("$env:BUILD_DEFINITIONNAME","").Trim();
Write-Verbose "Extracted buildVersion $bldVer";
Write-Host "##vso[task.setvariable variable=ExtensionVersion;]$bldVer"

持续交付功能可使用来自 CI 的输出将新的已知良好内部版本自动生成和部署到一个或多个环境 (bit.ly/28PWsfk)。持续交付和连续部署之间存在些许差异。后者针对单个环境。小团队可能仅实施持续部署,因为每个变更会直接反映到生产中。持续交付可在多个环境中移动代码,最后终止于生产,这一过程可能包括自动化 UI、负载和性能测试以及审批。

DEV 环境的部署完全自动且会频繁发生。这意味着,无需手动即可将每个成功的 CI 生成部署到 DEV。如图 6 所示,DEV 成功后,部署到 BETA 环境之前请求预审批。此阶段由项目负责人或项目经理批准。最后,针对公共发布到生产执行预审批步骤。这需要同时由项目负责人或项目经理批准。为了简便,我们选择使用预审批步骤并自动执行审批后步骤,因为我们没有理由批准部署后步骤并随后不将其部署到下一个环境。

发布触发器
图 6 发布触发器

图 7 显示发布定义,它可将 VSIX 扩展包部署到三个环境。第一个环境,DEV (1),由生成扩展的团队拥有和管理。扩展部署为私有形式并与开发沙箱帐户共享。

发布定义
图 7 发布定义

测试和批准发布后,部署继续第二个环境,BETA (2)。扩展仍部署为私有形式并与用户验收沙箱帐户共享。

用户验收测试完成和批准后,通过更改发布服务器、将可见性设置为公有并将扩展部署到应用商店 (3),部署会继续。

发布扩展任务 (4) 是部署进程的核心且是管道的秘密武器。通过解压缩内容、更新配置值和压缩所有文件,此任务可更新 VSIX 文件。然后,任务将其部署到已配置的应用商店发布服务器帐户,如所示的为 Beta 环境配置的 alm-rangers 发布服务器。

扩展 ID 标记 (5) 和名称会被覆盖以确保,每个环境中运行的扩展实例是唯一的,Dev 和 Beta 扩展可自动与开发和用户验收测试 Team Services 帐户共享,并且 DEV 和 BETA 发布是私有的。

你需要个人访问令牌 (6) 以使用发布扩展任务或命令行发布扩展。要安全地存储令牌,你可以创建与应用商店的 Team Services 服务连接。连接可定义键/值对,其中键是连接的名称,值是访问令牌。

应探索的一些其他任务包括:

  • 查询扩展版本: 检查应用商店,以查看已发布的扩展的版本号。版本可存储在变量中并由管道使用以创建新版本,如增加主要、次要或补丁版本号。
  • 安装扩展: 将扩展部署到应用商店,无需将其安装到帐户。
  • 共享扩展: 与指定帐户共享私有扩展。

此时,管道一致地生成、打包和更新扩展,更重要的是,保护环境以免发生常见故障。例如,当 TypeScript 代码中存在错误或文件丢失时,会出现生成故障。当 VSIX 无效、环境访问受限或某个审批者拒绝发布时,部署会失败。

总结

现在你已有自动化的生成-发布管道,可以加快开发进程,减少人为干预引起的错误,更重要的是,可以改进解决方案以及通过持续反映、衡量和学习不断完善。

但是,这一主题我们改天再讨论。

自动化的 CI 和 CD 管道将手动和易于出错的扩展生成-发布进程从数天减少到数分钟。这是一个鼓舞人心的体验,使用我们的开发团队能够将时间和精力集中在真正重要的事情上。

此处例举的 DevOps 实践也可应用于你自己的项目。Team Services 针对面向任意平台的任意语言启用 DevOps,包括本地、云、混合云和移动。借助可规划、版本化、生成、部署和监视应用程序的功能,Team Services 可提供你所需的一切来将想法转变为软件的可用部件。借助此信息,我们很兴奋地看到社区创建的扩展在你着手 DevOps 历程时改进了 Team Services 的功能。

DevOps 资源

 


Willy-Peter Schaub是 Microsoft Canada Excellence Centre 的 Visual Studio ALM Rangers 高级项目经理。他的博客位于 blogs.msdn.microsoft.com/willy-peter_schaub,你也可以关注他的 Twitter :@wpschaub

Wouter de Kort在荷兰 Ordina 担任 Microsoft 首席顾问,帮助公司始终保持软件开发领先地位。他的博客位于 wouterdekort.com。你可以关注他的 Twitter:@wouterdekort

Mattias Sköld在 Sogeti Sweden 担任 DevOps/ALM 培训师,帮助客户改进软件实践并推动 Sogeti 内部采用 ALM/DevOps 实践。他的博客位于 mskold.blogspot.com,你也可关注他的 Twitter:@mattiasskold

衷心感谢以下 Microsoft 技术专家对本文的审阅: Donovan Brown、Jess Houwing 和 Will Smythe