【DevOps云实践】使用Azure Pipeline部署.NET应用到Azure App Service

2022-09-10T13:11:33+08:00 | 13分钟阅读 | 更新于 2022-09-10T13:11:33+08:00

Macro Zhao

【DevOps云实践】使用Azure Pipeline部署.NET应用到Azure App Service

@TOC

推荐超级课程:

在开发过程中,包含许多步骤,其中之一是交付部分 - 应用程序需要放置在某个地方,以供最终用户使用并运行并提供实际功能。这是DevOps文化和一般SDLC周期的一部分。

这部分通常被称为构建和部署,或者更现代化的方式是CI(持续集成)和CD(持续交付)。主要思想是尽可能自动化这个过程,每当我们推送新代码时,构建和发布过程可以自动运行,以将更改交付到源位置。

这里将讨论以下主题:

  1. Azure App Service - 将应用程序作为服务托管在Azure上。
  2. Azure DevOps - 一些配置事项。
  3. Azure Pipelines - 构建和部署配置。

1 Microsoft Azure

根据统计数据用法 ,这是第二受欢迎的云服务提供商。云提供了许多服务和功能。其中最常用和受欢迎的之一是应用服务(用于托管Web应用程序、函数、作业)。

1.1 在Azure门户中创建服务

要创建新资源,需要前往portal.azure.com,创建新的资源组、创建应用服务计划、应用服务,所有这些都在这个组中。复制名称或记住,因为稍后需要在变量中使用它来指定部署应用程序的位置。

对于本示例,将使用Windows操作系统用于应用服务。其他可能的类型是Linux或容器。

带有资源的示例资源组

建议在组和所有资源上使用强命名约定。对于某些服务,比如存储账户,需要去除空格和其他特殊字符。因此,建议阅读关于此主题的文档和文章。

2 Azure DevOps

这是主要可用于一些项目的服务,用于存储代码并删除工作。假设有包含代码(至少)的存储库。

在系统中,我们需要在项目设置中开启Pipeline。此设置可通过创建项目时选择或稍后使用所需功能。选择“项目设置” → “概述”。

对于我们的目的和工作,我们需要:

  1. Azure Repos - 用于具有代码的Git存储库。
  2. Azure Pipelines - 用于CI/CD等事项。

其他服务一般不需要在此文章的主题内操作。

2.1 服务连接

要使用部署功能,需要配置服务连接以在所有Pipeline中部署到Azure。前往“项目设置” → “服务连接”。

在创建部署Pipeline之前需要完成此配置!

项目中添加的服务连接示例

要添加新连接,需要拥有Azure帐户,通常是所有服务(DevOps、Azure等)的Microsoft帐户。

要添加新连接,需要选择“新服务连接” → “Azure Resource Manager”。还可以使用其他服务,但大多适用于旧的和更自定义的事项与手动配置。取决于您拥有的权限,配置选项可能会有所不同。

添加到Azure的新服务连接

选择“服务主体(自动)”用于最基本的使用(如果您是Azure中拥有所有权限的管理员)。

选择Azure的身份验证方法

提供连接详细信息。在这里需要从Azure选择活动订阅(它将根据您的帐户自动加载),添加名称(唯一),描述。不需要选择资源组 - 仅在连接需要仅在特定组内使用时才需要。还要勾选授予所有Pipeline访问权限的框 - 这将有助于在您构建的所有Pipeline中使用此连接。

提供连接设置和名称(唯一)

经过这些步骤后,新连接就可以在Pipeline中用于部署到Azure。或者也可以在经典发布中用作部署,因为内部使用相同的逻辑和任务。

3 Azure Pipeline

文档为该服务提供了简单描述:

AzurePipeline支持持续集成(CI)和持续交付(CD),以持续测试、构建和部署您的代码。您可以通过定义Pipeline来实现这一点。

构建Pipeline的最新方法是使用YAMLPipeline编辑器 。您还可以使用Classic编辑器 中的ClassicPipeline。

这意味着我们可以使用它来为最终用户提供应用程序,并自动化一些过程,如构建、测试、部署等。它可以以非常不同的方式进行配置,以实现良好且强大的DevOpsPipeline和一般开发流程(简单、快速、一切均为代码)。

这里将仅涵盖使用YAMLPipeline,它允许使用代码和Git管理文件和历史记录,并在可能的情况下共享功能。

与Pipeline一起工作的基本流程如下:

您可以在名为azure-pipelines.yml的YAML文件中定义Pipeline。

