Hyperdisk ML을 사용하여 AI/ML 데이터 로드 가속화


이 가이드에서는 Hyperdisk ML을 사용하여 Google Kubernetes Engine(GKE)에서 AI/ML 모델 가중치 로드를 간소화하고 가속화하는 방법을 설명합니다. Compute Engine Persistent Disk CSI 드라이버는 GKE 클러스터가 있는 Hyperdisk ML 스토리지에 액세스하기 위한 기본 방법입니다.

개요

Hyperdisk ML은 애플리케이션을 수평 확장하는 데 사용할 수 있는 고성능 스토리지 솔루션입니다. 여러 가상 머신에 동시에 높은 집계 처리량을 제공하므로 대량의 데이터에 액세스해야 하는 AI/ML 워크로드를 실행하는 데 적합합니다.

여러 노드로 읽기 전용 모드에서 사용 설정하면 Hyperdisk ML을 사용하여 모델 가중치 로드 속도를 모델 레지스트리에서 직접 로드할 때보다 최대 11.9배 높일 수 있습니다. 이러한 가속은 1.2TB/초로 동시 노드 2,500개로 확장할 수 있는 Google Cloud Hyperdisk 아키텍처를 통해 가능합니다. 따라서 AI/ML 추론 워크로드의 로드 시간을 개선하고 포드의 초과 프로비저닝을 줄일 수 있습니다.

Hyperdisk ML을 만들고 사용하는 대략적인 단계는 다음과 같습니다.

  1. Persistent Disk 디스크 이미지에 데이터 사전 캐시 또는 하이드레이션: 서빙에 사용할 수 있는 외부 데이터 소스의 데이터(예: Cloud Storage에서 로드된 Gemma 가중치)를 Hyperdisk ML 볼륨에 로드합니다. 디스크 이미지의 Persistent Disk는 Google Cloud Hyperdisk와 호환되어야 합니다.
  2. 기존 Google Cloud Hyperdisk를 사용하여 Hyperdisk ML 볼륨 만들기: 데이터가 로드된 Hyperdisk ML 볼륨을 참조하는 Kubernetes 볼륨을 만듭니다. 필요한 경우 포드가 실행될 모든 영역에서 데이터를 사용할 수 있도록 다중 영역 스토리지 클래스를 만들 수 있습니다.
  3. Hyperdisk ML 볼륨을 사용하는 Kubernetes 배포 만들기: 가속화된 데이터 로드를 통해 애플리케이션에서 사용할 Hyperdisk ML 볼륨을 참조합니다.

다중 영역 Hyperdisk ML 볼륨

Hyperdisk ML 디스크는 단일 영역에서만 사용할 수 있습니다. 필요한 경우 Hyperdisk ML 다중 영역 기능을 사용하여 동일한 콘텐츠를 포함하는 여러 영역 디스크를 단일 논리 PersistentVolumeClaim 및 PersistentVolume에 동적으로 연결할 수 있습니다. 다중 영역 기능에서 참조하는 영역 디스크는 동일한 리전에 있어야 합니다. 예를 들어 리전별 클러스터가 us-central1에 생성된 경우 다중 영역 디스크는 동일한 리전(예: us-central1-a, us-central1-b)에 있어야 합니다.

AI/ML 추론의 일반적인 사용 사례는 스팟 VM으로 가속기 가용성과 비용 효율성을 개선하면서 여러 영역에서 포드를 실행하는 것입니다. Hyperdisk ML은 영역별이므로 추론 서버가 여러 영역에서 여러 포드를 실행하는 경우 GKE는 데이터가 애플리케이션을 따르도록 영역 전체에서 디스크를 자동으로 클론합니다.

외부 데이터 소스에서 Hyperdisk ML을 하이드레이션하고 및 여러 영역에서 데이터에 액세스하도록 다중 영역 PV를 만듭니다.

다중 영역 Hyperdisk ML 볼륨에는 다음과 같은 제한사항이 있습니다.

  • 볼륨 크기 조절 및 볼륨 스냅샷 작업은 지원되지 않습니다.
  • 다중 영역 Hyperdisk ML 볼륨은 읽기 전용 모드에서만 지원됩니다.
  • 다중 영역 Hyperdisk ML 볼륨에 기존 디스크를 사용하는 경우 GKE는 여러 영역의 디스크 콘텐츠가 동일한지 확인하는 검사를 수행하지 않습니다. 상이한 콘텐츠를 포함하는 디스크가 하나라도 있는 경우 애플리케이션에서 영역 간의 잠재적 불일치를 고려해야 합니다.

자세한 내용은 VolumeSnapshot에서 다중 영역 ReadOnlyMany Hyperdisk ML 볼륨 만들기를 참조하세요.

시작하기 전에

