HAQM Web Services 한국 블로그

AWS CodeBuild를 통한 CI 가속화, 병렬 테스트 실행 지원

AWS CodeBuild가 병렬 테스트 실행을 지원합니다. 이를 통해 테스트 스위트를 동시에 실행하여 빌드 시간을 크게 단축할 수 있습니다. 이 게시물을 위해 작성한 데모 프로젝트에서는 환경을 프로비저닝하는 시간을 포함하여 총 테스트 시간이 35분에서 6분으로 단축되었습니다. AWS Management Console에서 가져온 두 스크린샷이 그 차이를 보여줍니다.

테스트 스위트 순차 실행

CodeBuild 병렬 테스트 결과

테스트 스위트 병렬 실행

CodeBuild 병렬 테스트 결과

테스트 시간이 매우 길면 대규모로 지속적 통합(CI)을 실행할 때 상당한 어려움이 발생합니다. 프로젝트가 복잡해지고 팀 규모가 확대되면서 포괄적인 테스트 스위트를 실행하는 데 필요한 시간이 크게 늘어나 파이프라인 실행 시간이 증가할 수 있습니다. 이로 인해 새로운 기능 및 버그 수정 제공이 지연될 뿐만 아니라 작업을 진행하기 전에 빌드 결과를 기다려야 하므로 개발자의 생산성이 저하됩니다. 저는 파이프라인을 실행하는 데 최대 60분이 걸렸는데, 마지막 단계에서 실패하면서 전체 재실행이 필요하여 추가 지연을 경험한 것입니다. 이러한 긴 주기는 CI 프로세스에서 개발자 신뢰를 떨어뜨리고 불만을 야기하며 궁극적으로 전체 소프트웨어 제공 주기를 늦출 수 있습니다. 또한 테스트를 오래 실행하면 리소스 경합이 발생하고 컴퓨팅 성능 낭비로 인한 비용이 증가하며 개발 프로세스의 전반적인 효율성이 저하될 수 있습니다.

CodeBuild의 병렬 테스트 실행을 통해 이제 여러 빌드 컴퓨팅 환경에서 동시에 테스트를 실행할 수 있습니다. 이 기능은 각 빌드 노드가 테스트 스위트의 하위 집합을 독립적으로 실행하는 샤딩 접근 방식을 구현합니다. CodeBuild는 각 노드가 실행해야 하는 테스트를 결정하는 데 사용되는 현재 노드 수와 총 노드 수를 식별하는 환경 변수를 제공합니다. 빌드 시에는 제어 빌드 노드나 노드 간의 조정이 없습니다. 각 노드는 독립적으로 작동하여 할당된 테스트를 실행합니다.

테스트 분할을 활성화하려면 buildspec.xml에서 원하는 병렬 처리 수준 및 기타 관련 파라미터를 지정하여 batch fanout 섹션을 구성합니다. 또한 빌드 단계에서 적절한 테스트 명령 및 선택한 분할 방법과 함께 codebuild-tests-run 유틸리티를 사용하세요.

테스트는 지정한 샤딩 전략에 따라 분할됩니다. codebuild-tests-run은 두 가지 샤딩 전략을 제공합니다.

  • 균등 분배. 이 전략은 테스트 파일을 알파벳순으로 정렬하고 병렬 테스트 환경 간에 균등하게 청크 단위로 배포합니다. 테스트 파일의 이름 또는 수량을 변경하면 샤드 전체에 파일이 재할당될 수 있습니다.
  • 안정성. 이 전략은 일관된 해싱 알고리즘을 사용하여 샤드 전반에서 테스트 분포를 수정합니다. 파일이 추가 또는 제거될 때 기존의 파일-샤드 할당이 유지됩니다.

테스트를 병렬로 실행할 때 CodeBuild는 테스트 보고서의 자동 병합을 지원합니다. CodeBuild는 자동 테스트 보고서 병합 기능을 통해 테스트 보고서를 단일 테스트 요약으로 통합하여 결과 분석을 간소화합니다. 병합된 보고서에는 집계된 합격/불합격 상태, 테스트 기간 및 실패 세부 정보가 포함되므로 수동 보고서 처리의 필요성이 줄어듭니다. CodeBuild 콘솔에서 병합된 결과를 보거나, AWS Command Line Interface(AWS CLI)를 사용하여 검색하거나, 다른 보고 도구와 통합하여 테스트 분석을 간소화할 수 있습니다.