其中有2个主要步骤:

  1. 构建 - 构建应用程序,可以运行代码检查、测试等。结果是包含应用程序以供运行或部署的构件。
  2. 部署 - 将应用程序构件部署到托管位置。

其中有不同的概念,但非常简短:

  1. Pipeline可以包含阶段
  2. 阶段可以逐个执行
  3. 阶段可以依赖于先前的阶段
  4. 每个阶段可以包含工作
  5. 工作可以并行执行
  6. 每个工作可以包含步骤
  7. 步骤是要执行的基本操作(如安装包、构建、发布等)
  8. 步骤是具有参数的可用任务列表中的任务

下面的图像提供了Pipeline结构和元素的简单描述:阶段、工作、步骤(任务)。

Pipeline结构和元素的可视化描述

因此,如果我们在Pipeline中查看,可以使用阶段 - 每个阶段中的步骤按顺序运行。

为了更好地允许自定义步骤,可以使用模板功能 - 每个步骤都可以存储为单独的文件作为模板。更多详细信息请参阅文档

为准备Pipeline,需要执行一些步骤:

  1. 创建存储库 - 在此点,我们已经有了存储库。
  2. 创建环境 - 准备用于部署应用程序的环境定义的配置,配置它们(如批准等)。
  3. 创建具有变量组的库 - 以在Pipeline中使用变量,并在不更改代码的情况下进行编辑。
  4. 创建Pipeline - 在存储库中准备文件,并为新Pipeline选择它们。
  5. 配置安全性 - 访问库、Pipeline权限以便能够使用它们。

这里我们将介绍使用YAML和环境进行部署的现代方式。这与使用另一种方法和配置的经典构建和发布不同。

3.1 创建环境

要从Pipeline部署,需要配置要用于执行部署作业的环境列表 - 一种特殊的工作类型,用于处理环境配置。

要创建新环境需前往“项目” → “Pipeline” → “环境”并点击“创建环境”按钮。

创建新环境

之后,我们可以看到环境列表以及最新状态(如果已经部署了一些东西)。

还可以配置,以便需要得到某些环境的批准才能进行部署。例如,让我们创建配置以指定在部署到“QA”环境时,需要某用户批准。为此,单击QA环境,转到配置 → “批准和检查”。

选择批准和检查

如果尚未配置任何内容,将看到空白屏幕。

环境的配置列表为空

要添加批准者,需要从目录中选择用户,并允许他们批准部署至该环境。

配置批准者

如果选择了多个用户,还可以配置是否需要所有用户批准,或者是否需要其中一个、两个或任意数量的用户批准。

3.2 创建库

在我们的示例中,我们将使用库来存储一些Pipeline变量,以便为Pipeline提供不同环境的不同值。这将有助于使用一个代码库,但具有不同的输入。

要创建该组,需前往“Pipeline” → “库”。

创建新组

配置组:名称、变量、描述等。

创建变量组并定义变量

为所有环境创建变量组。

创建的示例变量组

这是在所有环境中拥有单独的参数/值的主要思想。

3.3 创建Pipeline

首先需要创建带有逻辑和代码的文件。之后配置Pipeline并从存储库中选择适当的文件 - azure-pilelines.yml

3.3.1 Pipeline代码

.NET应用程序的示例Pipeline包含存储库中的几个文件。所有文件都放置在存储库根目录中的build文件夹中,其中包含解决方案和其他文件夹和项目。

包含构建和部署阶段的Pipeline示例。

此示例文件(作为模板):

  1. azure-pipelines.yml - 提供结构和工作流的主文件。
  2. pipelines/build.yml - 用于定义构建步骤和需要运行的工作的阶段。
  3. pipelines/release.yml - 用于部署功能的阶段,定义工作和规则。
  4. pipelines/build-dotnet.yml - 具有常用步骤的模板文件,用于使用dotnet cli构建.NET应用程序。
  5. pipelines/deploy-webapp.yml - 具有常用步骤的模板文件,用于从包(.zip归档文件)部署应用程序到Azure应用服务。

所有用于构建.NET应用程序的步骤都基于使用dotnet cli 。您可以在文档中了解更多信息。但基本上在本地开发中使用的命令相同。

文件 azure-pipelines.yml:

