GPU 측정항목을 사용하여 vLLM 모델 서빙 자동 확장

이 튜토리얼에서는 vLLM으로 LLM을 제공하는 Cloud Run 서비스를 Cloud Run 외부 측정항목 자동 확장 (CREMA)을 사용하여 커스텀 GPU 측정항목을 기반으로 자동 확장하는 방법을 설명합니다.

Cloud Run은 기본적으로 CPU 사용률 및 동시 실행을 사용하여 자동 확장하지만 GPU 집약적인 추론 워크로드에는 실행 중인 요청 수 또는 KV 캐시 사용률과 같은 큐 측정항목을 기반으로 자동 확장이 필요한 경우가 많습니다. CREMA는 Kubernetes 기반 이벤트 기반 자동 확장 (KEDA)을 Cloud Run과 통합하여 Prometheus 측정항목에 따라 동적 확장을 지원합니다. vLLM은 Prometheus 측정항목을 노출하고 Cloud Monitoring으로 전송합니다.

목표

이 튜토리얼에서는 다음 단계를 진행합니다.

비용

이 문서에서는 비용이 청구될 수 있는 구성요소를 사용합니다 Google Cloud.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요.

신규 Google Cloud 사용자는 무료 체험판을 사용할 수 있습니다.

시작하기 전에

  1. 계정에 로그인합니다. Google Cloud 를 처음 사용하는 경우 계정을 만들고 Google 제품의 실제 성능을 평가해 보세요. Google Cloud신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $300의 무료 크레딧이 제공됩니다.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  5. Verify that billing is enabled for your Google Cloud project.

  6. Cloud Run, Parameter Manager, Artifact Registry, Cloud Build, Secret Manager, Cloud Monitoring API를 사용 설정합니다.

    API 사용 설정에 필요한 역할

    API를 사용 설정하려면 serviceusage.services.enable 권한이 필요합니다. 프로젝트를 만든 경우 소유자 역할 (roles/owner)을 통해 이 권한을 이미 보유하고 있을 가능성이 높습니다. 그렇지 않은 경우 서비스 사용량 관리자 역할 (roles/serviceusage.serviceUsageAdmin)을 통해 이 권한을 얻을 수 있습니다. 역할을 부여하는 방법을 알아보세요.

    API 사용 설정

  7. gcloud CLI를 설치하고 초기화합니다.
  8. 이 튜토리얼 전체에서 사용할 환경 변수를 설정합니다.
    export PROJECT_ID=PROJECT_ID
    export REGION=us-central1
    export VLLM_SERVICE_NAME=vllm-service
    export MODEL_NAME=gemma-2-2b-it
    export REPO_NAME=vllm-repo
    export BUCKET_NAME=my-vllm-models-${PROJECT_ID}
    export CREMA_SERVICE_NAME=crema-service
    PROJECT_ID를 Google Cloud 프로젝트 ID로 바꿉니다.
  9. 프로젝트 구성을 설정합니다.
    gcloud config set project $PROJECT_ID
  10. 아직 계정이 없다면 Hugging Face에서 계정을 만듭니다. 그런 다음 읽기 토큰을 Hugging Face 사이트에서 만듭니다. Hugging Face는 토큰을 한 번만 표시합니다. 안전한 위치에 저장하세요. 다시 볼 수 없습니다.
  11. Hugging Face에서 gemma-2-2b-it 모델 페이지로 이동하여 모델의 계약 조건을 수락합니다.

필요한 역할

튜토리얼을 완료하는 데 필요한 권한을 얻으려면 관리자에게 프로젝트에 대한 다음 IAM 역할을 부여해 달라고 요청하세요.

역할 부여에 대한 자세한 내용은 프로젝트, 폴더, 조직에 대한 액세스 관리를 참조하세요.

커스텀 역할이나 다른 사전 정의된 역할을 통해 필요한 권한을 얻을 수도 있습니다.

모델 가중치를 Cloud Storage에 다운로드하고 업로드