시작하기 전에 다음 태스크를 수행했는지 확인합니다.

  • Google Kubernetes Engine API를 사용 설정합니다.
  • Google Kubernetes Engine API 사용 설정
  • 이 태스크에 Google Cloud CLI를 사용하려면 gcloud CLI를 설치한 후 초기화합니다. 이전에 gcloud CLI를 설치한 경우 gcloud components update를 실행하여 최신 버전을 가져옵니다.
  • 기본 리전 및 영역을 지원되는 값 중 하나로 설정하세요.
  • Google Cloud 프로젝트에 이 가이드에서 필요한 노드를 만들 할당량이 충분한지 확인합니다. GKE 클러스터 및 Kubernetes 리소스를 만드는 예시 코드에서 선택한 리전에 필요한 최소 할당량은 C3 CPU 88개 및 NVIDIA L4 GPU 4개입니다.

요구사항

GKE에서 Hyperdisk ML 볼륨을 사용하려면 클러스터가 다음 요구사항을 충족해야 합니다.

  • GKE 버전 1.30.2-gke.1394000 이상을 실행하는 Linux 클러스터를 사용합니다. 출시 채널을 사용하는 경우 채널에 이 드라이버에 필요한 최소 GKE 버전이나 그 이상의 버전이 있는지 확인해야 합니다.
  • Compute Engine Persistent Disk CSI 드라이버가 사용 설정되어 있는지 확인하세요. Compute Engine Persistent Disk 드라이버는 기본적으로 새로운 Autopilot 및 Standard 클러스터에서 사용 설정되며 Autopilot 사용 시 사용 중지하거나 수정할 수 없습니다. 클러스터에서 Compute Engine Persistent Disk CSI 드라이버를 사용 설정해야 하는 경우 기존 클러스터에서 Compute Engine Persistent Disk CSI 드라이버 사용 설정을 참조하세요.
  • 미리 읽기 값을 조정하려면 GKE 버전 1.29.2-gke.1217000 이상을 사용하세요.
  • 다중 영역 동적 프로비저닝 기능을 사용하려면 GKE 버전 1.30.2-gke.1394000 이상을 사용하세요.
  • Hyperdisk ML은 특정 노드 유형 및 영역에서만 지원됩니다. 자세한 내용은 Compute Engine 문서의 Google Cloud Hyperdisk 정보를 참조하세요.

모델 액세스 권한 얻기

GKE에 배포하기 위해 Gemma 모델에 액세스하려면 먼저 라이선스 동의 계약에 서명한 다음 Hugging Face 액세스 토큰을 생성해야 합니다.

Gemma를 사용하려면 동의 계약에 서명해야 합니다. 다음 안내를 따르세요.

  1. Kaggle.com의 모델 동의 페이지에 액세스합니다.
  2. Hugging Face 계정을 사용하여 동의를 확인합니다.
  3. 모델 약관에 동의합니다.

액세스 토큰 생성

Hugging Face를 통해 모델에 액세스하려면 Hugging Face 토큰이 필요합니다.

아직 토큰이 없으면 다음 단계에 따라 새 토큰을 생성합니다.

  1. 내 프로필 > 설정 > 액세스 토큰을 클릭합니다.
  2. 새 토큰을 선택합니다.
  3. 원하는 이름과 Read 이상의 역할을 지정합니다.
  4. 토큰 생성을 선택합니다.
  5. 클립보드에 생성된 토큰을 복사합니다.

GKE 클러스터 만들기

GPU를 활용하여 GKE Autopilot 또는 Standard 클러스터에서 LLM을 제공할 수 있습니다. 완전 관리형 Kubernetes 환경을 위해서는 Autopilot 클러스터를 사용하는 것이 좋습니다. 워크로드에 가장 적합한 GKE 작업 모드를 선택하려면 GKE 작업 모드 선택을 참조하세요.

Autopilot

  1. Cloud Shell에서 다음 명령어를 실행합니다.

    gcloud container clusters create-auto hdml-gpu-l4 \
      --project=PROJECT \
      --region=REGION \
      --release-channel=rapid \
      --cluster-version=1.30.2-gke.1394000
    

    다음 값을 바꿉니다.

    • PROJECT: Google Cloud 프로젝트 ID입니다.
    • REGION: 사용하려는 가속기 유형을 지원하는 리전(예: L4 GPU의 경우 us-east4)입니다.

    GKE는 배포된 워크로드의 요청에 따라 CPU 및 GPU 노드를 사용하여 Autopilot 클러스터를 만듭니다.

  2. 클러스터와 통신하도록 kubectl을 구성합니다.

    gcloud container clusters get-credentials hdml-gpu-l4 \
      --region=REGION
    