# Pipeline的参数
parameters:  
  - name: environment  
    displayName: Environment  
    type: string  
    default: BuildOnly  
    values:  
    - BuildOnly  
    - Development  
  - name: projectName  
    displayName: ProjectName  
    type: string  
    default: <Your_project_name> # <-replace value here!  
  - name: skipLint  
    displayName: SkipLint  
    type: boolean  
    default: false  
  
# 没有自动触发器
trigger:  
  - none  
  
variables:  
  - group: Deploy-Environment-Shared  
  
# 阶段 - 逐个执行的工作列表
stages:  
  # 构建和检查(以及其他内容)阶段
  - template: pipelines/build.yml  
    parameters:  
      Environment: ${{ parameters.Environment }}  
      ProjectName: ${{ parameters.ProjectName }}  
      SkipLint: ${{ parameters.SkipLint }}  
  
  - ${{ if not(eq(parameters.Environment,'BuildOnly')) }}:  
    - template: pipelines/release.yml  
      parameters:  
        Environment: ${{ parameters.Environment }}  
        ProjectName: ${{ parameters.ProjectName }}

文件 pipelines/build.yml:

stages:  
- stage: Build  
  displayName: Build${{ parameters.ProjectName }}  
  
  # 使用多个作业,使 linter 可以并行工作以完成构建。  
  # 这还允许在 Linux 上运行 Linter,而您的构建可以在 Windows 或 Mac 上运行。  
  jobs:  
    # 使用来自 GitHub 的 Super-Linter 对代码进行 Lint  
    - job: lint  
      displayName: Lint 代码库  
      condition: eq(${{ parameters.SkipLint }}, false)  
      pool:  
        vmImage: 'ubuntu-latest'  
      steps:  
      - script: docker pull github/super-linter:latest  
        displayName: 拉取 GitHub Super-Linter 镜像  
      - script: >-  
          docker run   
            -e RUN_LOCAL=true   
            -e VALIDATE_JSCPD=false   
            -e VALIDATE_MARKDOWN=false   
            -e VALIDATE_EDITORCONFIG=false   
            -v $(System.DefaultWorkingDirectory):/tmp/lint   
            github/super-linter  
        displayName: '运行 GitHub Super-Linter'  
        continueOnError: true  
  
    # 进行主要构建操作  
    - job: build  
      displayName: 构建和测试,创建构件  
      pool:  
        vmImage: 'windows-latest'  
      variables:  
        BuildConfiguration: 'Release'  
      steps:  
        - template: build-dotnet.yml  
          parameters:  
            ProjectServiceName: ${{ parameters.ProjectName }}  
            RestoreBuildProjects: '**/*.csproj'  
            TestProjects: 'tests/**/*.csproj'  
            DotnetVersion: '7.x'  
            ServicePublishProjects: '**/<your project name>.csproj' # 替换此处的值

文件 pipelines/build-dotnet.yml:

steps:  
- checkout: self  
  clean: true  
  
# 安装并缓存 .NET SDK  
- task: UseDotNet@2  
  displayName: '安装 Dotnet Core cli'  
  inputs:  
    version: ${{ parameters.DotnetVersion }}  
  
# 恢复 NuGet packages  
- task: DotNetCoreCLI@2  
  displayName: 'Dotnet 恢复'  
  inputs:  
    command: restore  
    projects: |  
      ${{ parameters.RestoreBuildProjects }}  
      ${{ parameters.TestProjects }}  
  
# 构建项目  
- task: DotNetCoreCLI@2  
  displayName: 'Dotnet 构建'  
  inputs:  
    projects: ${{ parameters.ServicePublishProjects }}  
    arguments: --configuration $(BuildConfiguration) --no-restore  
  
# 运行测试  
- task: DotNetCoreCLI@2  
  condition: ne('${{ parameters.TestProjects }}', '')  
  displayName: 'Dotnet 测试'  
  inputs:  
    command: test  
    projects: ${{ parameters.TestProjects }}  
    arguments: '--configuration $(BuildConfiguration) --no-restore --collect "Code coverage"'  
  
# 发布 web 应用程序(以便以后部署)  
- task: DotNetCoreCLI@2  
  displayName: 发布  
  inputs:  
    command: publish  
    publishWebProjects: false  
    zipAfterPublish: true  
    projects: ${{ parameters.ServicePublishProjects }}  
    arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory) --no-restore'  
  
# 作业完成后在Pipeline中发布构件  
- task: PublishPipelineArtifact@1  
  displayName: 发布Pipeline构件  
  inputs:  
    targetPath: '$(Build.ArtifactStagingDirectory)'  
    artifactName: '${{ parameters.ProjectServiceName }}'  
    publishLocation: 'pipeline'