작동 방식
프로젝트에서 병렬 테스트를 구현하는 방법을 보여드리겠습니다. 이 데모에서는 수백 개의 테스트가 포함된 아주 기본적인 Python 프로젝트를 생성했습니다. 작업 속도를 높이기 위해 명령줄에서 HAQM Q Developer에게 프로젝트 1개와 테스트 사례 1,800개를 생성해 달라고 요청했습니다. 각 테스트 사례는 별도의 파일이며 완료하는 데 1초가 걸립니다. 모든 테스트를 순서대로 실행하려면 환경을 프로비저닝하는 시간을 제외하고 30분이 소요됩니다.

이 데모에서는 10개의 컴퓨팅 환경에서 테스트 스위트를 병렬로 실행하고 스위트를 실행하는 데 걸리는 시간을 측정합니다.

이를 위해 프로젝트에 buildspec.yml 파일을 추가했습니다.

version: 0.2

batch:
  fast-fail: false
  build-fanout:
    parallelism: 10 # ten runtime environments 
    ignore-failure: false

phases:
  install:
    commands:
      - echo 'Installing Python dependencies'
      - dnf install -y python3 python3-pip
      - pip3 install --upgrade pip
      - pip3 install pytest
  build:
    commands:
      - echo 'Running Python Tests'
      - |
         codebuild-tests-run \
          --test-command 'python -m pytest --junitxml=report/test_report.xml' \
          --files-search "codebuild-glob-search 'tests/test_*.py'" \
          --sharding-strategy 'equal-distribution'
  post_build:
    commands:
      - echo "Test execution completed"

reports:
  pytest_reports:
    files:
      - "*.xml"
    base-directory: "report"
    file-format: JUNITXML 

YAML 파일에서 강조할 부분이 3개 있습니다.

먼저, batch 아래에 build-fanout 섹션이 있습니다. parallelism 명령은 CodeBuild에 병렬 실행할 테스트 환경의 수를 알려줍니다. ignore-failure 명령은 팬아웃 빌드 태스크 실패를 무시할 수 있는지 여부를 나타냅니다.

둘째, 사전 설치된 codebuild-tests-run 명령을 사용하여 테스트를 실행합니다.

이 명령은 전체 테스트 파일 목록을 수신하고 현재 노드에서 실행해야 하는 테스트를 결정합니다.

  • sharding-strategy 인수를 사용하여 위에서 설명한 것처럼 균등 분포 또는 안정성 분포 중에서 선택합니다.
  • files-search 인수를 사용하여 실행 대상 파일을 모두 전달합니다. 성능상의 이유로 제공된 codebuild-glob-search 명령을 사용하는 것이 좋지만 find(1)와 같은 모든 파일 검색 도구를 사용할 수 있습니다.
  • test-command 인수를 사용하여 샤드에서 실행할 실제 테스트 명령을 전달합니다.

마지막으로, reports 섹션은 CodeBuild에 각 노드의 테스트 보고서를 수집하고 병합하도록 지시합니다.

그런 다음 CodeBuild 콘솔을 열어 프로젝트와 이 프로젝트의 배치 빌드 구성을 생성합니다. 여기에는 새로운 것이 없으므로 자세한 내용은 생략하겠습니다. 설명서에 시작하는 데 필요한 모든 세부 정보가 있습니다병렬 테스트는 배치 빌드에서 작동합니다. 프로젝트를 배치로 실행되도록 구성해야 합니다.

CodeBuild: 배치 빌드 생성

이제 테스트 스위트 실행을 트리거할 준비가 되었습니다. GitHub 리포지토리에서 새 코드를 커밋하거나 콘솔에서 빌드를 트리거할 수 있습니다.

CodeBuild: 새 빌드 트리거

몇 분 후 각 테스트 환경 또는 샤드의 상태와 함께 빌드의 여러 단계에 대한 상태 보고서가 표시됩니다.

CodeBuild: 상태

테스트가 완료되면 Reports 탭을 선택하여 병합된 테스트 보고서에 액세스합니다.

