연습 - Azure Pipelines에서 부하 테스트 실행

완료됨

이 섹션에서는 릴리스 파이프라인에서 만든 테스트 계획을 실행합니다. 테스트 계획은 Apache JMeter를 사용하여 부하 테스트를 실행합니다.

테스트를 실행하는 방법은 다음과 같습니다.

  • 테스트를 구현하는 Git 분기를 페치하고 체크 아웃합니다.
  • 파이프라인을 수정하여 JMeter를 설치하고, 테스트 계획을 실행하고, 결과를 JUnit으로 변환하고, 결과를 Azure Pipelines에 게시합니다.
  • GitHub에 분기를 푸시하고 Azure Pipelines에서 실행되는 테스트를 확인한 다음, 결과를 검토합니다.

GitHub에서 분기 가져오기

이 섹션에서는 GitHub에서 jmeter 분기를 페치하여 해당 분기로 체크 아웃하거나 전환합니다.

이 분기에는 이전 모듈에서 작업한 Space Game 프로젝트가 포함되어 있습니다. 또한 시작할 Azure Pipelines 구성을 포함합니다.

  1. Visual Studio Code에서 통합 터미널을 엽니다.

  2. Microsoft 리포지토리에서 git checkout라는 분기를 다운로드하고 해당 분기로 전환하려면 다음 jmetergit fetch 명령을 실행합니다.

    git fetch upstream jmeter
    git checkout -B jmeter upstream/jmeter
    

    upstream은 Microsoft GitHub 리포지토리를 나타냅니다. 프로젝트의 Git 구성은 upstream 원격을 이해합니다. Microsoft 리포지토리에서 프로젝트를 포크하고 로컬에 복제할 때 해당 관계를 설정했기 때문입니다.

    잠시 후에 이 분기를 origin이라는 GitHub 리포지토리로 푸시합니다.

  3. 필요에 따라 Visual Studio Code에서 azure-pipelines.yml 파일을 엽니다. 초기 구성을 검토합니다.

    구성은 이 학습 경로의 이전 모듈에서 만든 구성과 유사합니다. 이 구성은 애플리케이션의 릴리스 구성만 빌드합니다. 간단히 하기 위해 이전 모듈에서 설정한 트리거, 수동 승인, 테스트가 생략됩니다.

    참고

    더 강력한 구성은 빌드 프로세스에 참여하는 분기를 지정할 수 있습니다. 예를 들어 코드 품질을 확인하기 위해 모든 분기에 변경 내용을 푸시할 때마다 단위 테스트를 실행할 수 있습니다. 더 철저한 테스트를 수행하는 환경에 애플리케이션을 배포할 수도 있습니다. 하지만 끌어오기 요청이 있거나, 릴리스 후보가 있거나, 코드를 ‘main’에 병합할 때만 이 배포를 실행합니다.

    자세한 내용은 Git 및 GitHub를 사용하여 빌드 파이프라인에서 코드 워크플로 구현빌드 파이프라인 트리거를 참조하세요.

  4. 선택적으로 Visual Studio Code에서 JMeter 테스트 계획 파일, LoadTest.jmx 및 XLST 변환, JMeter2JUnit.xsl을 체크 아웃할 수 있습니다. XLST 파일은 Azure Pipelines가 결과를 시각화할 수 있도록 JMeter 출력을 JUnit으로 변환합니다.

Azure Pipelines에 변수 추가

팀의 원래 테스트 계획은 스테이징 환경에서 실행되는 Space Game 웹 사이트의 호스트 이름에 대해 하드 코딩된 값을 제공합니다.

테스트 계획을 더 유연하게 만들기 위해 버전은 JMeter 속성을 사용합니다. 속성을 명령줄에서 설정할 수 있는 변수로 생각하세요.

JMeter에서 hostname 변수가 정의되는 방식은 다음과 같습니다.

Screenshot of setting the hostname variable in Apache JMeter.

