Я разделил свое веб-приложение на два проекта: веб-приложение и общую библиотеку. Мои миграции, контекст базы данных, модели и функция, на которую можно ссылаться и которая будет выполняться в функции Azure, — все это находится в общей библиотеке. Третий проект — моя функция Azure. Все они хранятся в одном репозитории в Azure DevOps. Когда я запускаю приведенный ниже сценарий конвейера, все работает отлично и проходит. Однако похоже, что конвейер неправильно создает или развертывает функцию Azure.
Когда я загружаю консоль Kudu, я вижу, что заархивированная папка загружается в каталог ~/wwwroot. Однако имя этой заархивированной папки — это заархивированный проект веб-приложения, а не заархивированный проект функции Azure. Как я могу это исправить? Мой azure-pipelines.yml приведен ниже.
Изменить: обновлен .yml до фактической используемой версии.
Код: Выделить всё
trigger:
branches:
include:
- development-cs
- main
- uat
variables:
buildConfiguration: 'Release'
azureSubscription: 'RandomAzureConnection' # Name of your Azure Service Connection
appName: 'RandomWebApp' # Name of your Azure Web App
functionAppName: 'RandomFunctionApp' # Name of your Azure Function App
resourceGroupName: 'Random_ResourceGroup' # Name of your Resource Group
sqlServerName: 'randomsqlserver.database.windows.net' # Azure SQL Server FQDN
runtimeStack: 'DOTNETCORE|9.0'
ResourceGroupLocation: 'East US'
# Database names
devSqlDatabaseName: 'randomdevdb'
uatSqlDatabaseName: 'randomuatdb'
mainSqlDatabaseName: 'RandomMainDB'
# Deployment Slots for Web App
devSlotName: 'devSlot'
uatSlotName: 'uatSlot'
stagingSlotName: 'stagingSlot'
productionSlotName: 'productionSlot'
stages:
- stage: BuildAndDeploy
displayName: 'Build and Deploy Stage'
jobs:
- job: Build
displayName: 'Build Job'
pool:
vmImage: 'ubuntu-latest'
steps:
# Checkout code and set up environment
- 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'
# Restore and Build all projects
- 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 the Web App package
- task: DotNetCoreCLI@2
displayName: 'Publish Web App'
inputs:
command: 'publish'
projects: 'RandomApp/WebApp.csproj'
arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/web --no-restore'
# Publish the Function App package into its own folder
- task: DotNetCoreCLI@2
displayName: 'Publish Function App'
inputs:
command: 'publish'
projects: 'RandomApp/RandomFunctions.csproj'
arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/functions --no-restore'
# Archive the Function App folder into a zip file
- task: ArchiveFiles@2
displayName: 'Archive Function App Package'
inputs:
rootFolderOrFile: '$(Build.ArtifactStagingDirectory)/functions'
includeRootFolder: false
archiveFile: '$(Build.ArtifactStagingDirectory)/functionapp.zip'
replaceExistingArchive: true
# (Optional) Cleanup the unzipped Function App folder so only the zip remains
- script: |
echo "Cleaning up unzipped Function App folder..."
rm -rf "$(Build.ArtifactStagingDirectory)/functions"
displayName: 'Cleanup Function App Folder'
# (Optional) Generate EF Core migration SQL script
- script: |
echo "Generating EF Core migration script..."
dotnet ef migrations script --idempotent \
--project "RandomApp/RandomShared.csproj" \
--startup-project "RandomApp/WebApp.csproj" \
--output $(Build.ArtifactStagingDirectory)/migration.sql
displayName: 'Generate EF Core Migration Script'
# List files for debugging purposes
- script: |
echo "Listing contents of the Artifact Staging Directory:"
ls -la "$(Build.ArtifactStagingDirectory)"
displayName: 'List Artifact Files'
# Publish build artifacts (both the web folder and the Function App zip)
- task: PublishBuildArtifacts@1
displayName: 'Publish Build Artifacts'
inputs:
# Change the path to publish both the web folder and the functionapp.zip file
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
# Install required tools in the Deploy Job
- 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 slot and database variables 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)"
echo "##vso[task.setvariable variable=functionSlot]''"
elif [ "$branchName" == "uat" ]; then
echo "##vso[task.setvariable variable=slotName]$(uatSlotName)"
echo "##vso[task.setvariable variable=sqlDatabaseName]$(uatSqlDatabaseName)"
echo "##vso[task.setvariable variable=functionSlot]none"
elif [ "$branchName" == "development-cs" ]; then
echo "##vso[task.setvariable variable=slotName]$(devSlotName)"
echo "##vso[task.setvariable variable=sqlDatabaseName]$(devSqlDatabaseName)"
echo "##vso[task.setvariable variable=functionSlot]development"
else
echo "##vso[task.setvariable variable=slotName]$(devSlotName)"
echo "##vso[task.setvariable variable=sqlDatabaseName]$(devSqlDatabaseName)"
echo "##vso[task.setvariable variable=functionSlot]development"
fi
echo "Branch: $branchName"
echo "Web App Slot Name: $(slotName)"
echo "SQL Server Name: $(sqlServerName)"
echo "SQL Database Name: $(sqlDatabaseName)"
echo "Function App Slot: $(functionSlot)"
displayName: 'Set Web App Slot, Function App Slot, and DB Based on Branch'
# Apply EF Core migrations for main and uat branches only
- script: |
echo "Applying EF Core Migrations using Service Principal..."
dotnet ef database update \
--project "RandomApp/RandomShared.csproj" \
--startup-project "RandomApp/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'))
# Deploy the Web App package to Azure App Service
- task: AzureWebApp@1
displayName: 'Deploy to Azure Web App'
inputs:
azureSubscription: '$(azureSubscription)'
appName: '$(appName)'
# Adjust the package path if your web app requires a zip package or folder.
package: '$(Pipeline.Workspace)/drop/web'
appType: 'webApp'
slotName: '$(slotName)'
# Update Web App settings using Azure CLI
- 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="randomdomain.com" \
AzureAd__TenantId="$(tenantId)" \
AzureAd__ClientId="$(clientId)" \
AzureAd__ClientSecret="$(clientSecret)"
# Update Function App settings (only for main and development-cs branches)
- task: AzureCLI@2
displayName: 'Update Function App Settings'
condition: or(eq(variables['Build.SourceBranchName'], 'main'), eq(variables['Build.SourceBranchName'], 'development-cs'))
inputs:
azureSubscription: '$(azureSubscription)'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
if [ "$(functionSlot)" = "development" ]; then
echo "Updating Function App settings for development slot (RandomFunctionApp/development)..."
az functionapp config appsettings set \
--name "$(functionAppName)" \
--resource-group "$(resourceGroupName)" \
--slot "development" \
--settings MyDbConnectionString="Server=tcp:$(sqlServerName),1433;Initial Catalog=$(sqlDatabaseName);Authentication=Active Directory Managed Identity;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
else
echo "Updating Function App settings for production Function App (RandomFunctionApp)..."
az functionapp config appsettings set \
--name "$(functionAppName)" \
--resource-group "$(resourceGroupName)" \
--settings MyDbConnectionString="Server=tcp:$(sqlServerName),1433;Initial Catalog=$(sqlDatabaseName);Authentication=Active Directory Managed Identity;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
fi
# Deploy the Function App package (only for main and development-cs branches)
- task: AzureFunctionApp@2
displayName: 'Deploy Function App to Azure'
condition: or(eq(variables['Build.SourceBranchName'], 'main'), eq(variables['Build.SourceBranchName'], 'development-cs'))
inputs:
connectedServiceNameARM: 'RandomAzureConnection'
appType: 'functionApp'
appName: '$(functionAppName)'
deployToSlotOrASE: true
resourceGroupName: '$(resourceGroupName)'
slotName: 'development'
package: '$(Pipeline.Workspace)/drop/functionapp.zip'
deploymentMethod: 'zipDeploy'
Изменить: я также заметил, что веб-приложение будет публиковаться в функции Azure. служба приложений, и моя служба приложений веб-приложений больше не будет публиковаться и отображать страницу с сообщением о том, что она готова к развертыванию.
Подробнее здесь: https://stackoverflow.com/questions/793 ... th-multipl