Standard

  1. Cloud Shell에서 다음 명령어를 실행하여 Standard 클러스터와 노드 풀을 만듭니다.

    gcloud container clusters create hdml-gpu-l4 \
        --location=REGION \
        --num-nodes=1 \
        --machine-type=c3-standard-44 \
        --release-channel=rapid \
        --cluster-version=CLUSTER_VERSION \
        --node-locations=ZONES \
        --project=PROJECT
    
    gcloud container node-pools create gpupool \
        --accelerator type=nvidia-l4,count=2,gpu-driver-version=latest \
        --location=REGION \
        --project=PROJECT \
        --node-locations=ZONES \
        --cluster=hdml-gpu-l4 \
        --machine-type=g2-standard-24 \
        --num-nodes=2
    

    다음 값을 바꿉니다.

    • CLUSTER_VERSION: GKE 클러스터의 버전입니다(예: 1.30.2-gke.1394000).
    • REGION: 클러스터 컨트롤 플레인의 컴퓨팅 리전입니다. 리전은 사용하려는 가속기(예: L4 GPU의 경우 us-east4)를 지원해야 합니다. L4 GPU를 사용할 수 있는 리전을 확인합니다.
    • ZONES: 노드가 생성된 영역입니다. 클러스터에 필요한 만큼 많은 영역을 지정할 수 있습니다. 모든 영역은 --zone 플래그에 지정된 대로 클러스터의 컨트롤 플레인과 동일한 리전에 있어야 합니다. 영역 클러스터의 경우 --node-locations에 클러스터의 기본 영역이 포함되어야 합니다.
    • PROJECT: Google Cloud 프로젝트 ID입니다.

    클러스터 만들기는 몇 분 정도 걸릴 수 있습니다.

  2. 클러스터와 통신하도록 kubectl을 구성합니다.

    gcloud container clusters get-credentials hdml-gpu-l4
    

Persistent Disk 디스크 이미지에 데이터 사전 캐시

Hyperdisk ML을 사용하려면 디스크 이미지에 데이터를 사전 캐시하고 GKE에서 워크로드가 읽을 Hyperdisk ML 볼륨을 만듭니다. 이 접근 방식(데이터 하이드레이션이라고도 함)을 사용하면 워크로드에서 필요할 때 데이터를 사용할 수 있습니다.

Cloud Storage에서 데이터를 복사하여 Persistent Disk 디스크 이미지를 사전 캐시하려면 다음 단계를 따르세요.

Hyperdisk ML을 지원하는 StorageClass 만들기

  1. 다음 StorageClass 매니페스트를 hyperdisk-ml.yaml 파일에 저장합니다.

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
        name: hyperdisk-ml
    parameters:
        type: hyperdisk-ml
    provisioner: pd.csi.storage.gke.io
    allowVolumeExpansion: false
    reclaimPolicy: Delete
    volumeBindingMode: WaitForFirstConsumer
    
  2. 다음 명령어를 실행하여 StorageClass를 만듭니다.

    kubectl create -f hyperdisk-ml.yaml
    

ReadWriteOnce(RWO) PersistentVolumeClaim 만들기

  1. 다음 PersistentVolumeClaim 매니페스트를 producer-pvc.yaml 파일에 저장합니다. 앞에서 만든 StorageClass를 사용합니다. 디스크에 데이터를 저장할 용량이 충분한지 확인합니다.

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: producer-pvc
    spec:
      storageClassName: hyperdisk-ml
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 300Gi
    
  2. 다음 명령어를 실행하여 PersistentVolumeClaim을 만듭니다.

    kubectl create -f producer-pvc.yaml
    

마운트된 Google Cloud Hyperdisk 볼륨을 채우는 Kubernetes 작업 만들기

