GKE 멀티 클러스터 추론 게이트웨이 설정

이 문서에서는 여러 GKE 클러스터(서로 다른 리전에 걸쳐 있을 수 있음)에서 AI/ML 추론 워크로드를 지능적으로 부하 분산하도록 Google Kubernetes Engine(GKE) 멀티 클러스터 추론 게이트웨이를 설정하는 방법을 설명합니다. 이 설정은 게이트웨이 API, 멀티 클러스터 인그레스, InferencePoolInferenceObjective와 같은 커스텀 리소스를 사용하여 확장성을 개선하고, 고가용성을 보장하며, 모델 제공 배포의 리소스 사용률을 최적화합니다.

이 문서를 이해하려면 다음 사항을 숙지해야 합니다.

이 문서는 다음 사용자를 대상으로 합니다.

  • AI/ML 워크로드를 서빙하기 위해 GKE의 컨테이너 조정 기능을 사용하려는 머신러닝 (ML) 엔지니어, 플랫폼 관리자 및 운영자, 데이터 및 AI 전문가
  • GKE 네트워킹과 상호작용하는 클라우드 설계자 또는 네트워킹 전문가

Google Cloud 콘텐츠에서 참조하는 일반적인 역할과 예시 태스크에 대해 자세히 알아보려면 일반 GKE Enterprise 사용자 역할 및 태스크를 참고하세요.

시작하기 전에

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

  • Google Kubernetes Engine API를 사용 설정합니다.
  • Google Kubernetes Engine API 사용 설정
  • 이 태스크에 Google Cloud CLI를 사용하려면 gcloud CLI를 설치한 후 초기화합니다. 이전에 gcloud CLI를 설치했으면 gcloud components update 명령어를 실행하여 최신 버전을 가져옵니다. 이전 gcloud CLI 버전에서는 이 문서의 명령어를 실행하지 못할 수 있습니다.
  • Compute Engine API, Google Kubernetes Engine API, Model Armor, Network Services API를 사용 설정합니다.

    API 액세스 사용 설정으로 이동하여 안내를 따릅니다.

  • Autoscaling API를 사용 설정합니다.

    자동 확장 API로 이동하여 안내를 따릅니다.

  • Hugging Face 기본 요건:

    • Hugging Face 계정이 아직 없으면 이 계정을 만듭니다.
    • Hugging Face에서 Llama 3.1 모델에 대한 액세스를 요청하고 승인을 받습니다.
    • Hugging Face의 모델 페이지에서 라이선스 동의 계약에 서명합니다.
    • Read 이상의 권한이 있는 Hugging Face 액세스 토큰을 생성합니다.

요구사항

  • 프로젝트에 H100 GPU 할당량이 충분한지 확인합니다. 자세한 내용은 GPU 할당량 계획배정 할당량을 참고하세요.
  • GKE 버전 1.34.1-gke.1127000 이상을 사용합니다.
  • gcloud CLI 버전 480.0.0 이상을 사용합니다.
  • 노드 서비스 계정에는 Autoscaling API에 측정항목을 쓸 수 있는 권한이 있어야 합니다.
  • 프로젝트에 roles/container.adminroles/iam.serviceAccountAdmin IAM 역할이 있어야 합니다.

멀티 클러스터 추론 게이트웨이 설정

GKE 멀티 클러스터 추론 게이트웨이를 설정하려면 다음 단계를 따르세요.

클러스터 및 노드 풀 만들기