다음은 hostname 변수가 __ P 함수를 사용하여 hostname 변수를 읽는 방법입니다.

Screenshot for reading the hostname variable in Apache JMeter.

해당 테스트 계획 파일인 LoadTest.jmx는 이 변수를 지정한 다음, 호스트 이름을 설정하는 데 사용합니다.

명령줄에서 JMeter를 실행할 때 -J 인수를 사용하여 hostname 속성을 설정합니다. 예를 들면 다음과 같습니다.

apache-jmeter-5.4.3/bin/./jmeter -n -t LoadTest.jmx -o Results.xml -Jhostname=tailspin-space-game-web-staging-1234.azurewebsites.net

여기서는 Azure Pipelines에서 변수를 설정합니다 STAGING_HOSTNAME . 이 변수는 스테이징 환경의 App Service에서 실행되는 사이트의 호스트 이름을 가리킵니다. 또한 jmeterVersion을 설정하여 설치할 JMeter 버전을 지정합니다.

에이전트가 실행되면 이러한 변수가 자동으로 환경 변수로 에이전트로 내보내지므로 파이프라인 구성에서 다음과 같이 JMeter를 실행할 수 있습니다.

apache-jmeter-5.4.3/bin/./jmeter -n -t LoadTest.jmx -o Results.xml -Jhostname=$(STAGING_HOSTNAME)

파이프라인 구성을 업데이트하기 전에 이제 파이프라인 변수를 추가해 보겠습니다. 이를 수행하려면:

  1. Azure DevOps에서 Space Game - web - Nonfunctional tests 프로젝트로 이동합니다.

  2. 파이프라인에서 라이브러리를 선택합니다.

  3. 릴리스 변수 그룹을 선택합니다.

  4. 변수에서 + 추가를 선택합니다.

  5. 변수 이름으로 STAGING_HOSTNAME을 입력합니다. 값으로 tailspin-space-game-web-staging-1234.azurewebsites.net과 같이 스테이징 환경에 해당하는 App Service 인스턴스의 URL을 입력합니다.

    중요

    값에 http:// 또는 https:// 프로토콜 접두사를 포함하지 마세요. JMeter에서는 테스트를 실행할 때 프로토콜을 제공합니다.

  6. jmeterVersion이라는 두 번째 변수를 추가합니다. 해당 값으로 5.4.3을 지정합니다.

    참고

    이 모듈을 테스트하는 데 마지막으로 사용한 JMeter의 버전입니다. 최신 버전을 얻으려면 Apache JMeter 다운로드를 참조하세요.

  7. 파이프라인에 변수를 저장하려면 페이지 맨 위에 있는 저장을 선택합니다.

    변수 그룹은 다음 이미지에 표시된 것과 유사합니다.

    Screenshot of Azure Pipelines, showing the variable group. The group contains five variables.

파이프라인 구성 수정

