Cloud Build 및 Terraform을 사용하여 Cloud Functions를 테스트하는 시스템

이 가이드는 Cloud Functions로 빌드된 앱의 엔드 투 엔드 테스트를 자동화하는 방법을 설명합니다. Cloud Build는 테스트 파이프라인을 실행하고, HashiCorp Terraform은 테스트를 실행하는 데 필요한 Google Cloud 리소스를 설정하고 분리합니다. Cloud Build 트리거는 각 코드 커밋 후 파이프라인을 시작합니다.

테스트 가능성은 앱을 디자인하고 아키텍처 선택을 평가할 때의 주요 고려 사항입니다. 앱이 예상대로 작동하는지 확인하려면 포괄적인 테스트 세트(자동 단위, 통합, 엔드 투 엔드 시스템 테스트 포함)를 작성하고 정기적으로 실행해야 합니다. 다양한 Cloud Functions 시나리오에 대해 각 테스트 범주에 접근하는 방법에 대한 자세한 내용은 테스트 권장사항 가이드를 참조하세요.

단위 테스트 생성 및 실행은 일반적으로 간단합니다. 이러한 테스트가 격리되어 있으며 실행 환경과 독립적이기 때문입니다. 하지만 통합 및 시스템 테스트는 특히 클라우드 환경에서 더 복잡합니다. 엔드 투 엔드 시스템 테스트의 필요성은 특히 Cloud Functions와 같은 서버리스 기술을 사용하는 앱과 관련이 있습니다. 이러한 앱은 종종 이벤트 중심적이고 느슨하게 연결되며 독립적으로 배포할 수 있습니다. 함수가 Google Cloud 실행 환경 내에서 이벤트에 올바르게 응답하는지 검증하려면 포괄적인 엔드 투 엔드 테스트가 필요합니다.

아키텍처

다음 다이어그램은 이 가이드에서 사용하는 구성요소를 보여줍니다.

빌드 및 테스트 프로젝트의 아키텍처 다이어그램

이 아키텍처에는 다음과 같은 구성요소가 있습니다.

  • Cloud Build 파이프라인을 호스팅하고 실행하는 build 프로젝트입니다.
  • 테스트 중인 샘플 앱의 Google Cloud 리소스를 호스팅하는 test 프로젝트입니다.
    • 서버리스 웹 성능 모니터링 가이드에 설명된 앱이 샘플 앱으로 사용됩니다.
    • 샘플 앱의 Google Cloud 리소스는 각 빌드 반복마다 생성되고 소멸됩니다. Firestore 데이터베이스는 예외입니다. 한 번 생성되어 모든 후속 빌드에서 재사용됩니다.

목표

  • Cloud Build 파이프라인을 생성하여 Cloud Functions로 빌드된 샘플 앱의 단위 및 엔드 투 엔드 테스트를 실행합니다.
  • 빌드 내에서 Terraform을 사용하여 앱에 필요한 Google Cloud 리소스를 설정하고 폐기합니다.
  • 전용 Google Cloud 테스트 프로젝트를 사용하여 테스트 환경을 격리합니다.
  • Cloud Source Repositories에서 Git 저장소를 생성하고, Cloud Build 트리거를 추가하여 커밋 후에 엔드 투 엔드 빌드를 실행합니다.

비용

이 가이드에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

이 가이드를 마치면 만든 리소스를 삭제하여 비용이 계속 청구되지 않게 할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

  1. Cloud 프로젝트를 선택하거나 만듭니다. 샘플 앱을 호스팅하는 test 프로젝트입니다.

    프로젝트 선택기 페이지로 이동

  2. test 프로젝트의 GCP 프로젝트 ID를 기록합니다. 환경 설정과 관련한 다음 섹션에서 이 ID가 필요합니다.
  3. 프로젝트에 Cloud Build, Cloud Functions, Cloud Source Repositories API를 사용 설정합니다.

    API를 사용 설정합니다.

  4. Cloud Console에서 Firestore 페이지로 이동합니다.
  5. Firestore 페이지로 이동
  6. Firestore 데이터베이스를 만듭니다.

    Firestore 데이터베이스 생성 방법 알아보기

  7. 다른 Google Cloud 프로젝트를 선택하거나 만듭니다. Cloud Build 파이프라인을 호스팅하는 build 프로젝트입니다.
  8. 리소스 관리 페이지로 이동
  9. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

    결제 사용 설정 방법 알아보기

