如何在 Azure DevOps 中正确使用 Azure Function Build 和部署多个项目

问题描述 投票:0回答:1

我正在使用 Azure 和基于 C# 的应用程序。我有 2 个应用程序服务、一个 Web 应用程序和一个函数应用程序。我的网络应用程序使用 dotnet 9.0,我的函数应用程序也使用 dotnet 9.0。我选择了带有隔离工作人员的计时器触发器,并使用了基于消耗的计划。此外,我的 Web 应用程序有 4 个部署槽:开发、uat、登台、生产。我的 Function 应用程序有 2 个部署槽:开发、生产。

我将我的 Web 应用程序分成 2 个项目,一个 Web 应用程序和一个共享库。我的迁移、dbcontext、模型以及在 Azure Function 中引用和运行的函数都在共享库中。第三个项目是我的 Azure 函数。所有这些都存储在 Azure DevOps 中的单个存储库中。当我运行下面的管道脚本时,一切正常并通过。但是,管道似乎无法正确构建或部署 Azure 函数。

当我加载 Kudu 控制台时,我看到压缩文件夹已上传到 ~/wwwroot 目录。但是,此压缩文件夹的名称是压缩的 webapp 项目,而不是压缩的 azure function 项目。我该如何解决这个问题?我的 azure-pipelines.yml 如下。

trigger:
  branches:
    include:
      - development-cs
      - main
      - uat

variables:
  buildConfiguration: 'Release'
  azureSubscription: 'MyAzureServiceConnection'       # Name of your Azure Service Connection
  appName: 'MyWebApp'                                 # Name of your Azure Web App
  resourceGroupName: 'MyResourceGroup'                # Name of your Resource Group
  sqlServerName: 'myserver.database.windows.net'       # Azure SQL Server FQDN
  runtimeStack: 'DOTNETCORE|9.0'
  ResourceGroupLocation: 'East US'

  # Database names
  devSqlDatabaseName: 'mydevdatabase'
  uatSqlDatabaseName: 'myuatdatabase'
  mainSqlDatabaseName: 'mymaindatabase'

  # Deployment Slots for Web App
  devSlotName: 'development'
  uatSlotName: 'uat'
  stagingSlotName: 'staging'
  productionSlotName: 'production'

