Connect(); 2018 特刊

第 33 卷,第 13 期

Azure - 使用 Azure Pipelines 正确部署代码

作者 Micheal Learned; 2018 特刊

新式应用是越来越复杂的系统,涉及多个技术堆栈和云本机服务。很难安排这些系统的自动发布管道。Azure Pipelines 提供了功能强大且易于使用的持续集成 (CI) 和持续交付 (CD) 服务,可用于生成和测试应用,再将应用部署到预期目标。本文将概述 Azure Pipelines 主要概念,并探讨各种 Azure 服务的部署方案。我们还将逐步介绍创建定目标到 Azure Kubernetes 服务 (AKS) 中 Docker 容器的 .NET Core 应用管道这一具体方案。最后,我们将介绍下一代 CI/CD,即 YAML 管道被配置为代码的一部分。

使用 Azure Pipelines,可以灵活配置生成和发布工作流。可以从 GitHub、Azure Repos、Bitbucket 和 Subversion 等多个版本控制提供程序中进行选择。大多数语言和应用框架都受支持,包括 .Net、Java、JavaScript、Python、PHP、Ruby、Xcode、C++ 和 Go。可以创建在任意位置部署的管道,包括任何云提供商或本地部署目标。可使用任何包管理存储库(如 NuGet、npm 和 Maven)生成和使用包。使用 Azure Pipelines,可以配置和自定义 CI/CD 解决方案,以适应几乎所有方案。内置管道任务、第三方任务、自定义任务以及基于文件的或内联的 PowerShell 和 Bash 脚本,全都有助于生成管道工作流。使用模板,可以轻松快速地分组和重用一组任务。

Azure Pipelines 主要概念

在 Azure Pipelines 中,可以为应用定义生成 (CI) 和发布 (CD) 工作流。这些工作流提供了用于安排和自动处理发布管道的框架。典型方案是,CI 生成管道从版本控制存储库中提取代码、编译代码、运行测试和其他分析过程,最后发布文件、二进制文件和可执行文件等项目。CD 发布管道会自动触发,并将已发布项目用作测试环境和生产环境的部署有效负载。使用 Azure Pipelines,可以创建简单或复杂的 CI/CD 管道,从而将应用部署到各种部署目标,包括 Web 服务器和数据库等各种 Azure 服务。可以定义发布管道的各个阶段,如开发、QA 和生产。请务必注意,生成管道和发布管道非常灵活,可以为其定义几乎任何所需的工作流。

代理是在生成管道和发布管道中运行作业的 Windows、Linux 和 macOS 计算机(或容器)。可以在物理计算机或虚拟机 (VM) 上安装和自托管代理,无论是在本地,还是在云中(例如 Azure)。或者,为了节省时间,也可以使用 Microsoft 托管的 Linux、macOS 和 Windows 代理。对于开放源代码项目,我们最多免费提供 10 个并行的 Microsoft 托管作业(有关详细信息,请单击本文末尾的链接)。

生成任务和发布任务****是管道的基本构建基块。它们是在管道中执行操作的已打包脚本。Azure Pipelines 随附了许多常见任务,用于执行代码生成、测试、打包和部署操作。可使用支持基于文件的或内联的 Bash、PowerShell 和 Python 脚本的任务,以深度自定义流程。甚至可以运行 Windows 批处理文件脚本。可使用 Azure Pipelines 提供的任务,也可利用 Visual Studio Marketplace 中的第三方任务,必要时还能创建自己的自定义任务。

生成模板和发布模板提供了可重用模式,有助于为常见方案(如生成 Android 应用或部署 Azure Web 应用)快速配置 CI/CD。实质上,模板是为了满足常见应用类型和目标的需求,而预设置参数的预定义任务集合。可以自定义模板,甚至可以将自定义工作流放入可重用模板中,以满足组织的特定需求。

服务连接****提供了一种安全机制,用于将外部服务连接到 Azure Pipelines 任务。这些外部服务可包括 Azure 订阅、Jenkins 或其他 CI 系统,以及诸如文件服务器之类的远程服务等。典型方案是,创建 Azure 资源管理器 (ARM) 服务连接,以支持 Azure Pipelines 将应用部署到各种 Azure 服务目标,如 Web 应用、Azure 虚拟机、Azure SQL 数据库或 Azure 订阅中的其他任何资源。

Azure 部署目标