이 섹션에서는 디스크를 프로비저닝하고 Hugging Face에서 마운트된 Google Cloud Hyperdisk 볼륨으로 Gemma 7B 명령어 조정 모델을 다운로드하는 Kubernetes 작업을 만드는 예시를 보여줍니다.

  1. 이 가이드의 예시에서 사용하는 Gemma LLM에 액세스하려면 Hugging Face 토큰이 포함된 Kubernetes 보안 비밀을 만듭니다.

    kubectl create secret generic hf-secret \
        --from-literal=hf_api_token=HF_TOKEN\
        --dry-run=client -o yaml | kubectl apply -f -
    

    HF_TOKEN을 이전에 생성한 Hugging Face 토큰으로 바꿉니다.

  2. 다음 예시 매니페스트를 producer-job.yaml로 저장합니다.

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: producer-job
    spec:
      template:  # Template for the Pods the Job will create
        spec:
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: cloud.google.com/compute-class
                    operator: In
                    values:
                    - "Performance"
                - matchExpressions:
                  - key: cloud.google.com/machine-family
                    operator: In
                    values:
                    - "c3"
                - matchExpressions:
                  - key: topology.kubernetes.io/zone
                    operator: In
                    values:
                    - "ZONE"
          containers:
          - name: copy
            resources:
              requests:
                cpu: "32"
              limits:
                cpu: "32"
            image: huggingface/downloader:0.17.3
            command: [ "huggingface-cli" ]
            args:
            - download
            - google/gemma-1.1-7b-it
            - --local-dir=/data/gemma-7b
            - --local-dir-use-symlinks=False
            env:
            - name: HUGGING_FACE_HUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_api_token
            volumeMounts:
              - mountPath: "/data"
                name: volume
          restartPolicy: Never
          volumes:
            - name: volume
              persistentVolumeClaim:
                claimName: producer-pvc
      parallelism: 1         # Run 1 Pods concurrently
      completions: 1         # Once 1 Pods complete successfully, the Job is done
      backoffLimit: 4        # Max retries on failure
    

    ZONE을 Hyperdisk를 만들려는 컴퓨팅 영역으로 바꿉니다. 배포 예시와 함께 사용하는 경우 G2 머신 용량이 있는 영역인지 확인합니다.

  3. 다음 명령어를 실행하여 작업을 만듭니다.

    kubectl apply -f producer-job.yaml
    

    작업에서 Persistent Disk 볼륨에 데이터를 복사하는 작업을 완료하는 데 몇 분 정도 걸릴 수 있습니다. 작업에서 프로비저닝이 완료되면 작업 상태가 '완료'로 표시됩니다.

  4. 작업 상태의 진행을 확인하려면 다음 명령어를 실행합니다.

    kubectl get job producer-job
    
  5. 작업이 완료되면 다음 명령어를 실행하여 작업을 정리할 수 있습니다.

    kubectl delete job producer-job
    

기존 Google Cloud Hyperdisk에서 ReadOnlyMany Hyperdisk ML 볼륨 만들기

이 섹션에서는 기존 Google Cloud Hyperdisk 볼륨에서 ReadOnlyMany(ROM) PersistentVolume 및 PersistentVolumeClaim 쌍을 만드는 단계를 설명합니다. 자세한 내용은 기존 영구 디스크를 PersistentVolume으로 사용을 참조하세요.

  1. GKE 버전 1.30.2-gke.1394000 이상에서 GKE는 READ_WRITE_SINGLE Google Cloud Hyperdisk 볼륨의 액세스 모드를 READ_ONLY_MANY로 자동 변환합니다.

    이전 버전의 GKE에서 기존 Google Cloud Hyperdisk 볼륨을 사용하는 경우 다음 명령어를 실행하여 액세스 모드를 수동으로 수정해야 합니다.

    gcloud compute disks update HDML_DISK_NAME \
        --zone=ZONE \
        --access-mode=READ_ONLY_MANY
    

    다음 값을 바꿉니다.

    • HDML_DISK_NAME: Hyperdisk ML 볼륨의 이름입니다.
    • ZONE: 기존 Google Cloud Hyperdisk 볼륨이 생성된 컴퓨팅 영역입니다.
  2. 이전에 채운 디스크를 참조하여 PersistentVolume 및 PersistentVolumeClaim 쌍을 만듭니다.

    1. 다음 매니페스트를 hdml-static-pv.yaml로 저장합니다.

      apiVersion: v1
      kind: PersistentVolume
      metadata:
        name: hdml-static-pv
      spec:
        storageClassName: "hyperdisk-ml"
        capacity:
          storage: 300Gi
        accessModes:
          - ReadOnlyMany
        claimRef:
          namespace: default
          name: hdml-static-pvc
        csi:
          driver: pd.csi.storage.gke.io
          volumeHandle: projects/PROJECT/zones/ZONE/disks/DISK_NAME
          fsType: ext4
          readOnly: true
        nodeAffinity:
          required:
            nodeSelectorTerms:
            - matchExpressions:
              - key: topology.gke.io/zone
                operator: In
                values:
                - ZONE
      ---
      apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        namespace: default
        name: hdml-static-pvc
      spec:
        storageClassName: "hyperdisk-ml"
        volumeName: hdml-static-pv
        accessModes:
        - ReadOnlyMany
        resources:
          requests:
            storage: 300Gi
      

      다음 값을 바꿉니다.

      • PROJECT: GKE 클러스터가 생성되는 프로젝트입니다.
      • ZONE: 기존 Google Cloud Hyperdisk 볼륨이 생성된 영역입니다.
      • DISK_NAME: 기존 Google Cloud Hyperdisk 볼륨의 이름입니다.
    2. 다음 명령어를 실행하여 PersistentVolume 및 PersistentVolumeClaim 리소스를 만듭니다.

      kubectl apply -f hdml-static-pv.yaml
      