이 섹션에서는 스테이징 단계에서 부하 테스트를 실행하도록 파이프라인을 수정합니다.

  1. Visual Studio Code에서 azure-pipelines.yml 파일을 엽니다. 그런 다음, 다음과 같이 파일을 수정합니다.

    전체 파일을 바꾸거나 강조 표시된 부분만 업데이트할 수 있습니다.

    trigger:
    - '*'
    
    variables:
      buildConfiguration: 'Release'
    
    stages:
    - stage: 'Build'
      displayName: 'Build the web application'
      jobs:
      - job: 'Build'
        displayName: 'Build job'
        pool:
          vmImage: 'ubuntu-20.04'
          demands:
          - npm
    
        variables:
          wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
          dotnetSdkVersion: '6.x'
    
        steps:
        - task: UseDotNet@2
          displayName: 'Use .NET SDK $(dotnetSdkVersion)'
          inputs:
            version: '$(dotnetSdkVersion)'
    
        - task: Npm@1
          displayName: 'Run npm install'
          inputs:
            verbose: false
    
        - script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
          displayName: 'Compile Sass assets'
    
        - task: gulp@1
          displayName: 'Run gulp tasks'
    
        - script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
          displayName: 'Write build info'
          workingDirectory: $(wwwrootDir)
    
        - task: DotNetCoreCLI@2
          displayName: 'Restore project dependencies'
          inputs:
            command: 'restore'
            projects: '**/*.csproj'
    
        - task: DotNetCoreCLI@2
          displayName: 'Build the project - $(buildConfiguration)'
          inputs:
            command: 'build'
            arguments: '--no-restore --configuration $(buildConfiguration)'
            projects: '**/*.csproj'
    
        - task: DotNetCoreCLI@2
          displayName: 'Publish the project - $(buildConfiguration)'
          inputs:
            command: 'publish'
            projects: '**/*.csproj'
            publishWebProjects: false
            arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
            zipAfterPublish: true
    
        - publish: '$(Build.ArtifactStagingDirectory)'
          artifact: drop
    
    - stage: 'Dev'
      displayName: 'Deploy to the dev environment'
      dependsOn: Build
      jobs:
      - deployment: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: dev
        variables:
        - group: Release
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: drop
              - task: AzureWebApp@1
                displayName: 'Azure App Service Deploy: website'
                inputs:
                  azureSubscription: 'Resource Manager - Tailspin - Space Game'
                  appName: '$(WebAppNameDev)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
    
    - stage: 'Test'
      displayName: 'Deploy to the test environment'
      dependsOn: Dev
      jobs:
      - deployment: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: test
        variables:
        - group: 'Release'
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: drop
              - task: AzureWebApp@1
                displayName: 'Azure App Service Deploy: website'
                inputs:
                  azureSubscription: 'Resource Manager - Tailspin - Space Game'
                  appName: '$(WebAppNameTest)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
    
    - stage: 'Staging'
      displayName: 'Deploy to the staging environment'
      dependsOn: Test
      jobs:
      - deployment: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: staging
        variables:
        - group: 'Release'
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: drop
              - task: AzureWebApp@1
                displayName: 'Azure App Service Deploy: website'
                inputs:
                  azureSubscription: 'Resource Manager - Tailspin - Space Game'
                  appName: '$(WebAppNameStaging)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
      - job: RunLoadTests
        dependsOn: Deploy
        displayName: 'Run load tests'
        pool:
          vmImage: 'ubuntu-20.04'
        variables:
        - group: Release
        steps:
        - script: |
            wget -c archive.apache.org/dist/jmeter/binaries/apache-jmeter-$(jmeterVersion).tgz
            tar -xzf apache-jmeter-$(jmeterVersion).tgz
          displayName: 'Install Apache JMeter'
        - script: apache-jmeter-$(jmeterVersion)/bin/./jmeter -n -t LoadTest.jmx -o Results.xml -Jhostname=$(STAGING_HOSTNAME)
          displayName: 'Run Load tests'
        - script: |
            sudo apt-get update
            sudo apt-get install xsltproc
            xsltproc JMeter2JUnit.xsl Results.xml > JUnit.xml
          displayName: 'Transform JMeter output to JUnit'
        - task: PublishTestResults@2
          inputs:
            testResultsFormat: JUnit
            testResultsFiles: JUnit.xml
    

    아래에 변경 내용이 요약되어 있습니다.

    • RunLoadTests 작업은 Linux 에이전트에서 부하 테스트를 수행합니다.
    • RunLoadTests 작업은 Deploy 작업을 사용하여 작업이 올바른 순서로 실행되는지 확인합니다. 부하 테스트를 실행하기 전에 App Service에 웹 사이트를 배포해야 합니다. 이 종속성을 지정하지 않으면 단계 내의 작업이 임의의 순서로 실행되거나 병렬로 실행될 수 있습니다.
    • 첫 번째 script 작업에서 JMeter를 다운로드하고 설치합니다. jmeterVersion 파이프라인 변수는 설치할 JMeter의 버전을 지정합니다.
    • 두 번째 script 작업은 JMeter를 실행합니다. -J 인수는 파이프라인에서 STAGING_HOSTNAME 변수를 읽어 JMeter에서 hostname 속성을 설정합니다.
    • 세 번째 script 작업에서는 XSLT 프로세서인 xsltproc를 설치하고 JMeter 출력을 JUnit으로 변환합니다.
    • PublishTestResults@2작업은 결과적으로 생성되는 JUnit 보고서, JUnit.xml을 파이프라인에 게시합니다. Azure Pipelines를 사용하면 테스트 결과를 시각화할 수 있습니다.
  2. 통합 터미널에서 azure-pipelines.yml을 인덱스에 추가하고, 변경 내용을 커밋하며, 분기를 GitHub로 푸시합니다.

    git add azure-pipelines.yml
    git commit -m "Run load tests with Apache JMeter"
    git push origin jmeter
    