Azure 提供了各种可用作应用部署目标的服务。应用服务、Windows 或 Linux 虚拟机、容器和其他许多 Azure 服务都是有效的部署目标。Docker 容器可以与应用服务、VM 和 Kubernetes(通过 AKS)结合使用。

虚拟机(Linux 和 Windows)是各种应用的常见部署目标。Azure Pipelines 支持 VM 作为部署目标,无论是在 Azure 中、在本地,还是甚至在其他云提供商中。可以在 VM 上安装和配置部署代理,再将 Azure Pipelines 部署挂钩到 VM。代理和 Azure Pipelines 通过非对称加密和 HTTPS 进行通信,以提供安全的部署方法。使用部署组,可以整理托管应用的服务器。部署组中的每个节点都托管一个 Azure Pipelines 代理,可以部署到它们。使用部署代理的一个示例是,将 Web 应用代码部署到一组 Web 服务器。也可以在物理计算机上安装代理,并以类似模式使用 Azure Pipelines 部署到它们。

应用服务****是一项 Azure 服务,可便于使用选定语言托管应用,而无需管理基础结构,并能运行 API、移动后端、Web 应用和无服务器代码。借助用于容器的 Web 应用,可以在 Windows 和 Linux 上运行容器化应用。将应用部署到应用服务的方法有许多,包括使用 Azure Pipelines。可使用现有 Azure Pipelines 模板,快速生成应用的 CD 管道。应用服务部署任务提供了各种标准功能,如部署到特定的应用服务槽、在部署时替代配置值和执行自定义脚本。

AKS 提供了一种基于 Azure 的 Kubernetes 管理服务,可便于轻松部署和管理容器化应用。AKS 通过为你处理运行状况监视和维护,免除了管理复杂容器业务流程的管理开销,并简化了容器管理。Azure 管理 Kubernetes 主机,而你只需管理和支付代理的费用。AKS 与 Azure 容器注册表集成,以提供完全托管的容器解决方案。

可使用模板部署到 Azure 服务和基础结构****,以提供基础结构即代码 (IaC),这会带来许多好处,如利用版本控制、CI/CD 和自动部署应用的基础结构。ARM 模板提供了声明性 JSON 方法,可用于部署 Azure 基础结构。使用 ARM 模板,可定义网络、安全组、负载均衡器、AKS 以及其他许多 Azure 基础结构组件。

Azure Pipelines 支持使用“Azure 资源组部署”任务部署 ARM 模板。使用此任务,可以创建管道,从而利用 ARM 模板将 Azure 服务部署到订阅。此任务提供了多个实用配置选项,如能够验证模板以防出错、能够在增量模式下部署以免影响现有 Azure 资源,以及能够处理资源组创建或现有资源组更新。

SQL Server**** 是 Azure 中以两种形式出现的数据库部署目标。SQL Server 可以是自托管的,而 Azure SQL 数据库则是用于数据库即服务 (DBaaS) 的 Azure 服务,可便于使用 SQL Server,而不用管理基础结构。Azure Pipelines 可以部署到以上两种形式的 SQL Server。SQL Server 提供了多个选项,可便于使用任务部署架构更改,如支持 dacpac、使用 sqlcmd 实用工具执行脚本,以及将第三方服务与 Redgate 工具结合使用。

例如:将 .NET Core 应用部署到 AKS 容器目标

.NET Core 是跨平台(Windows、Linux 和 macOS)开发平台,用于生成设备应用、云应用和物联网 (IoT) 应用。.NET Core 由 Microsoft、RedHat 和 .NET 社区联合维护和提供支持。AKS 是 Azure 托管 Kubernetes 服务。Kubernetes 简化了容器使用。可使用 Azure Pipelines 创建 CI/CD 管道,同时定目标到使用 Docker 容器的 AKS。ARM 模板用于表示 Azure 基础结构,如 AKS 和容器注册表。Docker 映像用于容器化 ASP.NET Web 应用。由于这是中等复杂的管道,因此可以访问 bit.ly/2T9Y0pT,查看在此方案中自动创建 CI/CD 管道的详细演练,以快速入门。

在此示例中,ASP.NET Core Web 应用存储在 Azure Repos 中。ARM 模板表示 AKS 群集和容器注册表。这样使用 IaC,可以将 Azure 基础结构与应用一起部署,这样便能在一个 CI/CD 管道中管理 Azure 资源和应用。图 1**** 是 Azure Repos 中的基本结构视图。

