Ćwiczenie — wdrażanie aplikacji internetowej
W firmie zajmującej się projektowaniem witryn internetowych zaangażuj najnowszą wersję witryny internetowej do repozytorium Git. Teraz możesz zaktualizować potok, aby skompilować witrynę internetową i wdrożyć go w usłudze aplikacja systemu Azure Service.
W tym procesie wykonasz następujące zadania:
- Dodaj nowy szablon potoku dla zadania kompilacji.
- Zaktualizuj potok, aby uwzględnić zadanie kompilacji.
- Dodaj nowy test weryfikacyjny kompilacji.
- Zaktualizuj etap wdrażania, aby wdrożyć aplikację.
- Uruchom potok.
Dodawanie szablonu potoku dla zadania kompilacji
Dodaj nową definicję zadania zawierającą kroki wymagane do utworzenia aplikacji witryny internetowej.
Otwórz Visual Studio Code.
W folderze deploy/pipeline-templates utwórz nowy plik o nazwie build.yml.
Dodaj następującą zawartość do pliku szablonu potoku 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.
Zmienianie nazwy pierwszego etapu potoku i dodawanie zadania kompilacji
Otwórz plik azure-pipelines.yml w folderze deploy.
Zmodyfikuj etap Lint . Zmień jego nazwę na Build (Kompilacja) i dodaj zadanie kompilacji, które używa utworzonego szablonu potoku 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
Zapisz zmiany w pliku.
Aktualizowanie pliku testu weryfikacyjnego kompilacji
Deweloperzy witryny internetowej dodali do witryny internetowej punkt końcowy kondycji. 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 weryfikacyjny kompilacji w celu wywołania kontroli kondycji z potoku wdrażania.
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 aplikacja systemu Azure 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 zadania wdrażania etapu wdrażania (w pobliżu wiersza 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 kroki potoku dodane później do pracy z bazą danych wymagają uruchomienia systemu operacyjnego Windows. W potoku można używać różnych pul agentów dla różnych zadań, więc inne zadania nadal korzystają z puli agentów potoku systemu Ubuntu Linux.
W kroku SaveDeploymentOutputs zadania wdrażania 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ąisOutput=true
właściwość, ponieważ ta zmienna jest używana na etapie testu weryfikacyjnego kompilacji. ZmiennaappServiceAppName
jest ustawiana i używana w tym samym etapie i zadaniu potoku. W związku z tym ustawienie nie jest potrzebneisOutput=true
.Na końcu zawartości zadania Deploy (Wdrażanie zadania) dodaj nowy krok, aby wdrożyć aplikację w usłudze aplikacja systemu Azure 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'
Uwaga
Zachowaj ostrożność przy użyciu wcięcia pliku YAML, upewniając się, że nowy krok wdrażania jest wcięcie na tym samym poziomie co
DeployBicepFile
krok. 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 wdrażania, usługa Azure Pipelines automatycznie pobiera artefakt.
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 pozycji Potoki.
Wybierz najnowszy przebieg potoku.
Poczekaj na pomyślne zakończenie etapu kompilacji .
Potok jest wstrzymywane przed uruchomieniem etapu Validate (Test Environment), ponieważ potok musi mieć uprawnienia do używania grupy zmiennych, do których odwołuje się etap. Należy zatwierdzić dostęp potoku do grupy zmiennych, ponieważ uruchamiasz potok w tym projekcie po raz pierwszy. Po ponownym uruchomieniu potoku nie musisz zatwierdzać dostępu do tej samej grupy zmiennych.
Wybierz pozycję Widok.
Wybierz pozycję Zezwól.
Wybierz pozycję Zezwól.
Etap Weryfikacji (środowisko testowe) kończy się pomyślnie.
Potok będzie kontynuowany, a etap Wdrażanie (środowisko testowe) zakończy się pomyślnie. Następnie potok uruchamia etap Testu weryfikacyjnego kompilacji (środowisko testowe), ale etap testu weryfikacyjnego kompilacji kończy się niepowodzeniem.
Wybierz etap Testu weryfikacyjnego kompilacji (środowisko testowe), aby otworzyć dziennik potoku.
Wybierz krok Uruchom testy weryfikacyjne kompilacji, aby wyświetlić skojarzona sekcja dziennika potoku.
Zwróć uwagę, że dziennik potoku zawiera odpowiedź na kontrolę 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ą.