Hugging Face에서 모델 가중치를 다운로드하고 Cloud Storage 버킷으로 전송하여 모델 서빙에 사용할 수 있도록 합니다.

  1. Hugging Face CLI를 설치합니다.

    pip install -U "huggingface_hub[cli]"
    
  2. Hugging Face CLI를 사용하여 모델 가중치를 로컬로 다운로드합니다.

    export HF_TOKEN="HF_TOKEN"
    export LOCAL_DIR="/tmp/$MODEL_NAME"
    HF_HOME=/tmp/huggingface python -m huggingface_hub.cli.hf download google/$MODEL_NAME --token $HF_TOKEN --local-dir=$LOCAL_DIR
    

    HF_TOKEN을 Hugging Face 사용자 액세스 토큰으로 바꿉니다. 토큰은 hf_로 시작하고 그 뒤에 35개의 임의 영숫자 문자 (예: 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)가 와야 합니다.

  3. Cloud Storage 버킷을 만들고 다운로드한 가중치를 복사합니다.

    gcloud storage buckets create gs://$BUCKET_NAME \
        --project=$PROJECT_ID \
        --location=$REGION \
        --uniform-bucket-level-access
    
    gcloud storage cp -r $LOCAL_DIR gs://$BUCKET_NAME/
    

vLLM 컨테이너 이미지를 Artifact Registry로 푸시

모델 서빙 컨테이너 이미지를 가져와서 Artifact Registry의 저장소로 푸시합니다.

  1. Artifact Registry에서 Docker 저장소를 만듭니다.

    gcloud artifacts repositories create $REPO_NAME \
        --repository-format=docker \
        --location=$REGION \
        --description="vLLM Docker Images"
    
  2. 레지스트리로 로컬 Docker 데몬을 인증합니다.

    gcloud auth configure-docker ${REGION}-docker.pkg.dev
    
  3. vLLM 이미지를 가져와서 태그를 지정하고 Artifact Registry로 푸시합니다.

    docker pull docker.io/vllm/vllm-openai:latest
    docker tag docker.io/vllm/vllm-openai:latest ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/vllm-openai:latest
    docker push ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/vllm-openai:latest
    

CREMA 자동 확장 처리 서비스 배포

자동 확장 처리 서비스를 배포하기 전에 CREMA의 서비스 계정 역할 및 매개변수 매니페스트를 구성합니다.

커스텀 서비스 계정 만들기

프로비저닝된 리소스를 사용하는 데 필요한 최소 권한으로 커스텀 서비스 계정을 만듭니다. 이 서비스 계정은 자동 확장 처리의 ID 역할을 합니다. 다음 명령어를 실행하여 CREMA 서비스 계정을 만듭니다.

export CREMA_SA="crema-autoscaler@${PROJECT_ID}.iam.gserviceaccount.com"

gcloud iam service-accounts create crema-autoscaler \
    --description="Service account for Cloud Run CREMA to read metrics and scale workloads" \
    --display-name="CREMA Autoscaler System"

커스텀 서비스 계정에 추가 권한 부여

서비스를 확장하려면 커스텀 서비스 계정에 다음 권한을 부여합니다.

  1. CREMA 서비스 계정에 Parameter Manager에서 읽을 수 있는 권한을 부여합니다.

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/parametermanager.parameterViewer"
    
  2. CREMA 서비스 계정에 서비스를 확장할 수 있는 권한을 부여합니다.

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/run.developer"
    
  3. CREMA 서비스 계정에 서비스 계정 사용자 역할을 부여합니다.

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/iam.serviceAccountUser"
    
  4. CREMA 서비스 계정에 측정항목을 볼 수 있는 권한을 부여합니다.

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/monitoring.viewer"
    

CREMA 구성 만들기 및 등록

CREMA 구성 매니페스트에서 확장 임곗값과 규칙을 정의하고 Parameter Manager에 등록합니다.

  1. 다음 구성을 my-crema-config.yaml로 저장합니다. 이 구성은 실행 중인 요청 수 (vllm:num_requests_running)가 2를 초과할 때 확장을 트리거합니다.

    apiVersion: crema/v1
    kind: CremaConfig
    spec:
      pollingInterval: 15
      triggerAuthentications:
        - metadata:
            name: adc-trigger-auth
          spec:
            podIdentity:
              provider: gcp
      scaledObjects:
        - spec:
            scaleTargetRef:
              name: projects/PROJECT_ID/locations/us-central1/services/vllm-service
            minReplicaCount: 1
            maxReplicaCount: 5
            triggers:
              - type: prometheus
                authenticationRef:
                  name: adc-trigger-auth
                metadata:
                  serverAddress: https://monitoring.googleapis.com/v1/projects/PROJECT_ID/location/global/prometheus
                  metric: vllm:num_requests_running
                  query: sum(vllm:num_requests_running)
                  threshold: '2'
    
  2. Parameter Manager에 구성 파일을 등록합니다.

    gcloud parametermanager parameters create crema-config \
        --location=global \
        --parameter-format=YAML
    
    gcloud parametermanager parameters versions create 1 \
        --location=global \
        --parameter=crema-config \
        --payload-data-from-file=my-crema-config.yaml
    