文件 pipelines/release.yml:

stages:  
# 每个选定环境的主要部署阶段  
- stage: Deploy  
  displayName: 部署${{ parameters.ProjectName }}  
  variables:  
  - group: Deploy-Environment-${{ parameters.Environment }}  
  jobs:  
  # 实际将 web 应用程序部署到 Azure  
  - deployment: DeployWebApp  
    displayName: 将 WebApp 部署到 Azure  
    pool:  
      vmImage: 'windows-latest'  
    environment: ${{ parameters.Environment }}  
    strategy:  
      runOnce:  
        deploy:  
          steps:  
            - template: deploy-webapp.yml  
              parameters:  
                Environment: ${{ parameters.Environment }}  
                ProjectName: ${{ parameters.ProjectName }}  
                PackageName: '<your project name for package (zip)>' # 替换此处的值

文件 pipelines/deploy-webapp.yml:

steps:  
- checkout: self  
  clean: true  
  
# 下载Pipeline构件  
- task: DownloadPipelineArtifact@2  
  inputs:  
    artifactName: '${{ parameters.ProjectName }}'  
    buildType: 'current'  
    targetPath: '$(Build.ArtifactStagingDirectory)${{ parameters.ProjectName }}'  
  
# 部署到 Azure App Service  
- task: AzureWebApp@1  
  displayName: '部署到 $(AppServiceNameBackend)'  
  inputs:  
    azureSubscription: '$(AzureServiceConnection)'  
    appType: 'webApp'  
    appName: '$(AppServiceNameBackend)'  
    package: '$(Build.ArtifactStagingDirectory)${{ parameters.ProjectName }}${{ parameters.PackageName }}.zip'

这些Pipeline文件可以用于大多数项目,只需要更新一些变量。当然,如果需要添加一些特殊定制,可以根据需要添加和修改。

3.3.2 创建Pipeline

要在存储库中使用代码,还需要进行一步操作 — 创建实际的Pipeline运行并查看结果。

创建新的Pipeline

选择要使用的存储库。可以使用外部服务,但在我们的示例和流程中,我们使用内部存储库以简化操作。主要思想是相同的,因为大多数其他服务提供了自己的 CI/CD 工具(GitHub Actions 等)。

选择源文件位置

从列表中选择存储库。通常情况下,您将只有一个与项目名称相同的存储库(默认情况下),但可能会有多个,因为项目作为所有相关工作的聚合。它可以是后端、前端、基础设施等。

具有应用程序的示例存储库

选择现有的Pipeline(如果所有代码已经推送到存储库中)或者可以从模板中选择。在这种情况下,Pipeline文件将仅包含一个根文件(azure-pipelines.yml)带有示例代码。

从模板或现有文件中选择

从存储库中的某个分支选择文件。示例中的文件位于具有所有相关文件的“build”文件夹中。

从特定分支选择新Pipeline

最后需要审查结果并能“运行”或“保存”。保存后,可以像往常一样运行。因为没有配置自动触发器,Pipeline需要手动运行。

审查并保存新Pipeline

此步骤准备好使用Pipeline,并将显示在列表中。

新Pipeline

我建议也使用文件夹来组织Pipeline定义。转到“所有”并单击“新建文件夹”按钮。

根据主题或组创建新文件夹

这将有助于搜索所需的Pipeline,按照您的意愿进行分组,将旧的移动到文件夹中,将新的移动到新的文件夹中等。

要移动到文件夹,需要选择Pipeline并选择“重命名/移动”。

选择要重命名或移动到文件夹的Pipeline

选择要移动的文件夹

3.4 附加配置

为了运行Pipeline并成功部署,需要配置一些安全事项:

  1. 用于库的Pipeline权限 — 用于每个使用的组。
  2. 环境的安全性 — 用于每个环境。

完成这些步骤后,Pipeline将准备就绪并可以运行。

3.4.1 配置库访问权限

每个变量组需要能够在Pipeline中使用。因此,需要进入每个Pipeline设置权限并选择所有变量。

配置Pipeline权限以使用组中的变量

从列表中添加Pipeline。

选择所有 YAML Pipeline以访问变量

选择后,选定的Pipeline将可以访问变量。

3.4.2 配置环境

选择环境、设置、安全性。这将打开带有用户和Pipeline权限的页面。

环境的安全性

将一个或多个Pipeline添加到列表中。

