본문 바로가기

Data Engineering/Cloud

[GCP] 티끌모아 GPU, 구글 클라우드에서의 GPU 모델 서빙기 (feat. BATCH)

문제점: 대부분의 CSP는 GPU 부족 상태


H100 기준으로 2023에 GCP는 약 5만 여대의 GPU를 확보한 것으로 추정된다고 합니다.

https://www.reddit.com/r/singularity/comments/1890o9y/nvidia_gpu_shipments_by_customer/

 

 

리드타임이 거의 1년이므로, 아직 수요에 비하면 GPU 공급이 따라오지 못하는 실정입니다.

 

저같은 경우는 적어도 제가 사용하는 T4 GPU는 부족한 것을 몸소 느끼는 중입니다(asia-northeast3 한국 기준).

 

이로 인해 비용 효율적인 SPOT 형태의 Provisioning은 어렵습니다.

 

그렇지만 제가 GPU로 모델 서빙에 필요한 작업은 near real time이고, 주기적으로 inference를 하면 되기에 Cron 형태의 작업을 실행하면 됩니다.

따라서 GCP의 Job as Service 인 Batch를 선택하였습니다. Batch는 결국 GCE 기반이기에 기존 cloud-init을 이용한 GPU 모델 서빙과 호환 가능할 것이라고 생각했습니다.

https://cloud.google.com/batch?hl=ko

 

https://cloud.google.com/batch?hl=ko

 

cloud.google.com

 

AWS에 존재하는 BATCH 서비스와 같은 서비스로 보입니다.

https://aws.amazon.com/ko/batch/

 

효율적인 배치 처리 - AWS Batch - AWS

기본적으로 AWS와 통합하여 확장, 네트워킹, 관리 기능을 구현할 수 있습니다.

aws.amazon.com


해결 과정: 일단 asia-northeast3-c (T4가 있는 zone)에서 GPU job 실행

Python SDK client로 이를 배포하려는 작업을 진행합니다.

그런데 문제가 발생했습니다. VM을 Container 형태로 모델을 배포하는데에는 Container-Optimized OS(COS) 사용을 권장합니다. 그런데 COS의 컨테이너 내부에서 GPU를 사용하려면 GPU device를 mount해야 하기에 cloud-init.yml 파일로 startup cript를 작성해줘야 합니다.

 

그 cloud-init.yml 파일을 metadata의 user-data key에 넣어주면 자동으로 startup 시에 systemd로 cloud-init에 정의된 서비스를 시작합니다.

 

https://cloud.google.com/container-optimized-os/docs/how-to/run-gpus?hl=ko#e2e

 

GPU 가속기로 인스턴스 실행  |  컨테이너 최적화 OS  |  Google Cloud

의견 보내기 GPU 가속기로 인스턴스 실행 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에서는 Container-Optimized OS 가상 머신(VM) 인스턴스에서 NVIDIA

cloud.google.com

 

그런데 batch_v1 client의 Type과 API 공식 문서에서 눈 씻고 찾아봐도 metadata를 넣는 부분은 없습니다(client의 method에서 metadata라는 kwarg가 있지만 이건 gRPC에서 사용되는 metadata이지, instance-level의 metadata가 아닙니다)
https://cloud.google.com/python/docs/reference/batch/latest/google.cloud.batch_v1.types

 

Package types (0.17.31)  |  Python client library  |  Google Cloud

Send feedback Package types (0.17.31) Stay organized with collections Save and categorize content based on your preferences. API documentation for batch_v1.types package. Classes A Job's resource allocation policy describes when, where, and how compute res

cloud.google.com


때문에 Batch에서의 다양한 GPU 사용 방법 토의가 Google cloud community에 있었습니다.
https://www.googlecloudcommunity.com/gc/Infrastructure-Compute-Storage/GCP-Batch-use-NVDIA-GPU-to-train-models-what-installation-are/m-p/784063

 

Re: GCP Batch use NVDIA GPU to train models what installation are required?

