练习 - 将 Azure Functions 应用部署到 Azure

已完成

你的项目附带了一个管道,用于在解决方案中生成项目并将 Web 应用部署到 Azure 应用服务。 现在可扩展该管道来同时部署新的 Azure Functions 项目。

在本部分中,你将:

  • 查看生成阶段。
  • 添加一个部署函数应用的任务。
  • 添加一个任务来将已发布的应用服务配置为使用已发布的函数。
  • 保存管道以触发 CI/CD 工作流。

查看生成阶段

在这里,你将查看在 azure-pipelines.yml 中定义的现有 CI/CD 管道。

  1. 在 Azure DevOps 中,导航到“Pipelines”。

  2. 选择管道。

  3. 选择“编辑”。 通过从下拉菜单中选择分支,确保分支设置为 main。 这将打开定义现有 CI/CD 管道的 azure-pipelines.yml 文件。

    由于在项目路径中使用通配符,因此下面突出显示的任务将自动还原、生成和发布新的 Azure Functions 项目。

    stages:
    - stage: 'Build'
      displayName: 'Build the web application'
      jobs: 
      - job: 'Build'
        displayName: 'Build job'
        pool:
          vmImage: 'ubuntu-20.04'
          demands:
          - npm
    
        variables:
          wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
          dotnetSdkVersion: '6.0.x'
    
        steps:
        - task: UseDotNet@2
          displayName: 'Use .NET SDK $(dotnetSdkVersion)'
          inputs:
            version: '$(dotnetSdkVersion)'
    
        - task: Npm@1
          displayName: 'Run npm install'
          inputs:
            verbose: false
    
        - script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
          displayName: 'Compile Sass assets'
    
        - task: gulp@1
          displayName: 'Run gulp tasks'
    
        - script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
          displayName: 'Write build info'
          workingDirectory: $(wwwrootDir)
    
        - task: DotNetCoreCLI@2
          displayName: 'Restore project dependencies'
          inputs:
            command: 'restore'
            projects: '**/*.csproj'
    
        - task: DotNetCoreCLI@2
          displayName: 'Build the project - $(buildConfiguration)'
          inputs:
            command: 'build'
            arguments: '--no-restore --configuration $(buildConfiguration)'
            projects: '**/*.csproj'
    
        - task: DotNetCoreCLI@2
          displayName: 'Publish the project - $(buildConfiguration)'
          inputs:
            command: 'publish'
            projects: '**/*.csproj'
            publishWebProjects: false
            arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
            zipAfterPublish: true
    
        - publish: '$(Build.ArtifactStagingDirectory)'
          artifact: drop
    

Andy:这是我们上一个生成阶段。 从原始项目开始,我们没有更改过,因为任务已配置为根据通配符匹配模式针对所有项目运行。

Mara:是的,这应该会按原样工作。 我觉得我们在这里不需要做任何更改。 此生成任务运行后,将发布 Web 和排行榜项目的 zip 文件项目供部署阶段使用。

添加一个部署 Azure 函数的任务

Andy:我觉得我们也可按原样来重复使用应用服务部署任务。 但愿有类似的我们可用于部署函数应用的任务。

Mara:我有些好消息。 经过略微调查,似乎有一个概念上与应用服务部署任务类似的任务,但它用于 Azure Functions 部署。 我们现在来查看它。

Azure 函数应用任务

AzureFunctionApp@1 任务旨在部署函数应用。 它在概念上与 AzureWebApp@1 任务类似,包括此函数应用方案所需的一切内容:

  • azureSubscription 指的是 Azure 服务连接管道变量的名称。
  • appType 指定正在部署的应用是适合 Linux (functionAppLinux) 还是 Windows (functionApp)。
  • appName 指定 Azure 帐户中 Azure Functions 应用实例的名称。
  • package 指定要部署的包的路径。
  • runtimeStack 指示函数应在哪个映像上运行,这是 Linux 部署所必需的。
  • startUpCommand 指定在部署函数后要运行的启动命令,这是 Linux 部署所必需的。

如需详细了解此任务有多么灵活,可查看 Azure 函数应用任务文档。

将下面突出显示的代码添加到管道的末尾。