AI/ML 추론 워크로드를 호스팅하고 리전 간 부하 분산을 사용 설정하려면 서로 다른 리전에 각각 H100 GPU 노드 풀이 있는 GKE 클러스터 두 개를 만듭니다.

  1. 첫 번째 클러스터를 만듭니다.

    gcloud container clusters create CLUSTER_1_NAME \
        --region LOCATION \
        --project=PROJECT_ID \
        --gateway-api=standard \
        --release-channel "rapid" \
        --cluster-version=GKE_VERSION \
        --machine-type="MACHINE_TYPE" \
        --disk-type="DISK_TYPE" \
        --enable-managed-prometheus --monitoring=SYSTEM,DCGM \
        --hpa-profile=performance \
        --async # Allows the command to return immediately
    

    다음을 바꿉니다.

    • CLUSTER_1_NAME: 첫 번째 클러스터의 이름입니다(예: gke-west).
    • LOCATION: 첫 번째 클러스터의 리전(예: europe-west3)
    • PROJECT_ID: 프로젝트 ID입니다.
    • GKE_VERSION: 사용할 GKE 버전입니다(예: 1.34.1-gke.1127000).
    • MACHINE_TYPE: 클러스터 노드의 머신 유형입니다(예: c2-standard-16).
    • DISK_TYPE: 클러스터 노드의 디스크 유형입니다(예: pd-standard).
  2. 첫 번째 클러스터의 H100 노드 풀을 만듭니다.

    gcloud container node-pools create NODE_POOL_NAME \
        --accelerator "type=nvidia-h100-80gb,count=2,gpu-driver-version=latest" \
        --project=PROJECT_ID \
        --location=CLUSTER_1_ZONE \
        --node-locations=CLUSTER_1_ZONE \
        --cluster=CLUSTER_1_NAME \
        --machine-type=NODE_POOL_MACHINE_TYPE \
        --num-nodes=NUM_NODES \
        --spot \
        --async # Allows the command to return immediately
    

    다음을 바꿉니다.

    • NODE_POOL_NAME: 노드 풀의 이름입니다(예: h100).
    • PROJECT_ID: 프로젝트 ID입니다.
    • CLUSTER_1_ZONE: 첫 번째 클러스터의 영역입니다(예: europe-west3-c).
    • CLUSTER_1_NAME: 첫 번째 클러스터의 이름입니다(예: gke-west).
    • NODE_POOL_MACHINE_TYPE: 노드 풀의 머신 유형(예: a3-highgpu-2g)
    • NUM_NODES: 노드 풀의 노드 수입니다(예: 3).
  3. 사용자 인증 정보를 가져옵니다.

    gcloud container clusters get-credentials CLUSTER_1_NAME \
        --location CLUSTER_1_ZONE \
        --project=PROJECT_ID
    

    다음을 바꿉니다.

    • PROJECT_ID: 프로젝트 ID입니다.
    • CLUSTER_1_NAME: 첫 번째 클러스터의 이름입니다(예: gke-west).
    • CLUSTER_1_ZONE: 첫 번째 클러스터의 영역입니다(예: europe-west3-c).
  4. 첫 번째 클러스터에서 Hugging Face 토큰의 보안 비밀을 만듭니다.

    kubectl create secret generic hf-token \
        --from-literal=token=HF_TOKEN
    

    HF_TOKEN을 Hugging Face 액세스 토큰으로 바꿉니다.

  5. 첫 번째 클러스터와 다른 리전에 두 번째 클러스터를 만듭니다.

    gcloud container clusters create gke-east --region LOCATION \
        --project=PROJECT_ID \
        --gateway-api=standard \
        --release-channel "rapid" \
        --cluster-version=GKE_VERSION \
        --machine-type="MACHINE_TYPE" \
        --disk-type="DISK_TYPE" \
        --enable-managed-prometheus \
        --monitoring=SYSTEM,DCGM \
        --hpa-profile=performance \
        --async # Allows the command to return immediately while the
    cluster is created in the background.
    

    다음을 바꿉니다.

    • LOCATION: 두 번째 클러스터의 리전입니다. 이 리전은 첫 번째 클러스터와 다른 리전이어야 합니다. 예를 들면 us-east4입니다.
    • PROJECT_ID: 프로젝트 ID입니다.
    • GKE_VERSION: 사용할 GKE 버전입니다(예: 1.34.1-gke.1127000).
    • MACHINE_TYPE: 클러스터 노드의 머신 유형입니다(예: c2-standard-16).
    • DISK_TYPE: 클러스터 노드의 디스크 유형입니다(예: pd-standard).
  6. 두 번째 클러스터의 H100 노드 풀을 만듭니다.

    gcloud container node-pools create h100 \
        --accelerator "type=nvidia-h100-80gb,count=2,gpu-driver-version=latest" \
        --project=PROJECT_ID \
        --location=CLUSTER_2_ZONE \
        --node-locations=CLUSTER_2_ZONE \
        --cluster=CLUSTER_2_NAME \
        --machine-type=NODE_POOL_MACHINE_TYPE \
        --num-nodes=NUM_NODES \
        --spot \
        --async # Allows the command to return immediately
    

    다음을 바꿉니다.

    • PROJECT_ID: 프로젝트 ID입니다.
    • CLUSTER_2_ZONE: 두 번째 클러스터의 영역입니다(예: us-east4-a).
    • CLUSTER_2_NAME: 두 번째 클러스터의 이름입니다(예: gke-east).
    • NODE_POOL_MACHINE_TYPE: 노드 풀의 머신 유형(예: a3-highgpu-2g)
    • NUM_NODES: 노드 풀의 노드 수입니다(예: 3).
  7. 두 번째 클러스터의 경우 사용자 인증 정보를 가져오고 Hugging Face 토큰의 보안 비밀을 만듭니다.

    gcloud container clusters get-credentials CLUSTER_2_NAME \
        --location CLUSTER_2_ZONE \
        --project=PROJECT_ID
    
    kubectl create secret generic hf-token --from-literal=token=HF_TOKEN
    

    다음을 바꿉니다.

    • CLUSTER_2_NAME: 두 번째 클러스터의 이름입니다(예: gke-east).
    • CLUSTER_2_ZONE: 두 번째 클러스터의 영역입니다(예: us-east4-a).
    • PROJECT_ID: 프로젝트 ID입니다.
    • HF_TOKEN: Hugging Face 액세스 토큰입니다.