A separate question I have is, if Batch automatically fetches a GPU driver for me, how to ensure that it will be compatible with my cuda version (I use cuda 12.1)? It seems that I only have control over GPU type but not which GPU driver to fetch.

www.googlecloudcommunity.com

하지만 여기에서도 명확한 결론을 내리지는 못한 것으로 보였습니다.

 

추가: 약간의 언급 정도는 API 설명 쪽에 있긴 합니다. installGpuDrivers 부분을 확인하면 힌트가 존재합니다.

 

https://cloud.google.com/batch/docs/reference/rest/v1/projects.locations.jobs#instancepolicyortemplate

 

REST Resource: projects.locations.jobs  |  Batch  |  Google Cloud

Send feedback REST Resource: projects.locations.jobs Stay organized with collections Save and categorize content based on your preferences. Resource: Job The Cloud Batch Job description. JSON representation { "name": string, "uid": string, "priority": stri

cloud.google.com

 

따라서 다른 방법을 찾아본 결과, instance template을 사용하여 Batch job을 실행시키는 방법이 있고, 저는 instance template상에서 기본적으로 instance-level metadata가 보존된다는 것을 알고 있었습니다.

 

그래서 global에서 사용가능한 instance template을 하나 만들어 여기에 user-data에 cloud-init.yml을 넣어주고, 이를 복제하여 네트워크 설정을 하여 사용하기로 했습니다. 현재 저는 규모가 작기에 default이자 public subnet 에서 batch 작업을 실행시켰습니다.

 

만약 많은 Batch를 돌린다면 default vpc에서 하여 public 망으로 하지 않고, T4가 있는 각 리전별로 private 망으로 NAT Gateway를 도입하여 보안상 더욱 안전하게 진행할 수 있을 것입니다.

 

결론은 일단 Preemptible(SPOT) T4 GPU quota에 막히긴 했지만 정상적으로 VM instance가 생성된 것을 확인할 수 있었습니다! (다만 SPOT T4 GPU는 특이하게도 quota가 1이고 조정할 수도 없습니다...)

Quota 제한에 의한 Batch 서비스 제한

 

SPOT이 아닌 Standard 형태여도 마찬가지였습니다. 아마 기업에서 사용한다면 문의를 통해 해결할 수 있을 것입니다.

Standard에서 lack of GPU resources 겪은 상태

 

따라서 Location quota에 걸리지도 않고, Region에서의 GPU 부족을 해결하기 위해 다양한 location의 zone에서 실행시켜야만 합니다.

 


확장: GPU 자원이 있는 모든 Location을 등록하기

 

default vpc가 존재하기에 모든 location으로 매우 수월하게 확장할 수 있습니다. VPC Peering까지 사용하면 private IP를 사용하여 통신이 가능하기에 고품질의 통신을 저렴하게 달성할 수 있습니다. T4 GPU가 사용 가능한 Zones를 list로 받으면 Batch의 AllowedLocation 부분에 넣어 가능한 지역 중 하나에 Job을 실행시킬 수 있습니다.

 

단, 한 region 내부의 다른 zones만 AllowedLocation 내부에 들어갈 수 있으니 region과 zone들을 짝지어줘야 합니다.

 

구체적인 과정은 아래와 같습니다.

 

1. 기본적으로 Global instance template을 사용합니다

2. 기본 instance template을 sdk로 copy하고, region와 zone을 T4가 있는 곳으로 변경합니다(default vpc를 사용하지 않는 경우 network도 변경해야 합니다).

3. 이 instance template을 기반으로 Batch 서비스를 실행시킵니다.

4. Job 실행 상태를 폴링하며 timeout안에 RUNNING 상태가 되는지 확인합니다.

5-1. Timeout에 걸리거나, POOL_EXHAUST_ERROR가 나오거나 FAILED가 되면 바로 끝내고 copy한 instance template을 삭제합니다. 이후 다음 region에서 2번부터 다시 실행합니다.

5-2. RUNNING 상태가 되면 정상적으로 Job이 실행된 것이므로 copy했던 instance template을 cleanup하고 종료합니다.

 

또한 저는 모델 파일을 버전 관리를 쉽게 하기 위하여 Cloud Storage로 관리하는데, 더 낮은 레이턴시를 위하여 Single region에서 multi-region으로 바꿔주었습니다.

 


다시 문제 발생: Batch VM agent 설치 불가능 이슈

unsupported cos 에러 발생

 

Batch는 내부적으로 instance template을 만들어 메타데이터의 startup-script 레이블에서 자체 VM agent를 설치합니다. 하지만 cloud-init.yml이 들어가는 user-data 레이블과 startup-script 레이블의 중복 설정은 지원되지 않습니다(GCP가 아닌 Google Distributed Cloud 출처이지만 문제가 확실히 생기는 것 같습니다).

metadata label startup-script
Google Distributed Cloud 출처이긴 하지만 추천하지 않는 듯 합니다

 

https://cloud.google.com/kubernetes-engine/distributed-cloud/bare-metal/docs/vm-runtime/vm-startup-config

 

VM 시작 루틴 구성  |  Google Distributed Cloud (software only) for bare metal  |  Google Cloud

이제 베어메탈용 Anthos 클러스터는 베어메탈용 Google Distributed Cloud(소프트웨어 전용)입니다. 자세한 내용은 제품 개요를 참조하세요. 의견 보내기 VM 시작 루틴 구성 컬렉션을 사용해 정리하기 내

cloud.google.com

 

이 문제에 대한 2개의 해결책을 도출했습니다.


해결책 1: API 호출로 startup-script를 받아서 그걸 systemd 서비스로 등록 후 실행하는 cloud-init.yaml 파일 작성 (예상 문제 존재)

문제가 될 수 있는 부분이 있습니다.

 

1. Batch는 스크립트를 사용한 Job은 Debian, CentOS, Rocky 등을 지원하고 컨테이너 Job은 Batch COS를 지원합니다.

https://cloud.google.com/batch/docs/vm-os-environment-overview?hl=ko

 

작업 VM의 OS 환경 개요  |  Batch  |  Google Cloud

TODO

cloud.google.com

2. 제 기존 인스턴스 템플릿에서 사용하는 OS는 Batch COS가 아닌 그냥 COS 입니다.

 

따라서 OS가 맞지 않아 예상치 못한 문제가 발생할 수 있습니다. 단, 제 인스턴스 템플릿의 OS를 Batch COS로 변경한다면 해결될 수 있습니다.

 

그러나 좀 더 안정적인 해결책을 찾고 싶었습니다.


해결책 2: Batch COS에서 cloud-init을 사용하지 않고 진행하기

일단 COS에서 cloud-init을 사용하게 된 계기가 있습니다. 바로 보안상 루트 사용자로 시작하지 않고, 이 경우에 루트 디렉토리에 Write를 할 수 없기에 새로운 계정을 만들고, 그 계정으로 컨테이너를 실행시키는 조금 복잡한 과정이 있었습니다(알고 보니 root에만 write를 할 수 없으니 다른 디렉토리(/etc)에서 실행하면 되네요...).

https://cloud.google.com/container-optimized-os/docs/concepts/security?hl=ko

 

보안 개요  |  컨테이너 최적화 OS  |  Google Cloud

이 페이지는 Cloud Translation API를 통해 번역되었습니다. 의견 보내기 보안 개요 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지는 Google Cloud에서 실

cloud.google.com

 

참고: cloud-init.yaml을 활용하여 엔드투엔드 COS에서 GPU 사용하기

 

GPU 가속기로 인스턴스 실행  |  컨테이너 최적화 OS  |  Google Cloud

의견 보내기 GPU 가속기로 인스턴스 실행 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에서는 Container-Optimized OS 가상 머신(VM) 인스턴스에서 NVIDIA

cloud.google.com

 

Batch COS는 서비스 자체적인 설정으로 인하여 컨테이너를 priviledge 모드로 사용하는 등 다양한 이유가 있어보였습니다. 실제로 아래 문서를 보면 기본적으로 실행가능한 작업들을 루트 권한으로 설정한다고 나와있습니다.

https://cloud.google.com/batch/docs/non-root-job?hl=ko

 

루트가 아닌 사용자로 작업 만들기 및 실행  |  Batch  |  Google Cloud

OS 로그인을 사용 설정하여 Batch를 루트가 아닌 사용자로 실행합니다.

cloud.google.com

 

따라서 기본적인 GPU 관련 설정만 옵션으로 넣어주면서 성공했습니다!

nvidia_gpu_options = "--volume /var/lib/nvidia/lib64:/usr/local/nvidia/lib64 --volume /var/lib/nvidia/bin:/usr/local/nvidia/bin --device /dev/nvidia0:/dev/nvidia0 --device /dev/nvidia-uvm:/dev/nvidia-uvm --device /dev/nvidiactl:/dev/nvidiactl -e NVIDIA_VISIBLE_DEVICES=all -e NVIDIA_DRIVER_CAPABILITIES=all --env LD_LIBRARY_PATH=/usr/local/nvidia/lib64"
transformers_module_options = "-e TRANSFORMERS_CACHE=/app/src_ocr"
custom_options = " ".join([f"-e {k}={v}" for k, v in env_vars.items()])
options = f"{nvidia_gpu_options} {transformers_module_options} {custom_options}"
job = {
    "task_groups":[
        {
            "task_spec":{
                "runnables": [{                        
                    "container": {
                        "image_uri": images_uri,                                                                                     
                        "entrypoint": "",
                        "volumes": [],
                        "options": options
                        }
                }],            
                ...​

결론: T4 GPU가 남아있는 Zone에서 Batch를 통한 배치 ML 모델 서빙 성공

여러 번 GPU 인퍼런스를 위하여 많은 시도를 하였지만 결국 작업에 맞는 가성비 좋은 솔루션을 찾아 기뻤습니다.

 

1. Cloud Run을 이용한 실시간 CPU 모델 서빙 -> 인퍼런스 속도 대비 가격이 매우 비쌈. 콜드 스타트 등 이슈로 인한 추가 비용 발생. GPU 모델 서빙 불가능 (현재는 가능하다고 합니다)

https://cloud.google.com/run/docs/configuring/services/gpu?hl=ko

2. Airflow를 이용하여 크롤링과 함께 GCE 기반 실시간 GPU 모델 서빙 -> 크롤링 과정동안 계속 GPU가 필요하지는 않음. GPU가 부족할 때가 너무 많음.

3. Batch를 이용하여 GPU 모델 배치로 서빙 -> SPOT GPU 사용 가능, GPU 리소스 최대한 사용 가능, 비용 절감.

 

현재 Cloud Run을 이용한 GPU 모델 실시간 서빙이 가능하다고는 하지만 모델의 크기가 크고, 인퍼런스를 하기 위한 컨테이너 이미지가 크기에 콜드스타트로 인한 비용의 과다 초래가 있을 것으로 보이긴 합니다.

 


발전 방향:

1. RunPod, Lambda와 같은 GPUaaS를 이용한 멀티 클라우드를 구현하면 좋을 것 같습니다.

2. GPU를 이용한 다양한 작업을 진행하는 경우, 클라우드 상에서 미리 GPU를 예약 구매하고, 스케줄링을 효율적으로 돌리면 될 것 같습니다.

 

여유가 된다면 GPU를 이용한 배치 서빙에 대한 Batch 서비스 사용 팁을 이후에 포스팅하겠습니다.

 

감사합니다.

 


추가: multi-region에서 batch 서비스로 GPU를 사용하여 배포하는 샘플 코드를 작성했습니다. 참고하시면 좋을 것 같습니다.

 

https://github.com/ket0825/gdg-batch-gpu-sample

 

GitHub - ket0825/gdg-batch-gpu-sample: gdg-batch-gpu-sample

gdg-batch-gpu-sample. Contribute to ket0825/gdg-batch-gpu-sample development by creating an account on GitHub.

github.com