Упражнение. Развертывание веб-приложения
В вашей компании по производству игрушек команда разработчиков закоммитила последнюю версию веб-сайта в ваш репозиторий Git. Теперь вы готовы обновить конвейер для сборки веб-сайта и развернуть его в Службе приложений Azure.
В этом процессе выполняются следующие задачи:
- Добавьте новый шаблон конвейера для задания сборки.
- Обновите конвейер, чтобы включить задание сборки.
- Добавьте новый тест дыма.
- Обновите этап развертывания, чтобы развернуть приложение.
- Запустите конвейер.
Добавление шаблона конвейера для задания сборки
Добавьте новое определение задания, содержащее шаги, необходимые для создания приложения веб-сайта.
Откройте Visual Studio Code.
В папке deploy/pipeline-templates создайте новый файл с именем build.yml.
Добавьте следующее содержимое в файл шаблона конвейера build.yml:
jobs: - job: Build displayName: Build application and database pool: vmImage: windows-latest steps: # Build, copy, and publish the website. - task: DotNetCoreCLI@2 displayName: Build publishable website inputs: command: 'publish' publishWebProjects: true - task: CopyFiles@2 displayName: Copy publishable website inputs: sourceFolder: '$(Build.SourcesDirectory)/src/ToyCompany/ToyCompany.Website/bin' contents: '**/publish.zip' targetFolder: '$(Build.ArtifactStagingDirectory)/website' flattenFolders: true - task: PublishBuildArtifacts@1 displayName: Publish website as pipeline artifact inputs: pathToPublish: '$(Build.ArtifactStagingDirectory)/website' artifactName: 'website'
Задание выполняет шаг сборки, чтобы превратить исходный код приложения веб-сайта в скомпилированный файл, готовый к выполнению в Azure. Затем задание копирует скомпилированный артефакт во временную промежуточную папку и публикует его в качестве артефакта конвейера.
Сохраните изменения в файле.
Переименуйте первый этап конвейера и добавьте задание сборки
Откройте файл azure-pipelines.yml в папке deploy.
Подкорректируйте этап Lint. Переименуйте его в Сборкаи добавьте задачу сборки, используя шаблон конвейера build.yml , который вы создали.
trigger: batch: true branches: include: - main pool: vmImage: ubuntu-latest stages: - stage: Build jobs: # Build the Visual Studio solution. - template: pipeline-templates/build.yml # Lint the Bicep file. - template: pipeline-templates/lint.yml # Deploy to the test environment. - template: pipeline-templates/deploy.yml parameters: environmentType: Test # Deploy to the production environment. - template: pipeline-templates/deploy.yml parameters: environmentType: Production
Сохраните изменения в файле.
Обновление файла теста дыма
Разработчики добавили на веб-сайт проверку состояния. Эта конечная точка проверяет, находится ли веб-сайт в сети и что он может получить доступ к базе данных. Здесь вы добавите новый тест дыма для вызова проверки работоспособности из конвейера развертывания.
Откройте файл Website.Tests.ps1 в папке развертывания.
Добавьте новый тестовый случай, вызывающий проверку работоспособности. Тестовый случай завершается ошибкой, если код ответа не равен 200, что указывает на успех.
param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $HostName ) Describe 'Toy Website' { It 'Serves pages over HTTPS' { $request = [System.Net.WebRequest]::Create("https://$HostName/") $request.AllowAutoRedirect = $false $request.GetResponse().StatusCode | Should -Be 200 -Because "the website requires HTTPS" } It 'Does not serves pages over HTTP' { $request = [System.Net.WebRequest]::Create("http://$HostName/") $request.AllowAutoRedirect = $false $request.GetResponse().StatusCode | Should -BeGreaterOrEqual 300 -Because "HTTP is not secure" } It 'Returns a success code from the health check endpoint' { $response = Invoke-WebRequest -Uri "https://$HostName/health" -SkipHttpErrorCheck Write-Host $response.Content $response.StatusCode | Should -Be 200 -Because "the website and configuration should be healthy" } }
Сохраните изменения в файле.
Добавление выходных данных в файл Bicep
Вы хотите добавить шаг развертывания, который публикует веб-сайт в Службе приложений Azure, но для шага публикации требуется имя приложения службы приложений. Здесь вы предоставляете имя приложения в виде выходных данных из файла Bicep.
Откройте файл main.bicep в папке deploy.
В конце содержимого файла добавьте имя приложения службы приложений в качестве выходных данных.
output appServiceAppName string = appServiceApp.name output appServiceAppHostName string = appServiceApp.properties.defaultHostName
Сохраните изменения в файле.
Этап развертывания обновления
Откройте файл deploy.yml в папке deploy/pipeline-templates.
В определении задания развертывания этапа Deploy (около строки 59) настройте задание для использования хостингового пула агентов Windows:
- stage: Deploy_${{parameters.environmentType}} displayName: Deploy (${{parameters.environmentType}} Environment) jobs: - deployment: DeployWebsite displayName: Deploy website pool: vmImage: windows-latest variables: - group: ToyWebsite${{parameters.environmentType}} environment: ${{parameters.environmentType}} strategy:
Некоторые этапы конвейера, которые вы добавили позже для работы с базой данных, требуют запуска операционной системы Windows. Пулы агентов можно использовать для различных заданий в конвейере, поэтому другие задания продолжают использовать пул агентов конвейера Ubuntu Linux.
На этапе Deploy в задаче SaveDeploymentOutputs добавьте новую переменную конвейера со значением имени приложения из выходных данных развертывания Bicep.
- bash: | echo "##vso[task.setvariable variable=appServiceAppName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppName.value')" echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')" name: SaveDeploymentOutputs displayName: Save deployment outputs into variables env: DEPLOYMENT_OUTPUTS: $(deploymentOutputs)
Обратите внимание, что переменная
appServiceAppHostName
имеет к ней свойствоisOutput=true
, так как эта переменная используется на этапе тестирования дыма. ПеременнаяappServiceAppName
устанавливается и используется в одном этапе конвейера и задании. Поэтому не требуется параметрisOutput=true
.В конце содержимого задания развертывания добавьте новый шаг для развертывания приложения в Azure App Service:
steps: - checkout: self - task: AzureResourceManagerTemplateDeployment@3 name: DeployBicepFile displayName: Deploy Bicep file inputs: connectedServiceName: ToyWebsite${{parameters.environmentType}} deploymentName: $(Build.BuildNumber) location: ${{parameters.deploymentDefaultLocation}} resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) -reviewApiUrl $(ReviewApiUrl) -reviewApiKey $(ReviewApiKey) deploymentOutputs: deploymentOutputs - bash: | echo "##vso[task.setvariable variable=appServiceAppName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppName.value')" echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')" name: SaveDeploymentOutputs displayName: Save deployment outputs into variables env: DEPLOYMENT_OUTPUTS: $(deploymentOutputs) - task: AzureRmWebAppDeployment@4 name: DeployWebsiteApp displayName: Deploy website inputs: appType: webApp ConnectionType: AzureRM azureSubscription: ToyWebsite${{parameters.environmentType}} ResourceGroupName: $(ResourceGroupName) WebAppName: $(appServiceAppName) Package: '$(Pipeline.Workspace)/website/publish.zip'
Заметка
Будьте осторожны с отступами файла YAML, чтобы шаг нового развертывания находился на том же уровне отступа, что и шаг
DeployBicepFile
. Если вы не уверены, скопируйте содержимое файла deploy.yml из примера на следующем шаге.Обратите внимание, что вы явно не скачали артефакт в определении конвейера. Поскольку вы используете задание развертывания, Azure Pipelines автоматически загружает этот артефакт.
Проверьте содержимое файла deploy.yml и зафиксируйте изменения
Убедитесь, что файл deploy.yml выглядит следующим образом:
parameters: - name: environmentType type: string - name: deploymentDefaultLocation type: string default: westus3 stages: - ${{ if ne(parameters.environmentType, 'Production') }}: - stage: Validate_${{parameters.environmentType}} displayName: Validate (${{parameters.environmentType}} Environment) jobs: - job: ValidateBicepCode displayName: Validate Bicep code variables: - group: ToyWebsite${{parameters.environmentType}} steps: - task: AzureResourceManagerTemplateDeployment@3 name: RunPreflightValidation displayName: Run preflight validation inputs: connectedServiceName: ToyWebsite${{parameters.environmentType}} location: ${{parameters.deploymentDefaultLocation}} deploymentMode: Validation resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) -reviewApiUrl $(ReviewApiUrl) -reviewApiKey $(ReviewApiKey) - ${{ if eq(parameters.environmentType, 'Production') }}: - stage: Preview_${{parameters.environmentType}} displayName: Preview (${{parameters.environmentType}} Environment) jobs: - job: PreviewAzureChanges displayName: Preview Azure changes variables: - group: ToyWebsite${{parameters.environmentType}} steps: - task: AzureCLI@2 name: RunWhatIf displayName: Run what-if inputs: azureSubscription: ToyWebsite${{parameters.environmentType}} scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | az deployment group what-if \ --resource-group $(ResourceGroupName) \ --template-file deploy/main.bicep \ --parameters environmentType=$(EnvironmentType) \ reviewApiUrl=$(ReviewApiUrl) \ reviewApiKey=$(ReviewApiKey) - stage: Deploy_${{parameters.environmentType}} displayName: Deploy (${{parameters.environmentType}} Environment) jobs: - deployment: DeployWebsite displayName: Deploy website pool: vmImage: windows-latest variables: - group: ToyWebsite${{parameters.environmentType}} environment: ${{parameters.environmentType}} strategy: runOnce: deploy: steps: - checkout: self - task: AzureResourceManagerTemplateDeployment@3 name: DeployBicepFile displayName: Deploy Bicep file inputs: connectedServiceName: ToyWebsite${{parameters.environmentType}} deploymentName: $(Build.BuildNumber) location: ${{parameters.deploymentDefaultLocation}} resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) -reviewApiUrl $(ReviewApiUrl) -reviewApiKey $(ReviewApiKey) deploymentOutputs: deploymentOutputs - bash: | echo "##vso[task.setvariable variable=appServiceAppName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppName.value')" echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')" name: SaveDeploymentOutputs displayName: Save deployment outputs into variables env: DEPLOYMENT_OUTPUTS: $(deploymentOutputs) - task: AzureRmWebAppDeployment@4 name: DeployWebsiteApp displayName: Deploy website inputs: appType: webApp ConnectionType: AzureRM azureSubscription: ToyWebsite${{parameters.environmentType}} ResourceGroupName: $(ResourceGroupName) WebAppName: $(appServiceAppName) Package: '$(Pipeline.Workspace)/website/publish.zip' - stage: SmokeTest_${{parameters.environmentType}} displayName: Smoke Test (${{parameters.environmentType}} Environment) jobs: - job: SmokeTest displayName: Smoke test variables: appServiceAppHostName: $[ stageDependencies.Deploy_${{parameters.environmentType}}.DeployWebsite.outputs['DeployWebsite.SaveDeploymentOutputs.appServiceAppHostName'] ] steps: - task: PowerShell@2 name: RunSmokeTests displayName: Run smoke tests inputs: targetType: inline script: | $container = New-PesterContainer ` -Path 'deploy/Website.Tests.ps1' ` -Data @{ HostName = '$(appServiceAppHostName)' } Invoke-Pester ` -Container $container ` -CI - task: PublishTestResults@2 name: PublishTestResults displayName: Publish test results condition: always() inputs: testResultsFormat: NUnit testResultsFiles: 'testResults.xml'
Сохраните изменения в файле.
В терминале Visual Studio Code зафиксируйте и отправьте изменения в репозиторий Git, выполнив следующие команды:
git add . git commit -m "Build and deploy website application" git push
Запуск конвейера
В браузере перейдите к Конвейеры.
Выберите последний запуск конвейера.
Дождитесь успешного завершения этапа сборки.
Конвейер приостанавливается перед запуском этапа проверки (тестовая среда), так как конвейеру требуется разрешение на использование группы переменных, на которую ссылается этап. Необходимо одобрить доступ конвейера к группе переменных, так как вы впервые запускаете конвейер в этом проекте. При повторном запуске конвейера не нужно утверждать доступ к той же группе переменных.
Выберите вид.
Выберите Разрешение.
Выберите Разрешение.
Этап проверки (тестовая среда) завершается успешно.
Конвейер продолжается, и этап развертывания (тестовая среда) успешно завершается. Затем конвейер запускает тестовый тест (тестовая среда) этап, но этап тестирования дыма завершается сбоем.
Выберите этап теста дыма (тестовая среда), чтобы открыть журнал конвейера.
Выберите Выполнить тесты дыма, чтобы просмотреть связанный раздел журнала конвейера.
Обратите внимание, что журнал конвейера включает ответ проверки работоспособности. Ответ указывает, что возникла проблема с взаимодействием приложения с базой данных SQL Azure. База данных еще не развернута или настроена, поэтому веб-сайт не может получить к нему доступ. В следующем упражнении вы исправите эту проблему конфигурации.