ASP.NET Core 应用和 ARM 模板
图 1:ASP.NET Core 应用和 ARM 模板

此方案的生成管道包含多个步骤。可使用描述性标签来命名任务。图 2**** 展示了一组任务,用于创建定目标到 AKS 群集的容器化 ASP.NET Core 应用。

使用 Docker 和 AKS 的生成管道
图 2:使用 Docker 和 AKS 的生成管道

获取源是生成过程的第一步。ASP.NET Core 应用和 ARM 模板是从 Azure Repos 中提取,并提供给生成代理。使用云托管代理,便无需管理用于执行管道的基础结构。

创建 Azure 容器注册表****是生成过程的下一步。注册表存储和管理 Docker 映像。下面的几个步骤生成和发布 Docker 映像(在此示例中,包含 ASP.NET Core 应用)。此生成步骤使用“Azure 资源组部署”任务,以部署表示容器注册表的 ARM 模板。此任务示例展示了 Azure Pipelines 的灵活性,因为可以执行部署任务,以在生成过程中创建注册表。默认情况下,ARM 部署任务设置为“增量模式”。因此,如果已有容器注册表,它便不会在后续生成运行时再次创建。

Docker 任务用于生成并将 Docker 映像发布到容器注册表。此步骤容器化 ASP.NET Core 应用。对应用结合使用不可变基础结构和可移植容器,可以将容器部署到 Windows、大多数 Linux 发行版和 macOS 上的各种目标。在此方案中,容器定目标到 Azure 中的 AKS。

Helm 图表****提供了用于 Kubernetes 的打包格式,可便于轻松定义、版本控制和安装 Kubernetes 应用。Helm 是 Kubernetes 包管理器,通过“Helm 工具安装程序”任务安装在生成代理上。“打包和部署 Helm 图表”任务在此步骤中存档图表,所以 Helm 图表最终发布为生成项目。

复制 ARM 模板是一项复制任务,可将模板复制到生成代理上的临时目录。ARM 模板是表示 Azure 资源的 JSON 文件。此时,ARM 模板表示 Kubernetes 群集资源。虽然 ARM 模板存储在 Azure Repos 中,但你可以视需要对管道使用其他版本控制提供程序(如 GitHub)。

发布生成项目****是将分段目录的内容复制到 Azure Pipelines 的任务。可以将项目存储在某处的文件共享中,但 Azure Pipelines 非常方便,无需进行任何额外设置。在此示例中,这些项目是 ARM 模板和 Helm 图表生成的 Kubernetes 包。

在生成管道执行后,发布管道使用生成管道中的项目,并部署解决方案。图 3 展示了发布管道中的各个步骤。

.NET Core 应用和 Kubernetes 的发布管道
图 3:.NET Core 应用和 Kubernetes 的发布管道

“Azure 资源组部署”任务是发布管道中的第一步。此任务使用 AKS ARM 模板,并且是用于部署 AKS 群集的项目。此时,ARM 模板项目可用于发布管道,因为模板是以项目形式在生成管道运行期间发布。

可以在任何生成管道和发布管道中使用 PowerShell 任务。此时,PowerShell 任务使用 setvariable logging 命令初始化一些永久变量,以便后续 Helm 任务能够访问公用数据的关键位。在这种情况下,脚本访问上一 ARM 部署任务创建的部署输出。具体而言,所设置的变量是为了稍后用于应用路由和 Application Insights:

$deploymentOutputs=(ConvertFrom-Json '$(deploymentOutputs)')
$applicationRoutingZone=$deploymentOutputs.applicationRoutingZone.value
$aiKey=$deploymentOutputs.aiKey.value
Write-Host "##vso[task.setvariable
  variable=applicationRoutingZone;]$applicationRoutingZone"
Write-Host "##vso[task.setvariable variable=aiKey;]$aiKey"

Helm 任务安排发布过程的最后三步。Helm 工具安装程序可确保代理安装最新版 Kubernetes 包管理器,其中包括 Kubectl(适用于 Kubernetes 的命令行工具)等必备组件。执行 Helm 初始化命令和 Helm 升级命令是为了,将应用部署到 Kubernetes。在发布管道执行后,ASP.NET Core 应用便会部署到 Kubernetes 群集,且应用可通过 URL 进行访问。