VolumeSnapshot에서 다중 영역 ReadOnlyMany Hyperdisk ML 볼륨 만들기

이 섹션에서는 ReadOnlyMany 액세스 모드로 다중 영역 Hyperdisk ML 볼륨을 만드는 단계를 설명합니다. 기존 Persistent Disk 디스크 이미지에는 VolumeSnapshot을 사용합니다. 자세한 내용은 볼륨 스냅샷을 사용하여 Persistent Disk 스토리지 백업을 참조하세요.

다중 영역 Hyperdisk ML 볼륨을 만들려면 다음 단계를 따르세요.

디스크의 VolumeSnapshot 만들기

  1. 다음 매니페스트를 disk-image-vsc.yaml 파일로 저장합니다.

    apiVersion: snapshot.storage.k8s.io/v1
    kind: VolumeSnapshotClass
    metadata:
      name: disk-image-vsc
    driver: pd.csi.storage.gke.io
    deletionPolicy: Delete
    parameters:
      snapshot-type: images
    
  2. 다음 명령어를 실행하여 VolumeSnapshotClass를 만듭니다.

    kubectl apply -f disk-image-vsc.yaml
    
  3. 다음 매니페스트를 my-snapshot.yaml 파일로 저장합니다. ReadWriteOnce(RWO) PersistentVolumeClaim 만들기에서 이전에 만든 PersistentVolumeClaim을 참조합니다.

    apiVersion: snapshot.storage.k8s.io/v1
    kind: VolumeSnapshot
    metadata:
      name: my-snapshot
    spec:
      volumeSnapshotClassName: disk-image-vsc
      source:
        persistentVolumeClaimName: producer-pvc
    
  4. 다음 명령어를 실행하여 VolumeSnapshot을 만듭니다.

    kubectl apply -f my-snapshot.yaml
    
  5. VolumeSnapshot이 '준비됨'으로 표시되면 다음 명령어를 실행하여 Hyperdisk ML 볼륨을 만듭니다.

    kubectl wait --for=jsonpath='{.status.readyToUse}'=true \
        --timeout=300s volumesnapshot my-snapshot
    

다중 영역 StorageClass 만들기

두 개 이상의 영역에서 데이터 사본에 액세스할 수 있도록 하려면 StorageClass에 enable-multi-zone-provisioning 매개변수를 지정합니다. 그러면 allowedTopologies 필드에 지정한 영역에 디스크가 생성됩니다.

StorageClass를 만들려면 다음 단계를 따르세요.

  1. 다음 매니페스트를 hyperdisk-ml-multi-zone.yaml 파일로 저장합니다.

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: hyperdisk-ml-multi-zone
    parameters:
      type: hyperdisk-ml
      provisioned-throughput-on-create: "2400Mi"
      enable-multi-zone-provisioning: "true"
    provisioner: pd.csi.storage.gke.io
    allowVolumeExpansion: false
    reclaimPolicy: Delete
    volumeBindingMode: Immediate
    allowedTopologies:
    - matchLabelExpressions:
      - key: topology.gke.io/zone
        values:
        - ZONE_1
        - ZONE_2
    

    ZONE_1, ZONE_2, ..., ZONE_N을 스토리지에 액세스할 수 있는 영역으로 바꿉니다.

    이 예시에서는 GKE가 PersistentVolumeClaim을 해당 항목을 참조하는 모든 소비자보다 먼저 프로비저닝할 수 있도록 volumeBindingMode를 Immediate로 설정합니다.

  2. 다음 명령어를 실행하여 StorageClass를 만듭니다.

    kubectl apply -f hyperdisk-ml-multi-zone.yaml
    

다중 영역 StorageClass를 사용하는 PersistentVolumeClaim 만들기

다음 단계에서는 StorageClass를 참조하는 PersistentVolumeClaim을 만듭니다.

GKE는 지정된 디스크 이미지의 콘텐츠를 사용하여 스냅샷에 지정된 각 영역에 Hyperdisk ML 볼륨을 자동으로 프로비저닝합니다.

PersistentVolumeClaim을 만들려면 다음 단계를 따르세요.

  1. 다음 매니페스트를 hdml-consumer-pvc.yaml 파일로 저장합니다.

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: hdml-consumer-pvc
    spec:
      dataSource:
        name: my-snapshot
        kind: VolumeSnapshot
        apiGroup: snapshot.storage.k8s.io
      accessModes:
      - ReadOnlyMany
      storageClassName: hyperdisk-ml-multi-zone
      resources:
        requests:
          storage: 300Gi
    
  2. 다음 명령어를 실행하여 PersistentVolumeClaim을 만듭니다.

    kubectl apply -f hdml-consumer-pvc.yaml
    

Hyperdisk ML 볼륨을 사용하는 배포 만들기