CREMA 서비스 배포

CREMA 이미지를 Cloud Run의 내부 백그라운드 서비스로 배포합니다.

gcloud run deploy $CREMA_SERVICE_NAME \
    --image=us-central1-docker.pkg.dev/cloud-run-oss-images/crema-v1/autoscaler:1.0 \
    --region=$REGION \
    --service-account="$CREMA_SA" \
    --no-allow-unauthenticated \
    --no-cpu-throttling \
    --cpu=1 \
    --memory=1Gi \
    --min-instances=1 \
    --max-instances=1 \
    --ingress=internal \
    --base-image=us-central1-docker.pkg.dev/serverless-runtimes/google-24/runtimes/java25 \
    --set-env-vars="CREMA_CONFIG=projects/$PROJECT_ID/locations/global/parameters/crema-config/versions/1,OUTPUT_SCALER_METRICS=True"

vLLM 서비스 권한 구성

기본 Compute Engine 서비스 계정에 측정항목을 내보내고 Cloud Storage에서 모델 가중치를 읽을 수 있는 권한을 부여합니다.

  1. 프로젝트 번호를 검색합니다.

    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
    
  2. 서비스 계정에 측정항목을 작성할 수 있는 권한을 부여합니다.

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
        --role="roles/monitoring.metricWriter"
    
  3. 서비스 계정에 Cloud Storage에서 모델 가중치를 읽을 수 있는 권한을 부여합니다.

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
        --role="roles/storage.objectViewer"
    

OpenTelemetry 사이드카를 사용하여 vLLM 서비스 배포

Cloud Storage에서 마운트된 모델 가중치를 사용하여 기본 vLLM 서빙 컨테이너를 Cloud Run에 배포합니다. Cloud Run에서 사이드카를 사용하여 멀티 컨테이너 서비스를 배포하려면 선언적 YAML 서비스 사양이 필요하므로 OpenTelemetry 사이드카 수집기와 함께 기본 vLLM 엔진을 구성하여 vLLM 측정항목을 스크래핑하고 내보냅니다.

  1. 다음 멀티 컨테이너 배포 사양을 vllm-service.yaml로 저장합니다.

    apiVersion: serving.knative.dev/v1
    kind: Service
    metadata:
      name: vllm-service
      labels:
        cloud.googleapis.com/location: us-central1
      annotations:
        run.googleapis.com/scalingMode: manual
        run.googleapis.com/manualInstanceCount: "1"
    spec:
      template:
        metadata:
          annotations:
            run.googleapis.com/execution-environment: gen2
            run.googleapis.com/cpu-throttling: "false"
            run.googleapis.com/gpu-zonal-redundancy-disabled: "true"
            autoscaling.knative.dev/minScale: "1"
        spec:
          containerConcurrency: 80
          nodeSelector:
            run.googleapis.com/accelerator: nvidia-l4
          volumes:
            - name: gcs-volume
              csi:
                driver: gcsfuse.run.googleapis.com
                volumeAttributes:
                  bucketName: my-vllm-models-PROJECT_ID
          containers:
            # Primary container: vLLM serving engine
            - name: vllm-container
              image: us-central1-docker.pkg.dev/PROJECT_ID/vllm-repo/vllm-openai:latest
              ports:
                - containerPort: 8080
              resources:
                limits:
                  cpu: "4"
                  memory: 16Gi
                  nvidia.com/gpu: "1"
              args:
                - "--model"
                - "/gcs/gemma-2-2b-it"
                - "--port"
                - "8080"
                - "--max-model-len"
                - "2048"
                - "--chat-template"
                - "{% for msg in messages %}{{ msg['content'] }}{% endfor %}"
              volumeMounts:
                - name: gcs-volume
                  mountPath: /gcs
              startupProbe:
                httpGet:
                  path: /health
                  port: 8080
                periodSeconds: 10
                failureThreshold: 24
    
            # Sidecar container: OpenTelemetry Collector
            - name: otel-collector
              image: otel/opentelemetry-collector-contrib:latest
              resources:
                limits:
                  cpu: "1"
                  memory: 1Gi
              args:
                - |
                  --config=yaml:
                  receivers:
                    prometheus:
                      config:
                        scrape_configs:
                          - job_name: 'vllm'
                            scrape_interval: 10s
                            metrics_path: '/metrics'
                            static_configs:
                              - targets: ['localhost:8080']
                  processors:
                    resourcedetection:
                      detectors: [gcp]
                      timeout: 2s
                    transform:
                      metric_statements:
                        - context: datapoint
                          statements:
                            - set(attributes["exported_location"], attributes["location"])
                            - delete_key(attributes, "location")
                            - set(attributes["exported_cluster"], attributes["cluster"])
                            - delete_key(attributes, "cluster")
                            - set(attributes["exported_namespace"], attributes["namespace"])
                            - delete_key(attributes, "namespace")
                            - set(attributes["exported_job"], attributes["job"])
                            - delete_key(attributes, "job")
                            - set(attributes["exported_instance"], attributes["instance"])
                            - delete_key(attributes, "instance")
                  exporters:
                    googlemanagedprometheus:
                  service:
                    pipelines:
                      metrics:
                        receivers: [prometheus]
                        processors: [resourcedetection, transform]
                        exporters: [googlemanagedprometheus]
    
  2. 기존 서비스 구성을 멀티 컨테이너 매니페스트로 바꿉니다.

    gcloud run services replace vllm-service.yaml
    