作为快速开始方法,Azure DevOps Projects 有助于自动创建如前所述的 CI/CD 管道,尤其是当你不熟悉部署到 Azure 服务时。可借助 Azure 门户中的向导驱动体验,从各种应用框架和部署目标中进行选择。只需简单几步,就可以创建功能齐全的 CI/CD 管道,用于生成代码并将代码部署到各种 Azure 服务(如应用服务、VM、AKS 和 SQL 数据库)。借助 DevOps Projects,可以使用自己的代码,也可以使用所提供的多个示例应用中的任意一个。使用 DevOps Projects,可以在 Azure Pipelines 中创建管道,再将此管道用作为特定应用框架和 Azure 服务部署目标执行 CI/CD 的参考体系结构。此外,还可以进一步自定义管道。Azure DevOps Projects 还创建其他 Azure 资源,如用于监视的 Application Insights 资源,以及基于 Azure 门户的仪表板。有关 Azure DevOps Projects 文档,请访问 bit.ly/2B7XnpJ

YAML 管道中的配置即代码

上一示例展示了如何使用 Azure 门户生成端到端生成管道,用于创建项目并将项目馈送到发布管道。Azure 门户生成的管道类型称为“设计器管道”;这些是拖放管道。今年,我们引入了一种可以在源代码中定义的新管道:YAML 管道。

YAML 管道最明显的优点归因于,工作流驻留在代码中。可以进行分支、区分,并将更改合并到业务逻辑中。如果你认为这样很酷,请等到下一次有人更改管道,并导致生成中断或意外结果时再这样做。尽管这种方案可能会很痛苦,但当你发现可以识别、跟踪和修复问题,就像对待代码中的其他任何 bug 一样,你就会释然了!

如果存储库在根级别包含 azure-pipelines.yml 文件,那么当你要创建管道时,系统会提取此文件。可以对示例应用存储库之一创建分支,以了解这样做的实际效果 (aka.ms/get-started-yaml-pipeline)。图 4**** 展示了基本的 ASP.NET Core YAML 管道。如果 GitHub 存储库中尚无 azure-pipelines.yml 文件,那么在你新建管道时,系统会先分析存储库中的代码,再建议所需的管道类型,如图 5 所示。

示例应用存储库中的基本 ASP.NET Core YAML 管道
图 4:示例应用存储库中的基本 ASP.NET Core YAML 管道

Azure Pipelines 分析代码并建议 YAML 管道模板
图 5:Azure Pipelines 分析代码并建议 YAML 管道模板

为了帮助你从设计器管道迁移,并了解如何调整它们以适应 YAML,我们提供了工具和信息。编辑设计器管道时,依次选择任务和“查看 YAML”,如图 6 所示。

在设计器中选择任务后可以查看 YAML
图 6:在设计器中选择任务后可以查看 YAML

在某些情况下,可以直接使用此代码片段。有时(例如,如果任务使用过程参数,通常是由模板生成),需要手动调整 YAML。

aka.ms/azure-pipelines-vscode 中还有一个 VS Code 扩展处于预览阶段。若要生成预提交挂钩工具,它由语言服务器提供技术支持。有关详细信息,请访问 aka.ms/azure-pipelines-­language-server

若要详细了解可以对 YAML 执行哪些操作,请访问 aka.ms/azure-pipelines-yaml-schemaaka.ms/azure-pipelines-task-reference

脚本是一种在代码中处理 CI 和 CD 工作流的很常见方法。YAML 管道旨在尽量简化在任何所需的位置集成脚本的过程(尽可能以可移植方式)。在快速上手 YAML 时,可能会注意到两种方法,分别为以任务为中心的方法和以脚本为中心的方法。决定使用哪种方法归根结底还是取决于个人偏好。

对于简单任务,可使用通用跨平台脚本:

steps:
- script: echo This is pipeline $(System.DefinitionID)

可以显式运行 PowerShell 或 Bash 脚本。Bash 脚本的优点是,可以在多个平台上运行。有关示例,请参阅图 7。若要了解详细信息,请访问 aka.ms/cross-platform-scripts

图 7:包含可在 Linux、macOS 和 Windows 代理上运行的 Bash 脚本的 YAML 管道

trigger:
  batch: true
  branches:
    include:
    - master