환경 설정

이 가이드에서는 Cloud Shell에서 명령어를 실행합니다. Cloud Shell은 gcloud 명령줄 도구가 포함되고 Cloud SDK가 사전 설치된 셀 환경으로, 현재 프로젝트의 값이 이미 설정되어 있습니다. Cloud Shell은 초기화하는 데 몇 분 정도 걸릴 수 있습니다.

  1. build 프로젝트의 Cloud Console에서 Cloud Shell을 엽니다.

    Cloud Shell 열기

  2. 앞에서 복사한 test Google Cloud 프로젝트 ID에 대해 변수를 설정합니다.

    export TEST_PROJECT=your-test-project-id
    

    다음을 바꿉니다.

    • your-test-project-id: test Google Cloud 프로젝트의 ID입니다.
  3. 현재 build Google Cloud 프로젝트의 프로젝트 ID 및 프로젝트 번호를 변수로 설정합니다.

    export BUILD_PROJECT=$(gcloud config get-value core/project)
    export BUILD_PROJECT_NUM=$(gcloud projects list) \
        --filter="$BUILD_PROJECT" --format="value(PROJECT_NUMBER)"
    
  4. 배포 리전의 변수를 설정합니다.

    export REGION=us-central1
    

    이 가이드에서는 us-central1 리전을 사용하지만 이 리전을 any region where Cloud Functions를 사용할 수 있는 리전으로 변경할 수 있습니다.

  5. 이 가이드에서 사용하는 샘플 앱의 코드가 포함된 저장소를 클론합니다.

    git clone \
        https://github.com/GoogleCloudPlatform/solutions-serverless-web-monitoring.git
    
  6. 프로젝트 디렉터리로 이동합니다.

    cd solutions-serverless-web-monitoring
    

Terraform으로 테스트 인프라 만들기

이 가이드에서는 Terraform을 사용하여 테스트 프로젝트 내에서 Google Cloud 리소스를 자동으로 생성하고 폐기합니다. 각 빌드에 독립적인 리소스를 만들면 테스트를 서로 격리할 수 있습니다. 테스트를 격리하면 빌드가 동시에 수행될 수 있으며, 특정 리소스에 테스트 어설션을 만들 수 있습니다. 각 빌드가 끝날 때 리소스를 폐기하면 비용을 최소화하는 데 도움이 됩니다.

이 가이드에서는 서버리스 웹 모니터링 가이드에 설명된 앱을 배포합니다. 이 앱은 일련의 Cloud Functions, Cloud Storage 버킷, Cloud Pub/Sub 리소스, Firestore 데이터베이스로 구성됩니다. Terraform 구성은 이러한 리소스를 생성하는 데 필요한 단계를 정의합니다. Firestore 데이터베이스는 Terraform에서 배포하지 않습니다. 데이터베이스는 한 번 생성되면 모든 테스트에서 재사용됩니다.

Terraform 구성 파일 main.tf의 다음 코드 샘플은 trace Cloud 함수를 배포하는 데 필요한 단계를 보여줍니다. 전체 구성은 전체 파일을 참조하세요.

data "archive_file" "local_tracer_source" {
  type        = "zip"
  source_dir  = "./functions/tracer"
  output_path = "${var.local_output_path}/tracer.zip"
}

resource "google_storage_bucket_object" "gcs_tracer_source" {
  name   = "tracer.zip"
  bucket = "${google_storage_bucket.bucket_source_archives.name}"
  source = "${data.archive_file.local_tracer_source.output_path}"
}

resource "google_cloudfunctions_function" "function_tracer" {
  name = "tracer-${var.suffix}"
  project = "${var.project_id}"
  region = "${var.region}"
  available_memory_mb = "1024"
  entry_point = "trace"
  runtime = "nodejs8"
  trigger_http = "true"
  source_archive_bucket = "${google_storage_bucket.bucket_source_archives.name}"
  source_archive_object = "${google_storage_bucket_object.gcs_tracer_source.name}"
  environment_variables = {
    BUCKET_METRICS = "${google_storage_bucket.bucket_metrics.name}"
    ALLOWED_HOSTS = "${var.allowed_hosts}"
  }
}

// prevent unauthenticated invocations
resource "google_cloudfunctions_function_iam_binding" "tracer_disallow_unauthenticated" {
  project = "${var.project_id}"
  region = "${var.region}"
  cloud_function = "${google_cloudfunctions_function.function_tracer.name}"
  role = "roles/cloudfunctions.invoker"
  members = [
  ]
  depends_on = [
    google_cloudfunctions_function.function_tracer
  ]
}