테스트를 실행하는 Azure Pipelines 보기

여기서는 파이프라인 실행을 살펴보겠습니다. 스테이징 중에 부하 테스트가 실행되는 것을 볼 수 있습니다.

  1. Azure Pipelines에서 빌드로 이동하고 실행되는 빌드를 추적합니다.

    준비하는 동안 웹 사이트가 배포된 다음 부하 테스트가 실행되는 것을 볼 수 있습니다.

  2. 빌드가 완료되면 요약 페이지로 이동합니다.

    Screenshot of Azure Pipelines, showing the completed stages.

    배포 및 부하 테스트가 성공적으로 완료된 것을 볼 수 있습니다.

  3. 페이지 상단 부근에서 요약을 확인합니다.

    Space Game 웹 사이트의 빌드 아티팩트가 언제나처럼 게시된 것을 볼 수 있습니다. 부하 테스트가 통과되었음을 보여 주는 테스트 및 검사 섹션도 확인합니다.

    A screenshot of Azure Pipelines, showing the test summary.

  4. 테스트 요약을 선택하여 전체 보고서를 확인합니다.

    이 보고서에서는 두 테스트가 모두 통과한 것으로 표시합니다.

    Screenshot of Azure Pipelines, showing the full test report.

    테스트가 실패하는 경우 오류에 대한 자세한 결과가 표시됩니다. 이 결과에서 실패의 원인을 조사할 수 있습니다.

    XSLT 파일은 JUnit.xml이라는 JUnit 파일을 생성합니다. JUnit 파일에서는 다음 두 가지 질문에 답변합니다.

    • 평균 요청 시간이 1초 미만인가요?
    • 완료하는 데 1초 이상 걸리는 요청이 10% 미만인가요?

    보고서는 해당 요구 사항을 충족하는지 증명합니다. 세부 정보를 보려면 보고서에서 결과 화살표를 선택합니다. 그런 다음 통과된 항목만 선택되어 있는지 확인합니다.

    Screenshot of Filtering passed tests in the test report.

    평균 응답 시간최대 응답 시간 테스트 사례가 모두 성공했음을 확인할 수 있습니다.

    Screenshot of the test report, showing two successful test cases.

참고 항목

기본 계층에서 실행되는 B1 App Service 요금제를 사용하고 있습니다. 이 요금제는 테스트 환경의 앱과 같이 트래픽 요구 사항이 낮은 앱용입니다. 이 요금제에서는 웹 사이트의 성능이 예상보다 떨어질 수 있습니다. 실제로 프로덕션 환경과 더 밀접하게 일치하는 스테이징 환경에 대한 계획을 선택합니다. 예를 들어 표준프리미엄 요금제는 프로덕션 워크로드와 관련이 있습니다. 이는 전용 가상 머신 인스턴스에서 실행됩니다.