Fleet에 클러스터 등록

GKE 멀티 클러스터 추론 게이트웨이와 같은 멀티 클러스터 기능을 사용 설정하려면 클러스터를 Fleet에 등록하세요.

  1. 두 클러스터를 모두 프로젝트의 Fleet에 등록합니다.

    gcloud container fleet memberships register CLUSTER_1_NAME \
        --gke-cluster CLUSTER_1_ZONE/CLUSTER_1_NAME \
        --location=global \
        --project=PROJECT_ID
    
    gcloud container fleet memberships register CLUSTER_2_NAME \
        --gke-cluster CLUSTER_2_ZONE/CLUSTER_2_NAME \
        --location=global \
        --project=PROJECT_ID
    

    다음을 바꿉니다.

    • CLUSTER_1_NAME: 첫 번째 클러스터의 이름입니다(예: gke-west).
    • CLUSTER_1_ZONE: 첫 번째 클러스터의 영역입니다(예: europe-west3-c).
    • PROJECT_ID: 프로젝트 ID입니다.
    • CLUSTER_2_NAME: 두 번째 클러스터의 이름입니다(예: gke-east).
    • CLUSTER_2_ZONE: 두 번째 클러스터의 영역입니다(예: us-east4-a).
  2. 단일 게이트웨이가 여러 클러스터의 트래픽을 관리하도록 하려면 멀티 클러스터 인그레스 기능을 사용 설정하고 구성 클러스터를 지정하세요.

    gcloud container fleet ingress enable \
        --config-membership=projects/PROJECT_ID/locations/global/memberships/CLUSTER_1_NAME
    

    다음을 바꿉니다.

    • PROJECT_ID: 프로젝트 ID입니다.
    • CLUSTER_1_NAME: 첫 번째 클러스터의 이름입니다(예: gke-west).

프록시 전용 서브넷 만들기

내부 게이트웨이의 경우 각 리전에 프록시 전용 서브넷을 만듭니다. 내부 게이트웨이의 Envoy 프록시는 이러한 전용 서브넷을 사용하여 VPC 네트워크 내에서 트래픽을 처리합니다.

  1. 첫 번째 클러스터의 리전에 서브넷을 만듭니다.

    gcloud compute networks subnets create CLUSTER_1_REGION-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=CLUSTER_1_REGION \
        --network=default \
        --range=10.0.0.0/23 \
        --project=PROJECT_ID
    
  2. 두 번째 클러스터의 리전에 서브넷을 만듭니다.

    gcloud compute networks subnets create CLUSTER_2_REGION-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=CLUSTER_2_REGION \
        --network=default \
        --range=10.5.0.0/23 \
        --project=PROJECT_ID
    

    다음을 바꿉니다.

    • PROJECT_ID: 프로젝트 ID입니다.
    • CLUSTER_1_REGION: 첫 번째 클러스터의 리전(예: europe-west3)
    • CLUSTER_2_REGION: 두 번째 클러스터의 리전(예: us-east4)

필수 CRD 설치