이 단계에서는 Terraform 구성을 실행하여 테스트 리소스를 배포합니다. 이후 단계에서는 Cloud Build가 리소스를 자동으로 배포합니다.

  1. Cloud Shell에서 Terraform을 초기화합니다.

    docker run -v $(pwd):/app -w /app hashicorp/terraform:0.12.0 init
    

    공개 Terraform Docker 이미지를 사용합니다. Docker는 Cloud Shell에 이미 설치되어 있습니다. Docker 컨테이너가 Terraform 구성 파일을 읽을 수 있도록 현재 작업 디렉터리가 볼륨으로 마운트됩니다.

  2. Terraform apply 명령어를 사용하여 리소스를 생성합니다.

    docker run -v $(pwd):/app -w /app hashicorp/terraform:0.12.0 apply \
        --auto-approve \
        -var "project_id=$TEST_PROJECT" \
        -var "region=$REGION" \
        -var "suffix=$TEST_PROJECT"
    

    이 명령어에는 테스트 리소스를 생성할 Google Cloud 프로젝트 및 리전을 지정하는 변수가 포함됩니다. 또한 이 단계에서 명명된 리소스를 만드는 데 사용되는 서픽스도 포함됩니다. 이후 단계에서는 Cloud Build에서 자동으로 적합한 서픽스를 제공합니다.

    작업을 완료하는 데 몇 분이 걸립니다.

  3. test 프로젝트에서 리소스가 생성되었는지 확인합니다.

    gcloud functions list --project $TEST_PROJECT
    

    결과에는 이름이 이전에 제공된 서픽스로 끝나는 3개의 Cloud Functions가 표시됩니다.

엔드 투 엔드 테스트 실행

이 섹션에서는 이전 섹션에서 배포한 테스트 인프라에 대해 엔드 투 엔드 테스트를 실행합니다.

다음 코드 스니펫은 테스트를 보여줍니다. 테스트는 성공 및 실패 시나리오를 모두 검증합니다. 테스트 파이프라인을 요약하면 다음과 같습니다.

  • 먼저 테스트에서 trace 함수를 호출합니다. 이 호출은 다른 함수를 트리거하는 앱을 통해 이벤트 흐름을 시작합니다.
  • 그런 다음 테스트에서 각 함수의 동작을 확인하고, 객체가 Cloud Storage에 작성되고 결과가 Firestore에 유지되며 장애 발생 시 Pub/Sub 알림이 생성되는지 확인합니다.
def test_e2e_pass():
  run_pipeline('http://www.example.com/', True)

def test_e2e_fail():
  run_pipeline('https://cloud.google.com/docs/tutorials', False)

def run_pipeline(url, should_pass):
  """Triggers the web analysis pipeline and verifies outputs of each stage.

  Args:
    url (str): The page to analyze.
    should_pass (bool): Whether the page should load within the threshold time.
  """
  trace_response = call_tracer(url)
  filename = assert_tracer_response(trace_response)
  assert_gcs_objects(filename)
  assert_firestore_doc(filename, should_pass)
  assert_pubsub_message(should_pass)

  # clean up
  delete_gcs_objects(filename)
  delete_firestore_doc(filename)

엔드 투 엔드 테스트를 실행하려면 다음 단계를 완료하세요.

  1. Cloud Shell에서 새 virtualenv 환경을 만듭니다. virtualenv 유틸리티는 Cloud Shell에 이미 설치되어 있습니다.

    virtualenv venv
    
  2. virtualenv 환경을 활성화합니다.

    source venv/bin/activate
    
  3. 필수 Python 라이브러리를 설치합니다.

    pip install -r requirements.txt
    
  4. 엔드 투 엔드 테스트를 실행합니다.

    python -m pytest e2e/ --tfstate terraform.tfstate
    

    이전 섹션에서 생성된 테스트 리소스에 대한 세부정보가 포함된 Terraform 상태 파일을 전달합니다.

    테스트를 완료하는 데 몇 분이 걸릴 수 있습니다. 두 가지 테스트를 통과했다는 메시지가 표시됩니다. 경고는 무시해도 됩니다.

  5. Terraform destroy 명령어를 사용하여 테스트 리소스를 분리합니다.

    docker run -v $(pwd):/app -w /app hashicorp/terraform:0.12.0 destroy \
        --auto-approve \
        -var "project_id=$TEST_PROJECT" \
        -var "region=$REGION" \
        -var "suffix=$TEST_PROJECT"
    
  6. 리소스가 폐기되었는지 확인합니다.

    gcloud functions list --project $TEST_PROJECT
    

    앞에서 제공된 서픽스로 끝나는 이름을 가진 Cloud Functions가 더 이상 없습니다.