stages:
- stage: BuildAndDeploy
  displayName: 'Build and Deploy Stage'
  jobs:
  - job: Build
    displayName: 'Build Job'
    pool:
      vmImage: 'ubuntu-latest'
    steps:
      - checkout: self
        fetchDepth: 0
        persistCredentials: true
        clean: true

      - script: |
          echo "Build Sources Directory: $(Build.SourcesDirectory)"
        displayName: 'Print Build Sources Directory'

      - script: |
          echo '{ "sdk": { "version": "9.0.100" } }' > global.json
        displayName: 'Create global.json'

      - task: UseDotNet@2
        displayName: 'Install .NET 9.0.100 SDK in Build Job'
        inputs:
          packageType: 'sdk'
          version: '9.0.100'

      - script: |
          echo "Installing necessary tools..."
          sudo apt-get update
          sudo apt-get install -y azure-cli powershell
        displayName: 'Install Azure CLI and PowerShell'

      - script: |
          echo "Installing dotnet-ef tool..."
          dotnet tool install --global dotnet-ef --version 9.0.0-preview.6.24327.4
          echo '##vso[task.prependpath]$HOME/.dotnet/tools'
        displayName: 'Install dotnet-ef Tool in Build Job'

      - task: DotNetCoreCLI@2
        displayName: 'Restore NuGet Packages'
        inputs:
          command: 'restore'
          projects: '**/*.csproj'

      - task: DotNetCoreCLI@2
        displayName: 'Build Projects'
        inputs:
          command: 'build'
          projects: '**/*.csproj'
          arguments: '--configuration $(buildConfiguration) --no-restore'

      # Publish Web App package
      - task: DotNetCoreCLI@2
        displayName: 'Publish Web App'
        inputs:
          command: 'publish'
          projects: 'MyProject.WebApp/MyProject.WebApp.csproj'
          arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/web --no-restore'

      # (Optional) Generate EF Core migration SQL script
      - script: |
          echo "Generating EF Core migration script..."
          dotnet ef migrations script --idempotent \
              --project "MyProject.Shared/MyProject.Shared.csproj" \
              --startup-project "MyProject.WebApp/MyProject.WebApp.csproj" \
              --output $(Build.ArtifactStagingDirectory)/migration.sql
        displayName: 'Generate EF Core Migration Script'

      - task: PublishBuildArtifacts@1
        displayName: 'Publish Build Artifacts'
        inputs:
          pathToPublish: '$(Build.ArtifactStagingDirectory)'
          artifactName: 'drop'
          publishLocation: 'Container'

  - job: Deploy
    displayName: 'Deploy Job'
    dependsOn: Build
    pool:
      vmImage: 'ubuntu-latest'
    steps:
      - checkout: self
        fetchDepth: 0
        persistCredentials: true
        clean: true

      - download: current
        artifact: drop

      - task: UseDotNet@2
        displayName: 'Install .NET 9.0.100 SDK in Deploy Job'
        inputs:
          packageType: 'sdk'
          version: '9.0.100'

      - script: |
          echo "Installing Azure CLI..."
          sudo apt-get update
          sudo apt-get install -y azure-cli
        displayName: 'Install Azure CLI'

      - script: |
          echo "Installing dotnet-ef tool..."
          dotnet tool install --global dotnet-ef --version 9.0.0-preview.6.24327.4
          echo '##vso[task.prependpath]$HOME/.dotnet/tools'
        displayName: 'Install dotnet-ef Tool in Deploy Job'

      - script: |
          echo "Verifying dotnet-ef installation..."
          dotnet ef --version
        displayName: 'Verify dotnet-ef Installation in Deploy Job'

      - script: |
          echo "Testing connectivity to SQL Server..."
          sudo apt-get install -y netcat
          nc -zv $(sqlServerName) 1433
        displayName: 'Test SQL Server Connectivity'

      # Set Web App slot and SQL database name based on branch
      - script: |
          branchName=$(Build.SourceBranchName)
          if [ "$branchName" == "main" ]; then
              echo "##vso[task.setvariable variable=slotName]$(stagingSlotName)"
              echo "##vso[task.setvariable variable=sqlDatabaseName]$(mainSqlDatabaseName)"
          elif [ "$branchName" == "uat" ]; then
              echo "##vso[task.setvariable variable=slotName]$(uatSlotName)"
              echo "##vso[task.setvariable variable=sqlDatabaseName]$(uatSqlDatabaseName)"
          elif [ "$branchName" == "development-cs" ]; then
              echo "##vso[task.setvariable variable=slotName]$(devSlotName)"
              echo "##vso[task.setvariable variable=sqlDatabaseName]$(devSqlDatabaseName)"
          else
              echo "##vso[task.setvariable variable=slotName]$(devSlotName)"
              echo "##vso[task.setvariable variable=sqlDatabaseName]$(devSqlDatabaseName)"
          fi
          echo "Branch: $branchName"
          echo "Web App Slot Name: $(slotName)"
          echo "SQL Server Name: $(sqlServerName)"
          echo "SQL Database Name: $(sqlDatabaseName)"
        displayName: 'Set Web App Slot and DB Based on Branch'

      # Apply EF Core migrations (only for main and uat branches)
      - script: |
          echo "Applying EF Core Migrations using Service Principal..."
          dotnet ef database update \
              --project "MyProject.Shared/MyProject.Shared.csproj" \
              --startup-project "MyProject.WebApp/MyProject.WebApp.csproj" \
              --connection "Server=tcp:$(sqlServerName),1433;Database=$(sqlDatabaseName);Authentication=Active Directory Service Principal;User ID=$(sqlClientId);Password=$(sqlClientSecret);Encrypt=True;TrustServerCertificate=False;MultipleActiveResultSets=True;Connection Timeout=30;"
        displayName: 'Apply EF Core Migrations'
        condition: or(eq(variables['Build.SourceBranchName'], 'main'), eq(variables['Build.SourceBranchName'], 'uat'))

      - task: AzureWebApp@1
        displayName: 'Deploy to Azure Web App'
        inputs:
          azureSubscription: '$(azureSubscription)'
          appName: '$(appName)'
          package: '$(Pipeline.Workspace)/drop/web/**/*.zip'
          appType: 'webApp'
          slotName: '$(slotName)'

      - task: AzureCLI@2
        displayName: 'Update Web App Settings'
        inputs:
          azureSubscription: '$(azureSubscription)'
          scriptType: 'bash'
          scriptLocation: 'inlineScript'
          inlineScript: |
            echo "Updating Web App settings..."
            az webapp config appsettings set \
              --name "$(appName)" \
              --resource-group "$(resourceGroupName)" \
              --slot "$(slotName)" \
              --settings ConnectionStrings__DefaultConnection="Server=tcp:$(sqlServerName),1433;Initial Catalog=$(sqlDatabaseName);Authentication=Active Directory Managed Identity;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;" \
                        AzureAd__Instance="https://login.microsoftonline.com/" \
                        AzureAd__Domain="mydomain.com" \
                        AzureAd__TenantId="$(tenantId)" \
                        AzureAd__ClientId="$(clientId)" \
                        AzureAd__ClientSecret="$(clientSecret)"

上面的脚本是我尝试过的。此外,我尝试使用 VS Community 中的发布功能,效果非常好。完全没有问题。似乎只有在尝试将 CI/CD 与 DevOps 结合使用时才会出现问题。

编辑:我还注意到Web应用程序将在azure功能应用程序服务中发布,并且我的Web应用程序应用程序服务将不再发布并显示一个页面,表示它已准备好部署到。

c# asp.net-core azure-devops azure-functions azure-pipelines
1个回答
0
投票

您的 Web 应用程序和函数应用程序是单独的 Azure 资源。他们可以共享相同的应用程序服务计划,但在过去,我通常将它们分开以管理自己的扩展和成本。

提供的管道只是为 Web 应用程序创建可部署的工件并部署它。

dotnet publish
任务仅为单个项目创建输出。

要包含您的函数应用程序,请在与 Web 应用程序不同的文件夹中创建适当的可发布工件:

# Publish Function App package
- task: DotNetCoreCLI@2
  displayName: 'Publish Function App'
  inputs:
    command: 'publish'
    projects: 'MyProject.WebApp/MyProject.FunctionApp.csproj'
    arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/functionapp --no-restore'

在部署阶段包含部署函数应用程序的适当任务,例如

AzureFunctionApp@2

- task: AzureFunctionApp@2
  inputs:
    azureSubscription: '$(azureSubscription)'
    appName: 'MyFunctionApp'
    package: '$(Pipeline.Workspace)/drop/functionapp/**/*.zip'
    appType: 'functionApp' # or 'functionAppLinux'
    slotName: '$(functionAppslotName)'
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.