CREMA 서비스 로그 확인

  1. 콘솔 Google Cloud 에서 Cloud Run 페이지로 이동합니다.
  2. crema-service를 선택합니다.
  3. 로그 탭을 클릭하고 측정항목 폴링 주기가 활성 상태인지 확인합니다.

    [INFO] [METRIC-PROVIDER] Starting metric collection cycle
    [INFO] [METRIC-PROVIDER] Successfully fetched scaled object metrics ...
    [INFO] [METRIC-PROVIDER] Sending scale request ...
    [INFO] [SCALER] Received ScaleRequest ...
    [INFO] [SCALER] Current instances ...
    [INFO] [SCALER] Recommended instances ...
    

부하 테스트 실행

자동 확장을 테스트하려면 부하 테스트 스크립트를 실행하여 vLLM 서비스에 동시 요청을 보냅니다.

  1. 작업 디렉터리에 load-test.sh라는 파일을 만들고 다음 코드를 추가합니다.

    #!/bin/bash
    
    export SERVICE_URL=$(gcloud run services describe $VLLM_SERVICE_NAME --region $REGION --format='value(status.url)')
    
    echo "Launching 5 parallel heavy requests to trigger autoscaling..."
    
    for i in {1..5}; do
        curl -s -X POST "${SERVICE_URL}/v1/chat/completions" \
            -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
            -H "Content-Type: application/json" \
            -d "{
                \"model\": \"/gcs/${MODEL_NAME}\",
                \"messages\": [{\"role\": \"user\", \"content\": \"Write an exceptionally long, detailed, and exhaustive essay about the entire history of the universe from the Big Bang to the modern day.\"}]
            }" > /dev/null &
    done
    
    echo "All 5 requests dispatched. Waiting for requests to complete..."
    wait
    echo "Done."
    
  2. 스크립트를 실행 가능하게 만들고 부하 테스트를 실행합니다.

    chmod +x load-test.sh
    ./load-test.sh
    
  3. crema-service 로그 및 Cloud Run 측정항목 대시보드를 다시 확인하여 대기 중인 요청에 따라 권장 인스턴스 수가 확장되는지 확인합니다.

Cloud Monitoring에서 vLLM 측정항목 살펴보기