PersistentVolume과 함께 포드를 사용하는 경우 Deployment 또는 StatefulSet 같은 워크로드 컨트롤러를 사용하는 것이 좋습니다.

배포와 함께 ReadOnlyMany 모드로 기존 PersistentVolume을 사용하려면 여러 리더가 있는 영구 디스크 사용을 참조하세요.

배포를 만들고 테스트하려면 다음 단계를 따르세요.

  1. 다음 예시 매니페스트를 vllm-gemma-deployment로 저장합니다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: vllm-gemma-deployment
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: gemma-server
      template:
        metadata:
          labels:
            app: gemma-server
            ai.gke.io/model: gemma-7b
            ai.gke.io/inference-server: vllm
        spec:
          affinity:
            podAntiAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
              - weight: 100
                podAffinityTerm:
                  labelSelector:
                    matchExpressions:
                    - key: security
                      operator: In
                      values:
                      - S2
                  topologyKey: topology.kubernetes.io/zone
          containers:
          - name: inference-server
            image: us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:latest
            resources:
              requests:
                cpu: "2"
                memory: "25Gi"
                ephemeral-storage: "25Gi"
                nvidia.com/gpu: 2
              limits:
                cpu: "2"
                memory: "25Gi"
                ephemeral-storage: "25Gi"
                nvidia.com/gpu: 2
            command: ["python3", "-m", "vllm.entrypoints.api_server"]
            args:
            - --model=$(MODEL_ID)
            - --tensor-parallel-size=2
            env:
            - name: MODEL_ID
              value: /models/gemma-7b
            volumeMounts:
            - mountPath: /dev/shm
              name: dshm
            - mountPath: /models
              name: gemma-7b
          volumes:
          - name: dshm
            emptyDir:
                medium: Memory
          - name: gemma-7b
            persistentVolumeClaim:
              claimName: CLAIM_NAME
          nodeSelector:
            cloud.google.com/gke-accelerator: nvidia-l4
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: llm-service
    spec:
      selector:
        app: gemma-server
      type: ClusterIP
      ports:
        - protocol: TCP
          port: 8000
          targetPort: 8000
    

    CLAIM_NAME을 다음 값 중 하나로 바꿉니다.

    • hdml-static-pvc: 기존 Google Cloud Hyperdisk의 Hyperdisk ML 볼륨을 사용하는 경우
    • hdml-consumer-pvc: VolumeSnapshot 디스크 이미지의 Hyperdisk ML 볼륨을 사용하는 경우
  2. 다음 명령어를 실행하여 추론 서버를 사용할 수 있을 때까지 기다립니다.

    kubectl wait --for=condition=Available --timeout=700s deployment/vllm-gemma-deployment
    
  3. vLLM 서버가 작동하는지 테스트하려면 다음 단계를 따르세요.

    1. 다음 명령어를 실행하여 모델에 대한 포트 전달을 설정합니다.

      kubectl port-forward service/llm-service 8000:8000
      
    2. curl 명령어를 실행하여 모델에 요청을 전송합니다.

      USER_PROMPT="I'm new to coding. If you could only recommend one programming language to start with, what would it be and why?"
      
      curl -X POST http://localhost:8000/generate \
      -H "Content-Type: application/json" \
      -d @- <<EOF
      {
          "prompt": "<start_of_turn>user\n${USER_PROMPT}<end_of_turn>\n",
          "temperature": 0.90,
          "top_p": 1.0,
          "max_tokens": 128
      }
      EOF
      

    다음 출력에는 모델 응답 예시가 표시됩니다.

    {"predictions":["Prompt:\n<start_of_turn>user\nI'm new to coding. If you could only recommend one programming language to start with, what would it be and why?<end_of_turn>\nOutput:\nPython is often recommended for beginners due to its clear, readable syntax, simple data types, and extensive libraries.\n\n**Reasons why Python is a great language for beginners:**\n\n* **Easy to read:** Python's syntax is straightforward and uses natural language conventions, making it easier for beginners to understand the code.\n* **Simple data types:** Python has basic data types like integers, strings, and lists that are easy to grasp and manipulate.\n* **Extensive libraries:** Python has a vast collection of well-documented libraries covering various tasks, allowing beginners to build projects without reinventing the wheel.\n* **Large supportive community:**"]}
    

미리 읽기 값 조정

순차 I/O를 수행하는 워크로드가 있는 경우 미리 읽기 값을 조정하면 유용할 수 있습니다. 이는 일반적으로 AI/ML 모델 가중치를 메모리에 로드해야 하는 추론 또는 학습 워크로드에 적용됩니다. 순차 I/O가 있는 대부분의 워크로드는 일반적으로 미리 읽기 값이 1024KB 이상일 때 성능이 향상됩니다.