GKE 멀티 클러스터 추론 게이트웨이는 InferencePoolInferenceObjective과 같은 커스텀 리소스를 사용합니다. GKE Gateway API 컨트롤러는 InferencePool 커스텀 리소스 정의 (CRD)를 관리합니다. 하지만 클러스터에 알파 버전인 InferenceObjective CRD를 수동으로 설치해야 합니다.

  1. 클러스터의 컨텍스트 변수를 정의합니다.

    CLUSTER1_CONTEXT="gke_PROJECT_ID_CLUSTER_1_ZONE_CLUSTER_1_NAME"
    CLUSTER2_CONTEXT="gke_PROJECT_ID_CLUSTER_2_ZONE_CLUSTER_2_NAME"
    

    다음을 바꿉니다.

    • PROJECT_ID: 프로젝트 ID입니다.
    • CLUSTER_1_ZONE: 첫 번째 클러스터의 영역입니다(예: europe-west3-c).
    • CLUSTER_1_NAME: 첫 번째 클러스터의 이름입니다(예: gke-west).
    • CLUSTER_2_ZONE: 두 번째 클러스터의 영역입니다(예: us-east4-a).
    • CLUSTER_2_NAME: 두 번째 클러스터의 이름입니다(예: gke-east).
  2. 두 클러스터 모두에 InferenceObjective CRD를 설치합니다.

    # Copyright 2025 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #      http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    apiVersion: admissionregistration.k8s.io/v1
    kind: ValidatingAdmissionPolicy
    metadata:
      name: restrict-toleration
    spec:
      failurePolicy: Fail
      paramKind:
        apiVersion: v1
        kind: ConfigMap
      matchConstraints:
        # GKE will mutate any pod specifying a CC label in a nodeSelector
        # or in a nodeAffinity with a toleration for the CC node label.
        # Mutation hooks will always mutate the K8s object before validating
        # the admission request.  
        # Pods created by Jobs, CronJobs, Deployments, etc. will also be validated.
        # See https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#admission-control-phases for details
        resourceRules:
        - apiGroups:   [""]
          apiVersions: ["v1"]
          operations:  ["CREATE", "UPDATE"]
          resources:   ["pods"]
      matchConditions:
        - name: 'match-tolerations'
          # Validate only if compute class toleration exists
          # and the CC label tolerated is listed in the configmap.
          expression: > 
            object.spec.tolerations.exists(t, has(t.key) &&
            t.key == 'cloud.google.com/compute-class' &&
            params.data.computeClasses.split('\\n').exists(cc, cc == t.value))
      validations:
        # ConfigMap with permitted namespace list referenced via `params`.
        - expression: "params.data.namespaces.split('\\n').exists(ns, ns == object.metadata.namespace)"
          messageExpression: "'Compute class toleration not permitted on workloads in namespace ' + object.metadata.namespace"
    
    ---
    apiVersion: admissionregistration.k8s.io/v1
    kind: ValidatingAdmissionPolicyBinding
    metadata:
      name: restrict-toleration-binding
    spec:
      policyName: restrict-toleration
      validationActions: ["Deny"]
      paramRef:
        name: allowed-ccc-namespaces
        namespace: default
        parameterNotFoundAction: Deny
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: allowed-ccc-namespaces
      namespace: default
    data:
      # Replace example namespaces in line-separated list below.
      namespaces: |
        foo
        bar
        baz
      # ComputeClass names to monitor with this validation policy.
      # The 'autopilot' and 'autopilot-spot' CCs are present on
      # all NAP Standard and Autopilot clusters.
      computeClasses: |
        MY_COMPUTE_CLASS
        autopilot
        autopilot-spot
    
    
    kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.1.0/config/crd/bases/inference.networking.x-k8s.io_inferenceobjectives.yaml --context=CLUSTER1_CONTEXT
    
    kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.1.0/config/crd/bases/inference.networking.x-k8s.io_inferenceobjectives.yaml --context=CLUSTER2_CONTEXT
    

    다음을 바꿉니다.

    • CLUSTER1_CONTEXT: 첫 번째 클러스터의 컨텍스트입니다(예: gke_my-project_europe-west3-c_gke-west).
    • CLUSTER2_CONTEXT: 두 번째 클러스터의 컨텍스트입니다(예: gke_my-project_us-east4-a_gke-east).

대상 클러스터에 리소스 배포