CodeBuild: 테스트 보고서

Reports 섹션은 모든 샤드의 모든 테스트 데이터를 집계하고 모든 빌드의 기록을 보관합니다. Report history 섹션에서 가장 최근 빌드를 선택하여 세부 보고서에 액세스합니다.

CodeBuild: 테스트 보고서

예상대로 1,800개 테스트 사례의 집계된 상태와 각 테스트 사례의 개별 상태를 볼 수 있습니다. 이 데모에서는 모두 통과하여 보고서가 초록색입니다.

데모 프로젝트의 1,800개 테스트는 각각 완료하는 데 1초가 걸립니다. 이 테스트 스위트를 순차적으로 실행했을 때 완료하는 데 35분이 걸렸습니다. 테스트 스위트를 10개의 컴퓨팅 환경에서 병렬로 실행했을 때 환경을 프로비저닝하는 시간을 포함하여 완료하는 데 6분이 걸렸습니다. 병렬 실행은 순차 실행 시간의 17.1%가 걸렸습니다. 실제 수치는 프로젝트에 따라 다를 수 있습니다.

추가 정보
이 새로운 기능은 모든 테스트 프레임워크와 호환됩니다. 설명서에는 Django, Elixir, Go, Java(Maven), Javascript(Jest), Kotlin, PHPUnit, Pytest, Ruby(Cucumber) 및 Ruby(RSpec)용 예제가 포함되어 있습니다.

공백으로 구분된 목록을 허용하지 않는 테스트 프레임워크의 경우 codebuild-tests-run CLI는 CODEBUILD_CURRENT_SHARD_FILES 환경 변수를 통해 유연한 대안을 제공합니다. 이 변수에는 현재 빌드 샤드의 테스트 파일 경로를 줄바꿈으로 구분한 목록이 포함됩니다. 이를 사용하여 다양한 테스트 프레임워크 요구 사항에 맞게 조정하고 테스트 파일 이름의 형식을 지정할 수 있습니다.

샤딩 스크립트를 직접 작성하고 각 빌드에서 자동으로 설정되는 CODEBUILD_BATCH_BUILD_IDENTIFIER 환경 변수를 사용하여 환경 간에 테스트를 분할하는 방법을 추가로 사용자 지정할 수 있습니다. 이 기법을 사용하여 프레임워크별 병렬화 또는 최적화를 구현할 수 있습니다.

요금 및 가용성
병렬 테스트 실행을 통해 이제 이전보다 훨씬 짧은 시간에 테스트 스위트를 완료하여 개발 주기를 가속화하고 팀의 생산성을 개선할 수 있습니다. 이 게시물에서 예시를 위해 생성한 데모 프로젝트는 순차 빌드 시간의 18.7%가 소요되었습니다.

CodeBuild에서 제공하는 세 가지 컴퓨팅 모드(온디맨드, 예약 용량, AWS Lambda 컴퓨팅) 모두에서 병렬 테스트 실행을 사용할 수 있습니다.

이 기능은 현재 CodeBuild가 제공되는 모든 AWS 리전에서 사용할 수 있으며, 사용된 컴퓨팅 리소스에 대한 표준 CodeBuild 요금 외에는 추가 비용이 들지 않습니다.

오늘 CodeBuild에서 병렬 테스트 실행을 시도해 보시기 바랍니다. 자세한 내용을 알아보고 테스트 병렬화를 시작하려면 AWS CodeBuild 설명서를 참조하세요.

— seb

PS: 데모 애플리케이션 및 테스트 스위트를 생성할 때 사용한 프롬프트는 다음과 같습니다. “I’m writing a blog post to announce codebuild parallel testing. Write a very simple python app that has hundreds of tests, each test in a separate test file. Each test takes one second to complete.”


뉴스 블로그를 어떻게 생각하시나요? 이 1분짜리 설문조사에 참여해 주세요!

(이 설문조사는 외부 기업에서 호스트합니다. AWS는 AWS 개인정보 처리방침에 설명한 대로 사용자 정보를 처리합니다. AWS는 이 설문 조사를 통해 수집된 데이터를 소유하며 수집된 정보를 설문 응답자와 공유하지 않습니다)