새 PersistentVolume을 정적으로 프로비저닝하거나 동적으로 프로비저닝된 기존 PersistentVolume을 수정할 때 read_ahead_kb 마운트 옵션을 통해 이 옵션을 지정할 수 있습니다.

다음 예시에서는 미리 읽기 값을 4096KB로 조정하는 방법을 보여줍니다.

apiVersion: v1
kind: PersistentVolume
  name: DISK_NAME
spec:
  accessModes:
  - ReadOnlyMany
  capacity:
    storage: 300Gi
  csi:
    driver: pd.csi.storage.gke.io
    fsType: ext4
    readOnly: true
    volumeHandle: projects/PROJECT/zones/ZONE/disks/DISK_NAME
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: topology.gke.io/zone
          operator: In
          values:
          - ZONE
  storageClassName: hyperdisk-ml
  mountOptions:
  - read_ahead_kb=4096

다음 값을 바꿉니다.

  • DISK_NAME: 기존 Google Cloud Hyperdisk 볼륨의 이름입니다.
  • ZONE: 기존 Google Cloud Hyperdisk 볼륨이 생성된 영역입니다.

Hyperdisk ML 볼륨 성능 테스트 및 벤치마킹

이 섹션에서는 가변형 I/O 테스터(FIO)를 사용하여 Hyperdisk ML 볼륨의 기존 데이터 읽기 성능을 벤치마킹하는 방법을 보여줍니다. 이러한 측정항목을 사용하여 특정 워크로드 및 구성에 대한 볼륨의 성능을 평가할 수 있습니다.

  1. 다음 예시 매니페스트를 benchmark-job.yaml로 저장합니다.

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: benchmark-job
    spec:
      template:  # Template for the Pods the Job will create
        spec:
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: cloud.google.com/compute-class
                    operator: In
                    values:
                    - "Performance"
                - matchExpressions:
                  - key: cloud.google.com/machine-family
                    operator: In
                    values:
                    - "c3"
    
          containers:
          - name: fio
            resources:
              requests:
                cpu: "32"
            image: litmuschaos/fio
            args:
            - fio
            - --filename
            - /models/gemma-7b/model-00001-of-00004.safetensors:/models/gemma-7b/model-00002-of-00004.safetensors:/models/gemma-7b/model-00003-of-00004.safetensors:/models/gemma-7b/model-00004-of-00004.safetensors:/models/gemma-7b/model-00004-of-00004.safetensors
            - --direct=1
            - --rw=read
            - --readonly
            - --bs=4096k
            - --ioengine=libaio
            - --iodepth=8
            - --runtime=60
            - --numjobs=1
            - --name=read_benchmark
            volumeMounts:
            - mountPath: "/models"
              name: volume
          restartPolicy: Never
          volumes:
          - name: volume
            persistentVolumeClaim:
              claimName: hdml-static-pvc
      parallelism: 1         # Run 1 Pods concurrently
      completions: 1         # Once 1 Pods complete successfully, the Job is done
      backoffLimit: 1        # Max retries on failure
    

    CLAIM_NAME을 PersistentVolumeClaim 이름(예: hdml-static-pvc)으로 바꿉니다.

  2. 다음 명령어를 실행하여 작업을 만듭니다.

    kubectl apply -f benchmark-job.yaml.
    
  3. kubectl 로그를 사용하여 fio 도구의 출력을 확인합니다.

    kubectl logs benchmark-job-nrk88 -f
    

    결과는 다음과 유사합니다.

    read_benchmark: (g=0): rw=read, bs=4M-4M/4M-4M/4M-4M, ioengine=libaio, iodepth=8
    fio-2.2.10
    Starting 1 process
    
    read_benchmark: (groupid=0, jobs=1): err= 0: pid=32: Fri Jul 12 21:29:32 2024
    read : io=18300MB, bw=2407.3MB/s, iops=601, runt=  7602msec
        slat (usec): min=86, max=1614, avg=111.17, stdev=64.46
        clat (msec): min=2, max=33, avg=13.17, stdev= 1.08
        lat (msec): min=2, max=33, avg=13.28, stdev= 1.06
        clat percentiles (usec):
        |  1.00th=[11072],  5.00th=[12352], 10.00th=[12608], 20.00th=[12736],
        | 30.00th=[12992], 40.00th=[13120], 50.00th=[13248], 60.00th=[13376],
        | 70.00th=[13504], 80.00th=[13632], 90.00th=[13888], 95.00th=[14016],
        | 99.00th=[14400], 99.50th=[15296], 99.90th=[22144], 99.95th=[25728],
        | 99.99th=[33024]
        bw (MB  /s): min= 2395, max= 2514, per=100.00%, avg=2409.79, stdev=29.34
        lat (msec) : 4=0.39%, 10=0.31%, 20=99.15%, 50=0.15%
    cpu          : usr=0.28%, sys=8.08%, ctx=4555, majf=0, minf=8203
    IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=99.8%, 16=0.0%, 32=0.0%, >=64=0.0%
        submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
        complete  : 0=0.0%, 4=100.0%, 8=0.1%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
        issued    : total=r=4575/w=0/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0
        latency   : target=0, window=0, percentile=100.00%, depth=8
    
    Run status group 0 (all jobs):
    READ: io=18300MB, aggrb=2407.3MB/s, minb=2407.3MB/s, maxb=2407.3MB/s, mint=7602msec, maxt=7602msec
    
    Disk stats (read/write):
    nvme0n2: ios=71239/0, merge=0/0, ticks=868737/0, in_queue=868737, util=98.72%
    