각 클러스터에서 AI/ML 추론 워크로드를 사용할 수 있도록 모델 서버 및 InferenceObjective 커스텀 리소스와 같은 필수 리소스를 배포합니다.

  1. 두 클러스터에 모델 서버를 배포합니다.

    kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.1.0/config/manifests/vllm/gpu-deployment.yaml --context=CLUSTER1_CONTEXT
    
    kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.1.0/config/manifests/vllm/gpu-deployment.yaml --context=CLUSTER2_CONTEXT
    

    다음을 바꿉니다.

    • CLUSTER1_CONTEXT: 첫 번째 클러스터의 컨텍스트(예: gke_my-project_europe-west3-c_gke-west)
    • CLUSTER2_CONTEXT: 두 번째 클러스터의 컨텍스트입니다(예: gke_my-project_us-east4-a_gke-east).
  2. 두 클러스터에 InferenceObjective 리소스를 배포합니다. 다음 샘플 매니페스트를 inference-objective.yaml이라는 파일에 저장합니다.

    apiVersion: inference.networking.x-k8s.io/v1alpha2
    kind: InferenceObjective
    metadata:
      name: food-review
    spec:
      priority: 10
      poolRef:
        name: llama3-8b-instruct
        group: "inference.networking.k8s.io"
    
  3. 두 클러스터에 모두 매니페스트를 적용합니다.

    kubectl apply -f inference-objective.yaml --context=CLUSTER1_CONTEXT
    kubectl apply -f inference-objective.yaml --context=CLUSTER2_CONTEXT
    

    다음을 바꿉니다.

    • CLUSTER1_CONTEXT: 첫 번째 클러스터의 컨텍스트(예: gke_my-project_europe-west3-c_gke-west)
    • CLUSTER2_CONTEXT: 두 번째 클러스터의 컨텍스트입니다(예: gke_my-project_us-east4-a_gke-east).
  4. Helm을 사용하여 두 클러스터에 InferencePool 리소스를 배포합니다.

    helm install vllm-llama3-8b-instruct \
      --kube-context CLUSTER1_CONTEXT \
      --set inferencePool.modelServers.matchLabels.app=vllm-llama3-8b-instruct \
      --set provider.name=gke \
      --version v1.1.0 \
      oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepool
    
    helm install vllm-llama3-8b-instruct \
      --kube-context CLUSTER2_CONTEXT \
      --set inferencePool.modelServers.matchLabels.app=vllm-llama3-8b-instruct \
      --set provider.name=gke \
      --set inferenceExtension.monitoring.gke.enabled=true \
      --version v1.1.0 \
      oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepool
    

    다음을 바꿉니다.

    • CLUSTER1_CONTEXT: 첫 번째 클러스터의 컨텍스트입니다(예: gke_my-project_europe-west3-c_gke-west).
    • CLUSTER2_CONTEXT: 두 번째 클러스터의 컨텍스트입니다(예: gke_my-project_us-east4-a_gke-east).
  5. 두 클러스터에서 InferencePool 리소스를 내보낸 것으로 표시합니다. 이 주석을 사용하면 구성 클러스터에서 InferencePool를 가져올 수 있으며 이는 멀티 클러스터 라우팅에 필요한 단계입니다.

    kubectl annotate inferencepool vllm-llama3-8b-instruct networking.gke.io/export="True" \
        --context=CLUSTER1_CONTEXT
    
    kubectl annotate inferencepool vllm-llama3-8b-instruct networking.gke.io/export="True" \
        --context=CLUSTER2_CONTEXT
    

    다음을 바꿉니다.

    • CLUSTER1_CONTEXT: 첫 번째 클러스터의 컨텍스트입니다(예: gke_my-project_europe-west3-c_gke-west).
    • CLUSTER2_CONTEXT: 두 번째 클러스터의 컨텍스트입니다(예: gke_my-project_us-east4-a_gke-east).

구성 클러스터에 리소스 배포