- stage: 'Deploy'
  displayName: 'Deploy the web application'
  dependsOn: Build
  jobs:
  - deployment: Deploy
    pool:
      vmImage: 'ubuntu-20.04'
    environment: spike
    variables:
    - group: Release
    strategy:
      runOnce:
        deploy:
          steps:
          - download: current
            artifact: drop
          - task: AzureWebApp@1
            displayName: 'Azure App Service Deploy: website'
            inputs:
              azureSubscription: 'Resource Manager - Tailspin - Space Game'
              appName: '$(WebAppName)'
              appType: webAppLinux
              package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/Tailspin.SpaceGame.Web.zip'

          - task: AzureFunctionApp@1
            displayName: 'Azure Function Deploy: leaderboard'
            inputs:
              azureSubscription: 'Resource Manager - Tailspin - Space Game'
              appType: functionAppLinux
              appName: '$(LeaderboardAppName)'
              package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/Tailspin.SpaceGame.LeaderboardFunction.zip'
              runtimeStack: DOCKER|microsoft/azure-functions-dotnet:4
              startUpCommand: 'func azure functionapp publish $(functionAppName) --no-bundler'

提示

在 YAML 文件中,空格很重要。 确保你在此处添加的任务使用与上一任务相同的缩进。

添加一项任务来更新更新应用服务的应用设置

Andy:现在我们只需要将 Web 应用配置为使用已发布的排行榜 API 即可。 我们通常在门户中配置变量,但如果能在这里操作,则会更好。 这需要一个名为 LeaderboardFunctionUrl 的 AppSettings 参数。

Mara:我同意。 通过将执行此操作的任务添加到管道中,可帮助我们避免在更改任一服务时出现意外疏忽。 我们可将它放在末尾。

将下面突出显示的代码添加到管道的末尾。 请确保与上一个任务的缩进匹配。 如果想要详细了解此任务,可查看 Azure 应用服务设置任务文档。

- task: AzureFunctionApp@1
  displayName: 'Azure Function Deploy: leaderboard'
  inputs:
    azureSubscription: 'Resource Manager - Tailspin - Space Game'
    appType: functionAppLinux
    appName: '$(LeaderboardAppName)'
    package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/Tailspin.SpaceGame.LeaderboardFunction.zip'
    runtimeStack: DOCKER|microsoft/azure-functions-dotnet:4
    startUpCommand: 'func azure functionapp publish $(functionAppName) --no-bundler'

- task: AzureAppServiceSettings@1
  displayName: 'Update web app settings'
  inputs:
    azureSubscription: 'Resource Manager - Tailspin - Space Game'
    appName: $(WebAppName)
    resourceGroupName: $(ResourceGroupName)
    appSettings: |
      [
        {
          "name": "AppSettings__LeaderboardFunctionUrl",
          "value": "http://$(LeaderboardAppName).azurewebsites.net/api/LeaderboardFunction",
          "slotSetting": false
        }
      ]

保存管道以触发生成和发布

  1. 选择页面右上角的“Save”。 确认“Save”以触发运行。

  2. 在 Azure Pipelines 中,转到生成。 在生成运行时对其进行跟踪。

  3. 生成成功后,选择网站的部署任务,并选择 URL 以查看已部署的站点。

    Azure Pipelines 的屏幕截图,其中显示了网站 URL 的位置。

  4. 你会看到一个页面,其中网站正在应用服务上运行。 向下滚动,确认排行榜中有真实数据。 这由函数应用提供支持。

    Space Game 网站的屏幕截图。

    注意

    如果加载排行榜时出现错误,请仔细检查在本模块中执行的步骤。 如果看到异常消息“尝试以其访问权限禁止的方式访问套接字”,请确保正确设置了应用服务的 AppSettings__LeaderboardFunctionUrl 设置。

  5. 你还可直接测试函数应用。 只需使用以下格式导航到 URL 即可。 响应是 JSON,它在浏览器中应呈现为文本。

    http://<leaderboard function name>.azurewebsites.net/api/LeaderboardFunction?pageSize=10
    

    例如

    http://tailspin-space-game-leaderboard-4692.azurewebsites.net/api/LeaderboardFunction?pageSize=10
    

Andy:结果不错! 我们在这里展示出来的潜力应该对所有人都留下了深刻的印象。