Ćwiczenie — wdrażanie aplikacji internetowej
W twojej firmie produkującej zabawki, zespół zajmujący się tworzeniem stron internetowych zaangażował najnowszą wersję witryny do repozytorium Git. Teraz możesz zaktualizować potok, aby utworzyć witrynę internetową i wdrożyć ją w usłudze Azure App Service.
W tym procesie wykonasz następujące zadania:
- Dodaj nowy szablon potoku dla zadania kompilacji.
- Zaktualizuj pipeline, aby dodać zadanie kompilacji.
- Dodaj nowy test podstawowy.
- Zaktualizuj etap wdrażania, aby wdrożyć aplikację.
- Uruchom potok.
Dodaj szablon potoku dla zadania kompilacji
Dodaj nową definicję zadania zawierającą kroki wymagane do utworzenia aplikacji witryny internetowej.
Otwórz program Visual Studio Code.
W folderze deploy/pipeline-templates utwórz nowy plik o nazwie build.yml.
Dodaj następującą zawartość do pliku szablonu przepływu pracy 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'
Zadanie uruchamia krok kompilacji, aby przekształcić kod źródłowy aplikacji witryny internetowej w skompilowany plik gotowy do uruchomienia na platformie Azure. Następnie zadanie kopiuje skompilowany artefakt do tymczasowego folderu przejściowego i publikuje go jako artefakt potoku.
Zapisz zmiany w pliku.
Zmień nazwę pierwszego etapu potoku i dodaj zadanie kompilacji.
Otwórz plik azure-pipelines.yml w folderze deploy.
Zmodyfikuj etap lint. Zmień jego nazwę na Buildi dodaj zadanie kompilacji, które wykorzystuje szablon potoku build.yml, który stworzyłeś.
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
Zapisz zmiany w pliku.
Zaktualizuj plik testu kontrolnego
Deweloperzy strony internetowej dodali do niej punkt końcowy monitorowania stanu. Ten punkt końcowy sprawdza, czy witryna internetowa jest w trybie online i czy może dotrzeć do bazy danych. W tym miejscu dodasz nowy test powierzchniowy w celu wywołania sprawdzenia kondycji z pipeline'u wdrożeniowego.
Otwórz plik Website.Tests.ps1 w folderze deploy.
Dodaj nowy przypadek testowy, który wywołuje kontrolę kondycji. Przypadek testowy kończy się niepowodzeniem, jeśli kod odpowiedzi nie ma wartości 200, co oznacza powodzenie.
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" } }
Zapisz zmiany w pliku.
Dodawanie danych wyjściowych do pliku Bicep
Chcesz dodać krok wdrażania, który publikuje witrynę internetową w usłudze Azure App Service, ale krok publikowania wymaga nazwy aplikacji usługi App Service. W tym miejscu uwidaczniasz nazwę aplikacji jako dane wyjściowe z pliku Bicep.
Otwórz plik main.bicep w folderze deploy.
Na końcu zawartości pliku dodaj nazwę aplikacji usługi App Service jako dane wyjściowe.
output appServiceAppName string = appServiceApp.name output appServiceAppHostName string = appServiceApp.properties.defaultHostName
Zapisz zmiany w pliku.
Etap wdrażania aktualizacji
Otwórz plik deploy.yml w folderze deploy/pipeline-templates.
W definicji zadań wdrożeniowych etapu wdrażania (w wierszu 59) skonfiguruj zadanie do korzystania z puli agentów hostowanych w systemie 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:
Niektóre z kroków potoku, które dodasz później do pracy z bazą danych, wymagają systemu operacyjnego Windows do uruchomienia. Można używać różnych pul agentów dla różnych zadań w swoim potoku, więc inne zadania nadal korzystają z agenta Ubuntu Linux.
W kroku Deploy job's SaveDeploymentOutputs dodaj nową zmienną potoku z wartością nazwy aplikacji z danych wyjściowych wdrożenia 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)
Zwróć uwagę, że zmienna
appServiceAppHostName
ma zastosowaną właściwośćisOutput=true
, ponieważ jest używana na etapie testu dymu. ZmiennaappServiceAppName
jest ustawiana i używana w tej samej fazie i zadaniu potoku. Nie wymaga więc ustawieniaisOutput=true
.Na końcu zawartości zadania Deploy dodaj nowy krok w celu wdrożenia aplikacji w usłudze 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'
Notatka
Zachowaj ostrożność przy wcięciach w pliku YAML, upewniając się, że nowy krok wdrażania jest wcięty na tym samym poziomie co krok
DeployBicepFile
. Jeśli nie masz pewności, skopiuj całą zawartość pliku deploy.yml z przykładu w następnym kroku.Zwróć uwagę, że artefakt nie został jawnie pobrany w definicji potoku. Ponieważ używasz zadania wdrożeniowego, usługa Azure Pipelines automatycznie pobiera artefakt dla Ciebie.
Weryfikowanie zawartości pliku deploy.yml i zatwierdzanie zmian
Sprawdź, czy plik deploy.yml wygląda następująco:
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'
Zapisz zmiany w pliku.
W terminalu programu Visual Studio Code zatwierdź i wypchnij zmiany do repozytorium Git, uruchamiając następujące polecenia:
git add . git commit -m "Build and deploy website application" git push
Uruchamianie potoku
W przeglądarce przejdź do Rurociągi.
Wybierz najnowszy przebieg potoku.
Poczekaj, aż etap kompilacji zakończy się pomyślnie.
Potok jest wstrzymywany przed uruchomieniem etapu Validate (Test Environment), ponieważ potok musi mieć uprawnienia do używania grupy zmiennych, do której odwołuje się etap. Musisz zatwierdzić dostęp potoku do grupy zmiennych, ponieważ uruchamiasz potok w tym projekcie po raz pierwszy. Gdy ponownie uruchomisz potok, nie musisz zatwierdzać dostępu do tej samej grupy zmiennych.
Wybierz Widok.
Wybierz Zezwól.
Wybierz Zezwól.
Etap weryfikacji (środowisko testowe) zakończy się pomyślnie.
Potok będzie kontynuowany, a etap wdrażania (środowiska testowego) zakończy się pomyślnie. Następnie pipeline uruchamia test dymny (środowisko testowe) na etapie, ale etap testu dymnego kończy się niepowodzeniem.
Wybierz etap Smoke Test (środowisko testowe), aby otworzyć dziennik dziennika potoku.
Wybierz krok Uruchom testy dymne, aby wyświetlić skojarzoną sekcję dziennika potoku.
Zwróć uwagę, że dziennik pipeline zawiera odpowiedź z kontroli kondycji. Odpowiedź wskazuje, że występuje problem z komunikacją aplikacji z usługą Azure SQL Database. Baza danych nie jest jeszcze wdrożona ani skonfigurowana, dlatego witryna internetowa nie może uzyskać do niej dostępu. W następnym ćwiczeniu rozwiążesz ten problem z konfiguracją.