Hyperdisk ML 볼륨의 처리량 또는 IOPS 모니터링

Hyperdisk ML 볼륨의 프로비저닝된 성능을 모니터링하려면 Compute Engine 문서의 프로비저닝된 IOPS 및 처리량 분석을 참조하세요.

기존 Hyperdisk ML 볼륨의 프로비저닝된 처리량 또는 IOPS를 업데이트하거나 StorageClass에서 지정할 수 있는 추가 Google Cloud Hyperdisk 매개변수에 대해 알아보려면 Google Cloud Hyperdisk를 사용하여 스토리지 성능 확장을 참조하세요.

문제 해결

이 섹션에서는 GKE에서 Hyperdisk ML 볼륨의 문제를 해결하는 방법을 안내합니다.

디스크 액세스 모드를 업데이트할 수 없음

Hyperdisk ML 볼륨이 이미 ReadWriteOnce 액세스 모드에서 노드에 의해 사용 및 연결된 경우 다음 오류가 발생합니다.

AttachVolume.Attach failed for volume ... Failed to update access mode:
failed to set access mode for zonal volume ...
'Access mode cannot be updated when the disk is attached to instance(s).'., invalidResourceUsage

GKE는 볼륨이 ReadOnlyMany 액세스 모드 PersistentVolume에서 사용되면 Hyperdisk ML 볼륨의 accessMode를 READ_WRITE_SINGLE에서 READ_ONLY_MANY로 자동 업데이트합니다. 이 업데이트는 디스크가 새 노드에 연결될 때 실행됩니다.

이 문제를 해결하려면 ReadWriteOnce 모드에서 PersistentVolume을 사용하여 디스크를 참조하는 포드를 모두 삭제합니다. 디스크가 분리될 때까지 기다린 다음 ReadOnlyMany 모드에서 PersistentVolume을 사용하는 워크로드를 다시 만듭니다.

디스크를 READ_WRITE 모드로 연결할 수 없음

다음 오류는 GKE가 ReadWriteOnce 액세스 모드를 사용하여 READ_ONLY_MANY 액세스 모드의 Hyperdisk ML 볼륨을 GKE 노드에 연결하려고 시도했음을 나타냅니다.

AttachVolume.Attach failed for volume ...
Failed to Attach: failed cloud service attach disk call ...
The disk cannot be attached with READ_WRITE mode., badRequest

GKE는 볼륨이 ReadOnlyMany 액세스 모드 PersistentVolume에서 사용되면 Hyperdisk ML 볼륨의 accessMode를 READ_WRITE_SINGLE에서 READ_ONLY_MANY로 자동 업데이트합니다. 하지만 GKE는 액세스 모드를 READ_ONLY_MANY에서 READ_WRITE_SINGLE로 자동 업데이트하지 않습니다. 이는 다중 영역 디스크에 실수로 기록되어 다중 영역 디스크 간에 콘텐츠가 서로 달라지지 않도록 방지하는 안전 메커니즘입니다.

이 문제를 해결하려면 업데이트된 콘텐츠가 필요한 경우 Persistent Disk 디스크 이미지에 데이터 사전 캐시 워크플로를 따르는 것이 좋습니다. Hyperdisk ML 볼륨의 액세스 모드 및 기타 설정을 더 세부적으로 제어해야 하는 경우 Google Cloud Hyperdisk 볼륨의 설정 수정을 참조하세요.

할당량 초과 - 처리량 할당량 부족

다음 오류는 디스크 프로비저닝 시 Hyperdisk ML 처리량 할당량이 부족했다는 의미입니다.

failed to provision volume with StorageClass ... failed (QUOTA_EXCEEDED): Quota 'HDML_TOTAL_THROUGHPUT' exceeded

이 문제를 해결하려면 디스크 할당량에서 Hyperdisk 할당량 및 프로젝트에서 디스크 할당량을 늘리는 방법을 자세히 알아보세요.

추가 문제 해결 안내는 Google Cloud Hyperdisk로 스토리지 성능 확장을 참조하세요.

다음 단계