연습 - 웹 애플리케이션 배포
완구 회사 웹 사이트 개발 팀은 최신 버전의 웹 사이트를 Git 리포지토리에 커밋했습니다. 이제 파이프라인을 업데이트하여 웹 사이트를 빌드하고 Azure App Service에 배포할 수 있습니다.
이 프로세스에서는 다음 작업을 수행합니다.
- 빌드 작업에 대한 새 파이프라인 템플릿을 추가합니다.
- 빌드 작업을 포함하도록 파이프라인을 업데이트합니다.
- 새 스모크 테스트를 추가합니다.
- 배포 스테이지를 업데이트하여 애플리케이션을 배포합니다.
- 파이프라인을 실행합니다.
빌드 작업에 대한 파이프라인 템플릿 추가
웹 사이트 애플리케이션을 빌드하는 데 필요한 단계를 포함하는 새 작업 정의를 추가합니다.
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에서 실행할 준비가 된 컴파일된 파일로 전환합니다. 그런 다음 컴파일된 아티팩트를 임시 준비 폴더에 복사하고 파이프라인 아티팩트로 게시합니다.
파일의 변경 내용을 저장합니다.
첫 번째 파이프라인 스테이지의 이름을 변경하고 빌드 작업 추가
‘deploy’ 폴더에서 ‘azure-pipelines.yml’ 파일을 엽니다.
‘린트’ 스테이지를 수정합니다. 이름을 Build로 변경하고 만든 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
파일의 변경 내용을 저장합니다.
스모크 테스트 파일 업데이트
웹 사이트 개발자는 웹 사이트에 상태 엔드포인트를 추가했습니다. 이 엔드포인트는 웹 사이트가 온라인 상태이고 데이터베이스에 연결할 수 있는지 확인합니다. 여기서는 배포 파이프라인에서 상태 검사를 호출하는 새 스모크 테스트를 추가합니다.
‘deploy’ 폴더에서 ‘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 App Service에 게시하는 배포 단계를 추가하려고 하지만 게시 단계에는 App Service 앱의 이름이 필요합니다. 여기서는 앱 이름을 Bicep 파일의 출력으로 노출합니다.
‘deploy’ 폴더에서 ‘main.bicep’ 파일을 엽니다.
파일 내용의 끝에 App Service 앱의 이름을 출력으로 추가합니다.
output appServiceAppName string = appServiceApp.name output appServiceAppHostName string = appServiceApp.properties.defaultHostName
파일의 변경 내용을 저장합니다.
배포 스테이지 업데이트
‘deploy/pipeline-templates’ 폴더에서 ‘deploy.yml’ 파일을 엽니다.
배포 스테이지의 배포 작업 정의(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 파이프라인 에이전트 풀을 계속 사용합니다.
배포 작업의 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
파이프라인 실행
브라우저에서 Pipelines로 이동합니다.
가장 최근에 실행한 파이프라인을 선택합니다.
‘빌드’ 스테이지가 성공적으로 완료될 때까지 기다립니다.
파이프라인은 단계가 참조하는 변수 그룹을 사용할 수 있는 권한이 필요하므로 유효성 검사(테스트 환경) 단계를 실행하기 전에 일시 중지됩니다. 이 프로젝트에서 처음으로 파이프라인을 실행하기 때문에 변수 그룹에 대한 파이프라인의 액세스를 승인해야 합니다. 파이프라인을 다시 실행하면 동일한 변수 그룹에 대한 액세스를 승인할 필요가 없습니다.
보기를 선택합니다.
허용을 선택합니다.
허용을 선택합니다.
‘유효성 검사(테스트 환경)’ 스테이지가 성공적으로 완료됩니다.
파이프라인이 계속되고 배포(테스트 환경) 단계가 성공적으로 완료됩니다. 그런 다음, 파이프라인은 스모크 테스트(테스트 환경) 스테이지를 실행하지만 스모크 테스트 스테이지가 실패합니다.
스모크 테스트(테스트 환경) 스테이지를 선택하여 파이프라인 로그를 엽니다.
스모크 테스트 실행 단계를 선택하여 연결된 파이프라인 로그 섹션을 확인합니다.
파이프라인 로그에는 상태 검사 응답이 포함됩니다. 응답은 애플리케이션과 Azure SQL Database 간 통신에 문제가 있음을 나타냅니다. 데이터베이스가 아직 배포 또는 구성되지 않았으므로 웹 사이트에서 데이터베이스에 액세스할 수 없습니다. 다음 연습에서는 이 구성 문제를 해결합니다.