在“+”上选择所有Pipeline的列表

完成所有这些步骤后,新的Pipeline就可以运行并进行工作了。

3.5 运行Pipeline

要运行Pipeline,需要转到选择的Pipeline并单击“运行Pipeline”按钮。

由于Pipeline使用参数,它会在 UI 中向用户显示这些参数,以便用户可以选择并进行更改。

带有参数的运行Pipeline

当Pipeline成功验证编译的 YAML 后,它将显示阶段和作业。

如果 YAML 验证失败,它会显示错误并不会运行Pipeline。对于一些情况,如果验证完成但有安全性问题(权限) — 它会创建Pipeline但显示错误消息(在问题未解决之前将显示失败状态)。

阶段视图

作业视图

结果可能因您的项目、代码和其他方面而有所不同。但对于大多数情况,将显示日志、警告(如果有)、作业步骤,甚至测试结果(如果有)甚至更多 — 一些扩展可能会添加具有诸如代码分析等详细信息的附加选项卡。

运行作业后,可以查看流程中的每个步骤的步骤列表,其中包含所有日志和每个步骤的状态。因此,可以简单地查看每个步骤的更多详细信息,甚至下载原始日志文件。

包含每个步骤和日志的结果

选定的部署环境

下面的图片展示了当 QA 环境需要批准但用户拒绝时,它会停止Pipeline并以失败的状态结束。

如果Pipeline失败,这些构件就不能在发布中使用。只有成功的Pipeline可以稍后与构件一起使用。因此,可以在发布中使用它们以部署到多个环境中。

QA 部署在开发完成后失败(多环境的另一个示例)

接下来的示例是用户选择并批准 QA — 成功部署。

QA 部署成功

当然,在不同的项目和不同的配置中,可以看到相同的结果或不同的结果。但主要思想是一样的 — 需要逐步进行操作,并使用文档获取更多细节,了解如何使用和实现所需的行为。

3.5 Pipeline审查

这里提供了Pipeline的简短摘要以及所使用元素的可视结构:库、环境。

Azure DevOps 门户中的依赖关系

下图显示了文件的可视依赖关系 — 在这里我们可以看到这里有哪些阶段和作业。它们都保存在各自的文件中。

模板中的文件

接下来的图片提供了详细查看用于构建 .NET 应用程序的实际Pipeline模板。

包含步骤细节的详细Pipeline

希望这些图片能帮助您更好地了解Pipeline及其内部发生的情况。

结论

使用 Azure Pipeline是将 CI/CD 实施到项目中甚至是简单的方法。在本文中,我们看到了如何为 .NET 应用程序实现Pipeline(但还可以用于其他类型,只需修改构建模板 — 构件是用于后续部署的实际结果)使用 Azure DevOps(存储库)中的存储库、配置、使用模板、环境、库。

© 2011 - 2025 Macro Zhao的分享站

关于我

如遇到加载502错误,请尝试刷新😄

Hi,欢迎访问 Macro Zhao 的博客。Macro Zhao(或 Macro)是我在互联网上经常使用的名字。

我是一个热衷于技术探索和分享的IT工程师,在这里我会记录分享一些关于技术、工作和生活上的事情。

我的CSDN博客:
https://macro-zhao.blog.csdn.net/

欢迎你通过评论或者邮件与我交流。
Mail Me

推荐好玩(You'll Like)
  • AI 动·画
    • 这是一款有趣·免费的能让您画的画中的角色动起来的AI工具。
    • 支持几十种动作生成。
我的项目(My Projects)
  • 爱学习网

  • 小乙日语App

    • 这是一个帮助日语学习者学习日语的App。
      (当然初衷也是为了自用😄)
    • 界面干净,简洁,漂亮!
    • 其中包含 N1 + N2 的全部单词和语法。
    • 不需注册,更不需要订阅!完全免费!
  • 小乙日文阅读器

    • 词汇不够?照样能读日语名著!
    • 越读积累越多,积跬步致千里!
    • 哪里不会点哪里!妈妈再也不担心我读不了原版读物了!
赞助我(Sponsor Me)

如果你喜欢我的作品或者发现它们对你有所帮助,可以考虑给我买一杯咖啡 ☕️。这将激励我在未来创作和分享更多的项目和技术。🦾

👉 请我喝一杯咖啡

If you like my works or find them helpful, please consider buying me a cup of coffee ☕️. It inspires me to create and share more projects in the future. 🦾

👉 Buy me a coffee