Cloud Build 파이프라인 제출

이 섹션에서는 Cloud Build를 사용하여 테스트 파이프라인을 자동화합니다.

Cloud Build 권한 설정

Cloud Build 서비스 계정을 사용하여 Cloud Build를 실행합니다. 빌드에서 실행된 시스템 테스트는 Cloud Functions, Cloud Storage 버킷, Pub/Sub 리소스, Firestore 문서를 생성하고 상호 작용합니다. 이러한 작업을 수행하려면 Cloud Build에 다음이 필요합니다.

  • 테스트 프로젝트에서 적절한 ID 및 액세스 관리(IAM) 역할
  • Cloud Functions 런타임 서비스 계정으로 작동하는 기능. 기본적으로 Cloud Functions는 App Engine 서비스 계정(your-test-project-id@appspot.gserviceaccount.com)을 런타임 서비스 계정으로 사용합니다. 여기서 your-test-project-idtest Google Cloud 프로젝트의 이름입니다.

이 절차에서는 적절한 역할을 추가한 다음 Cloud Build 서비스 계정을 추가합니다.

  1. Cloud Shell에서 적합한 IAM 역할을 기본 Cloud Build 서비스 계정에 추가합니다.

    for role in cloudfunctions.developer pubsub.editor storage.admin datastore.user; do \
        gcloud projects add-iam-policy-binding $TEST_PROJECT \
        --member="serviceAccount:$BUILD_PROJECT_NUM@cloudbuild.gserviceaccount.com" \
        --role="roles/$role"; \
        done
    
  2. Cloud Build 서비스 계정을 테스트 프로젝트 내의 App Engine 서비스 계정의 serviceAccountUser로 추가합니다.

    gcloud iam service-accounts add-iam-policy-binding \
        $TEST_PROJECT@appspot.gserviceaccount.com \
        --member="serviceAccount:$BUILD_PROJECT_NUM@cloudbuild.gserviceaccount.com" \
        --role=roles/iam.serviceAccountUser \
        --project $TEST_PROJECT
    

수동 빌드 제출

빌드는 다음 네 가지 논리적 작업을 수행합니다.

  • 단위 테스트 실행
  • 샘플 앱 배포
  • 엔드 투 엔드 테스트 실행
  • 샘플 앱 폐기

cloudbuild.yaml 파일에서 다음 코드 스니펫을 검토합니다. 이 스니펫은 Terraform을 사용하여 샘플 앱을 배포하고 엔드 투 엔드 테스트를 실행하는 개별 Cloud Build 단계를 보여줍니다.

# setup Terraform using public terraform Docker image
- id: terraform-init
  name: hashicorp/terraform:0.12.0
  args: ['init']

# deploy the required GCP resources
- id: terraform-apply
  name: hashicorp/terraform:0.12.0
  args: ['apply', '-auto-approve']
  env:
    - 'TF_VAR_project_id=$_TEST_PROJECT_ID'
    - 'TF_VAR_region=$_REGION'
    - 'TF_VAR_suffix=$BUILD_ID'

# run end-to-end tests to verify live interactions
- id: end-to-end-tests
  name: 'python:3.7-slim'
  entrypoint: /bin/sh
  args:
    - -c
    - 'pip install -r requirements.txt && python -m pytest e2e --tfstate terraform.tfstate'

Cloud Build에 수동 빌드를 제출하고 엔드 투 엔드 테스트를 실행하려면 다음을 수행합니다.

  • Cloud Shell에서 다음을 입력합니다.

    gcloud builds submit --config cloudbuild.yaml \
        --substitutions=_REGION=$REGION,_TEST_PROJECT_ID=$TEST_PROJECT
    

    빌드를 실행하는 데 몇 분이 걸립니다. 다음과 같은 빌드 단계가 발생합니다.

    • Cloud Build는 대체를 사용하여 생성한 테스트 리소스의 Google Cloud 프로젝트 및 리전을 지정하는 변수를 제공합니다.

    • Cloud Build는 build Google Cloud 프로젝트에서 빌드를 실행합니다. 테스트 리소스는 별도의 test 프로젝트에서 생성됩니다.

    빌드 로그가 Cloud Shell로 스트리밍되므로 빌드 진행 상황을 확인할 수 있습니다. 빌드가 완료되면 로그 스트림이 종료됩니다. 최종 terraform-destroy 빌드 단계가 성공했으며 빌드가 완료되었음을 나타내는 메시지가 표시됩니다.