steps:
- bash: |
   echo "Hello world from $AGENT_NAME running on $AGENT_OS"
   case $BUILD_REASON in
    "Manual") echo "$BUILD_REQUESTEDFOR manually queued the build." ;;
    "IndividualCI") echo "This is a CI build for $BUILD_REQUESTEDFOR." ;;
    "BatchedCI") echo "This is a batched CI build for $BUILD_REQUESTEDFOR." ;;
    *) $BUILD_REASON ;;
    esac
  displayName: Hello world

如果团队不需要设计器发布管道提供的阶段和审批选项,可以在一个 YAML 管道中生成、测试和部署所有内容,如图 8**** 所示。

图 8:从驻留在代码库的 YAML 管道生成、测试和部署

# Build, test and deploy in a YAML pipeline
pool:
  vmImage: 'ubuntu-16.04'
  # replace the hosted Ubuntu pool above with the Windows pool below if
  # you want to deploy to a Windows web app
  # vmImage: 'vs2017-win2016'
variables:
  buildConfiguration: 'Release'
trigger:
- master
steps:
- script: |
    dotnet build --configuration $(buildConfiguration)
    dotnet test dotnetcore-tests --configuration $(buildConfiguration) --logger trx
- task: PublishTestResults@2
  inputs:
    testRunner: VSTest
    testResultsFiles: '**/*.trx'
- task: DotNetCoreCLI@2
  inputs:
    command: publish
    publishWebProjects: True
    arguments: '--configuration $(BuildConfiguration)
      --output $(Build.ArtifactStagingDirectory)'
    zipAfterPublish: True
- task: AzureRmWebAppDeployment@3
  inputs:
    azureSubscription: 'YourSubscription'
    WebAppName: 'your-webapp'
    Package: $(Build.ArtifactStagingDirectory)/**/*.zip
    # Uncomment the attribute below if you are deploying to a Windows Web app
    # TakeAppOfflineFlag: true

此示例适用于 Linux 和 Windows Web 应用。若要让其适用于 Windows,只需添加和删除相关注释,以更改正在使用的 Microsoft 托管池,并将 TakeAppOfflineFlag 参数设置为 true,以便在部署之前让应用脱机,以免 Web 应用 .DLL 文件出现“文件正在使用”错误。

服务连接(旧称为“终结点”)可能是流程中的棘手设置部分。以下参数指定了 Web 应用目标:

azureSubscription: 'YourSubscription'

WebAppName: 'your-webapp'

这些参数引用 Azure 资源管理器服务连接中的字段。请访问 aka.ms/azure-pipeline-service-connection

总结

开始使用 Azure Pipelines 是免费的。对于特定每月分钟数和特定并行作业数,Azure Pipelines 提供了各种免费使用层。额外作业数和分钟数可以按月付费购买。开放源代码项目接收多个免费的并行作业。若要详细了解 Azure Pipelines 定价,请访问 aka.ms/azure-pipelines-pricing

通过使用 Azure Pipelines 将应用部署到 Azure,可以创建可重用 CI/CD 模式,并可靠地自动执行每个部署步骤。可以多种方式创建管道,使用简单或复杂的工作流,并安全地部署到各种部署目标。Azure DevOps Projects 提供 Azure Pipelines 自动化,有助于快速开始将应用部署到 Azure 服务。借助 YAML 管道,可以创建配置即代码模式,从而带来许多好处。若要了解详细信息,请访问 aka.ms/sign-up-for-azure-pipelinesaka.ms/azure-devops-projectaka.ms/learn-azure-pipelines


Micheal Learned 在 Microsoft 内外从事软件工程项目已达 20 余年。Learned 将主要时间都用在与家人、朋友在一起上,以及研究所有 DevOps 和云事务上。可以通过 Twitter 与他联系:@mlhoop。**

Andy Lewis**** 撰写有关 Azure DevOps 的各种内容,包括版本控制和 CI/CD 管道。他在 Microsoft 为 Windows、Office 和开发部门的客户提供服务。Lewis 为 IBM、Borland、Intuit、SAS Institute 和 Microsoft 的诸多受众设计和开发了内容、多媒体和应用。**

衷心感谢以下 Microsoft 技术专家对本文的审阅:Jason Conner、Matt Cooper
Jason Conner 是一名 DevOps 工程师,在伊利诺斯州中部工作,专注于研究 .NET 开发、大数据和 Azure。

Matt Cooper 是北卡罗来纳州罗利市的一名项目经理,致力于研究 Azure Pipelines 平台、代理和 YAML 分析器。


在 MSDN 杂志论坛讨论这篇文章