등록된 모든 클러스터의 InferencePool 리소스 간에 트래픽이 라우팅되고 부하 분산되는 방식을 정의하려면 Gateway, HTTPRoute, HealthCheckPolicy 리소스를 배포합니다. 이러한 리소스는 이 문서에서 gke-west인 지정된 구성 클러스터에만 배포합니다.

  1. 다음 콘텐츠로 mcig.yaml이라는 파일을 만듭니다.

    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: cross-region-gateway
      namespace: default
    spec:
      gatewayClassName: gke-l7-cross-regional-internal-managed-mc
      addresses:
      - type: networking.gke.io/ephemeral-ipv4-address/europe-west3
        value: "europe-west3"
      - type: networking.gke.io/ephemeral-ipv4-address/us-east4
        value: "us-east4"
      listeners:
      - name: http
        protocol: HTTP
        port: 80
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: vllm-llama3-8b-instruct-default
    spec:
      parentRefs:
      - name: cross-region-gateway
        kind: Gateway
      rules:
      - backendRefs:
        - group: networking.gke.io
          kind: GCPInferencePoolImport
          name: vllm-llama3-8b-instruct
    ---
    apiVersion: networking.gke.io/v1
    kind: HealthCheckPolicy
    metadata:
      name: health-check-policy
      namespace: default
    spec:
      targetRef:
        group: "networking.gke.io"
        kind: GCPInferencePoolImport
        name: vllm-llama3-8b-instruct
      default:
        config:
          type: HTTP
          httpHealthCheck:
            requestPath: /health
            port: 8000
    
  2. 매니페스트를 적용합니다.

    kubectl apply -f mcig.yaml --context=CLUSTER1_CONTEXT
    

    CLUSTER1_CONTEXT을 첫 번째 클러스터(구성 클러스터)의 컨텍스트로 바꿉니다(예: gke_my-project_europe-west3-c_gke-west).

맞춤 측정항목 보고 사용 설정

맞춤 측정항목 보고를 사용 설정하고 교차 리전 부하 분산을 개선하려면 모든 클러스터에서 KV 캐시 사용량 측정항목을 내보냅니다. 부하 분산기는 내보낸 KV 캐시 사용 데이터를 맞춤 부하 신호로 사용합니다. 이 맞춤 부하 신호를 사용하면 각 클러스터의 실제 워크로드를 기반으로 더 지능적인 부하 분산 결정을 내릴 수 있습니다.

  1. 다음 콘텐츠로 metrics.yaml이라는 파일을 만듭니다.

    apiVersion: autoscaling.gke.io/v1beta1
    kind: AutoscalingMetric
    metadata:
      name: gpu-cache
      namespace: default
    spec:
      selector:
        matchLabels:
          app: vllm-llama3-8b-instruct
      endpoints:
      - port: 8000
        path: /metrics
        metrics:
        - name: vllm:kv_cache_usage_perc # For vLLM versions v0.10.2 and newer
          exportName: kv-cache
        - name: vllm:gpu_cache_usage_perc # For vLLM versions v0.6.2 and newer
          exportName: kv-cache-old
    
  2. 두 클러스터 모두에 측정항목 구성을 적용합니다.

    kubectl apply -f metrics.yaml --context=CLUSTER1_CONTEXT
    kubectl apply -f metrics.yaml --context=CLUSTER2_CONTEXT
    

    다음을 바꿉니다.

    • CLUSTER1_CONTEXT: 첫 번째 클러스터의 컨텍스트입니다(예: gke_my-project_europe-west3-c_gke-west).
    • CLUSTER2_CONTEXT: 두 번째 클러스터의 컨텍스트입니다(예: gke_my-project_us-east4-a_gke-east).

부하 분산 정책 구성

AI/ML 추론 요청이 GKE 클러스터에 분산되는 방식을 최적화하려면 부하 분산 정책을 구성하세요. 적절한 균형 모드를 선택하면 리소스 사용률을 효율적으로 유지하고, 개별 클러스터의 과부하를 방지하며, 추론 서비스의 전반적인 성능과 응답성을 개선할 수 있습니다.

제한 시간 구성

요청의 기간이 길 것으로 예상되는 경우 부하 분산기의 제한 시간을 더 길게 구성합니다. GCPBackendPolicy에서 timeoutSec 필드를 예상 P99 요청 지연 시간의 2배 이상으로 설정합니다.

예를 들어 다음 매니페스트는 부하 분산기 제한 시간을 100초로 설정합니다.

apiVersion: networking.gke.io/v1
kind: GCPBackendPolicy
metadata:
  name: my-backend-policy
spec:
  targetRef:
    group: "networking.gke.io"
    kind: GCPInferencePoolImport
    name: vllm-llama3-8b-instruct
  default:
    timeoutSec: 100
    balancingMode: CUSTOM_METRICS
    trafficDuration: LONG
    customMetrics:
    - name: gke.named_metrics.kv-cache
      dryRun: false

자세한 내용은 멀티 클러스터 게이트웨이 제한사항을 참고하세요.