테스트 실행 자동화

지속적 통합(CI)의 핵심 원칙은 포괄적인 자동화된 테스트를 정기적으로 실행하는 것입니다. 일반적으로 빌드 테스트 파이프라인은 공유 코드 저장소에 대한 커밋마다 실행됩니다. 이 설정은 공유 저장소에 대한 각 커밋이 테스트되고 유효성이 확인되어 팀이 문제를 조기에 감지할 수 있도록 합니다.

다음 섹션에서는 아래의 작업을 수행합니다.

  • Cloud Source Repositories에서 Git 저장소를 만듭니다.
  • 모든 커밋마다 엔드 투 엔드 빌드를 실행하려면 Cloud Build 트리거를 추가합니다.
  • 코드를 저장소로 푸시하여 빌드를 트리거합니다.

Cloud Source Repository 및 Cloud Build 트리거 생성

  1. Cloud Shell에서 새로운 Cloud Source Repository를 생성합니다.

    gcloud source repos create serverless-web-monitoring
    
  2. Cloud Console에서 Cloud Build 트리거 페이지를 엽니다.

    트리거 페이지로 이동

  3. 트리거 만들기를 클릭합니다.

    트리거 만들기 페이지가 열립니다.

  4. 다음 옵션을 입력합니다.

    • 이름 필드에 end-to-end-tests를 입력합니다.
    • 이벤트에서 분기로 푸시를 선택합니다.
    • 소스에서 severless-web-monitoring저장소로 선택하고 ^master$분기로 선택합니다.
    • 빌드 구성에서 Cloud Build 구성 파일을 선택합니다.
    • Cloud Build 구성 파일 위치 필드에 cloudbuild.yaml을 입력합니다.
    • 테스트 리소스가 생성될 Google Cloud 리전을 지정하기 위해 변수 대체를 추가하려면 변수 추가를 클릭합니다.

      • 변수: _REGION
      • : your-test-region

        다음을 바꿉니다.

        • your-test-region: Cloud Shell에서 $REGION 변수의 값입니다.
    • 테스트 리소스를 호스트할 프로젝트의 ID를 지정하기 위해 다른 변수 대체를 추가하려면 변수 추가를 클릭합니다.

      • 변수: _TEST_PROJECT_ID
      • : your-test-project

        다음을 바꿉니다.

        • your-test-project: Cloud Shell에서 $TEST_PROJECT 변수의 값입니다.
  5. 만들기를 클릭하여 빌드 트리거를 저장합니다.

빌드 시작

  1. Cloud Shell에서 git config에 리포지토리를 새로운 원격으로 추가합니다.

    git remote add csr \
        https://source.developers.google.com/p/$BUILD_PROJECT/r/serverless-web-monitoring
    
  2. 빌드를 트리거하려면 코드를 저장소로 푸시합니다.

    git push csr master
    
  3. 가장 최근 빌드를 나열합니다.

    gcloud builds list --limit 3
    

    결과에 빌드가 WORKING 상태로 표시되어 빌드가 예상대로 트리거되었음을 나타냅니다.

  4. 다음 단계를 위해 WORKING 빌드의 ID를 복사합니다.

  5. 빌드 로그를 Cloud Console에 스트리밍합니다.

    gcloud builds log --stream build-id
    

    다음을 바꿉니다.

    • build-id: 이전 단계에서 복사한 WORKING 빌드의 ID입니다.

    빌드가 완료되면 로그 스트림이 종료됩니다. 최종 terraform-destroy 빌드 단계가 성공했으며 빌드가 완료되었음을 나타내는 메시지가 표시됩니다.

삭제

이 가이드에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요.

프로젝트 삭제

  1. Cloud Console에서 리소스 관리 페이지로 이동합니다.

    리소스 관리로 이동

  2. 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
  3. 대화상자에서 프로젝트 ID를 입력한 후 종료를 클릭하여 프로젝트를 삭제합니다.

다음 단계