부하 테스트를 실행한 후 트래픽이 Cloud Monitoring의 모델 서빙 측정항목에 미치는 영향을 살펴봅니다.

  1. Google Cloud 콘솔에서 Cloud Monitoring의 측정항목 탐색기 페이지로 이동합니다.

    측정항목 탐색기로 이동

  2. 측정항목 선택 을 클릭합니다.

  3. Prometheus 대상 > Vllm 을 펼치고 /gauge로 끝나는 사용 가능한 측정항목을 선택합니다. 예를 들어 prometheus/vllm:num_requests_running/gauge를 선택하여 부하 테스트 중에 활성 요청 수를 확인합니다.

vLLM 프로덕션 측정항목 문서에 설명된 대로 Cloud Monitoring으로 내보낸 추가 vLLM 측정항목은 다음과 같습니다.

  • prometheus/vllm:num_requests_waiting/gauge: vLLM 엔진에서 처리하기 위해 큐에서 대기 중인 요청 수입니다.
  • prometheus/vllm:num_requests_running/gauge: 모델 일괄 처리에서 실행 중인 요청 수입니다.
  • prometheus/vllm:gpu_cache_usage_perc/gauge: 사용된 GPU KV 캐시 메모리의 비율입니다.
  • prometheus/vllm:num_requests_swapped/gauge: 메모리 압력으로 인해 KV 캐시가 호스트 CPU 메모리로 스왑된 요청 수입니다.

이 튜토리얼에서는 vllm:num_requests_running을 기반으로 확장하지만 CREMA 구성에서 이러한 vLLM 측정항목을 사용하여 큐 크기, KV 캐시 사용률 또는 요청 스왑을 기반으로 워크로드의 자동 확장 규칙을 맞춤설정할 수 있습니다.

모든 요청을 동일하게 취급하는 표준 HTTP 요청 동시 실행 측정항목과 달리 vLLM의 내부 측정항목은 다양한 프롬프트 길이의 동적 GPU 메모리 공간을 고려합니다. vllm:num_requests_running을 기반으로 확장하면 실제 GPU 부하를 기반으로 사전 예방적으로 확장할 수 있습니다. 이렇게 하면 서버가 요청을 vllm:num_requests_waiting에 대기열에 추가하기 전에 활성 용량 버퍼가 유지되어 심각한 첫 번째 토큰까지의 시간 (TTFT) 지연 급증으로부터 사용자를 보호합니다.

정리

Google Cloud 계정에 추가 비용이 청구되지 않게 하려면 이 튜토리얼에서 배포한 모든 리소스를 삭제합니다.

프로젝트 삭제

이 튜토리얼용으로 새 프로젝트를 만든 경우 이 프로젝트를 삭제합니다. 기존 프로젝트를 사용했고 이 튜토리얼에 추가된 변경사항을 제외하고 보존하려면 튜토리얼을 위해 만든 리소스를 삭제합니다.

비용이 청구되지 않도록 하는 가장 쉬운 방법은 튜토리얼에서 만든 프로젝트를 삭제하는 것입니다.

프로젝트를 삭제하는 방법은 다음과 같습니다.

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

    리소스 관리로 이동

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

튜토리얼 리소스 삭제

  1. 이 튜토리얼에서 배포한 Cloud Run 서비스를 삭제합니다. Cloud Run 서비스는 요청을 수신할 때까지 비용을 청구하지 않습니다.

    Cloud Run 서비스를 삭제하려면 다음 명령어를 실행합니다.

    gcloud run services delete SERVICE-NAME

    SERVICE-NAME를 서비스 이름으로 바꿉니다.

    Google Cloud 콘솔에서 Cloud Run 서비스를 삭제할 수도 있습니다.

  2. 튜토리얼 설정 중에 추가한 gcloud 기본 리전 구성을 삭제합니다.

     gcloud config unset run/region
    
  3. 프로젝트 구성을 삭제합니다.

     gcloud config unset project
    
  4. Parameter Manager에 할당된 CREMA 구성을 삭제합니다.

    gcloud parametermanager parameters delete crema-config \
        --location=global \
        --quiet
    
  5. CREMA용으로 만든 커스텀 서비스 계정을 삭제합니다.

    gcloud iam service-accounts delete $CREMA_SA \
        --quiet
    
  6. 모델이 포함된 Cloud Storage 버킷을 삭제합니다.

    gcloud storage rm --recursive gs://$BUCKET_NAME
    
  7. 이 튜토리얼에서 만든 다른 Google Cloud 리소스를 삭제합니다.

다음 단계