맞춤 측정항목진행 중인 요청 부하 분산 모드는 상호 배타적이므로 GCPBackendPolicy에서 이러한 모드 중 하나만 구성하세요.

배포의 부하 분산 모드를 선택합니다.

커스텀 측정항목

최적의 부하 분산을 위해 대상 사용률을 60%로 시작하세요. 이 타겟을 달성하려면 GCPBackendPolicycustomMetrics 구성에서 maxUtilization: 60를 설정하세요.

  1. 다음 콘텐츠로 backend-policy.yaml이라는 파일을 만들어 kv-cache 맞춤 측정항목을 기반으로 부하 분산을 사용 설정합니다.

    apiVersion: networking.gke.io/v1
    kind: GCPBackendPolicy
    metadata:
      name: my-backend-policy
    spec:
      targetRef:
        group: "networking.gke.io"
        kind: GCPInferencePoolImport
        name: vllm-llama3-8b-instruct
      default:
        balancingMode: CUSTOM_METRICS
        trafficDuration: LONG
        customMetrics:
          - name: gke.named_metrics.kv-cache
            dryRun: false
            maxUtilization: 60
    
  2. 새 정책을 적용합니다.

    kubectl apply -f backend-policy.yaml --context=CLUSTER1_CONTEXT
    

    CLUSTER1_CONTEXT을 첫 번째 클러스터의 컨텍스트(예: gke_my-project-europe-west3-c-gke-west)로 바꿉니다.

진행 중인 요청

전송 중 분산 모드를 사용하려면 각 백엔드에서 처리할 수 있는 전송 중 요청 수를 추정하고 용량 값을 명시적으로 구성하세요.

  1. 다음 콘텐츠로 backend-policy.yaml라는 파일을 만들어 진행 중인 요청 수를 기반으로 부하 분산을 사용 설정합니다.

    kind: GCPBackendPolicy
    apiVersion: networking.gke.io/v1
    metadata:
      name: my-backend-policy
    spec:
      targetRef:
        group: "networking.gke.io"
        kind: GCPInferencePoolImport
        name: vllm-llama3-8b-instruct
      default:
        balancingMode: IN_FLIGHT
        trafficDuration: LONG
        maxInFlightRequestsPerEndpoint: 1000
        dryRun: false
    
  2. 새 정책을 적용합니다.

    kubectl apply -f backend-policy.yaml --context=CLUSTER1_CONTEXT
    

    CLUSTER1_CONTEXT을 첫 번째 클러스터의 컨텍스트(예: gke_my-project_europe-west3-c_gke-west)로 바꿉니다.

배포를 확인합니다.

내부 부하 분산기는 비공개 IP 주소를 사용하므로 내부 부하 분산기를 확인하려면 VPC 네트워크 내에서 요청을 보내야 합니다. 클러스터 중 하나 내에서 임시 포드를 실행하여 VPC 네트워크에서 요청을 보내고 내부 부하 분산기를 확인합니다.

  1. 임시 포드에서 대화형 셸 세션을 시작합니다.

    kubectl run -it --rm --image=curlimages/curl curly --context=CLUSTER1_CONTEXT -- /bin/sh
    

    CLUSTER1_CONTEXT을 첫 번째 클러스터의 컨텍스트(예: gke_my-project_europe-west3-c_gke-west)로 바꿉니다.

  2. 새 셸에서 게이트웨이 IP 주소를 가져오고 테스트 요청을 보냅니다.

    GW_IP=$(kubectl get gateway/cross-region-gateway -n default -o jsonpath='{.status.addresses[0].value}')
    
    curl -i -X POST ${GW_IP}:80/v1/completions -H 'Content-Type: application/json' -d '{
    "model": "food-review-1",
    "prompt": "What is the best pizza in the world?",
    "max_tokens": 100,
    "temperature": 0
    }'
    

    다음은 성공적인 응답의 예입니다.

    {
      "id": "cmpl-...",
      "object": "text_completion",
      "created": 1704067200,
      "model": "food-review-1",
      "choices": [
        {
          "text": "The best pizza in the world is subjective, but many argue for Neapolitan pizza...",
          "index": 0,
          "logprobs": null,
          "finish_reason": "length"
        }
      ],
      "usage": {
        "prompt_tokens": 10,
        "completion_tokens": 100,
        "total_tokens": 110
      }
    }
    

다음 단계