동적 워크로드 스케줄러를 사용하여 일괄 워크로드용 GPU 배포


이 페이지에서는 동적 워크로드 스케줄러 및 ProvisioningRequest를 사용하여 GPU가 포함된 대규모 일괄 워크로드의 GPU 가용성을 최적화하는 방법을 보여줍니다.

정의된 GPU 용량 관리 조건으로 오프 피크타임에 실행할 수 있는 대규모 일괄 워크로드에 동적 워크로드 스케줄러를 사용하는 것이 좋습니다. 이러한 워크로드는 딥 러닝 모델 학습이거나 원자적 프로비저닝 모델이 포함된 대량의 GPU가 필요한 시뮬레이션일 수 있습니다. 즉, 모든 리소스가 동시에 생성됩니다.

동적 워크로드 스케줄러 없이 Google Kubernetes Engine(GKE)에서 GPU 워크로드를 실행하려면 GKE Standard 노드 풀에서 GPU 실행을 참조하세요.

동적 워크로드 스케줄러를 사용해야 하는 경우

워크로드가 다음 조건을 모두 충족하는 경우 동적 워크로드 스케줄러를 사용하는 것이 좋습니다.

  • 워크로드 실행을 위해 GPU를 요청합니다.
  • 예약된 GPU 용량이 제한되거나 없고 GPU 리소스의 획득 가능성을 높이려는 경우
  • 워크로드가 시간에 구애받지 않으며 사용 사례는 GKE에서 사용량이 가장 많은 시간 외에 GPU 리소스를 할당하는 경우와 같이 요청된 모든 용량을 얻을 때까지 대기할 수 있습니다.
  • 워크로드에 여러 노드가 필요하며 모든 GPU 노드가 프로비저닝되고 동시에 준비될 때까지 실행을 시작할 수 없습니다(예: 분산형 머신러닝 학습).

시작하기 전에

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

  • Google Kubernetes Engine API를 사용 설정합니다.
  • Google Kubernetes Engine API 사용 설정
  • 이 태스크에 Google Cloud CLI를 사용하려면 gcloud CLI를 설치한 후 초기화합니다. 이전에 gcloud CLI를 설치한 경우 gcloud components update를 실행하여 최신 버전을 가져옵니다.

동적 워크로드 스케줄러에서 노드 풀 사용

다음 세 가지 방법 중 하나를 사용하여 동적 워크로드 스케줄러가 클러스터의 특정 노드 풀에서 작동하도록 지정할 수 있습니다.

노드 풀 만들기

gcloud CLI를 사용하여 동적 워크로드 스케줄러가 사용 설정된 노드 풀을 만듭니다.

gcloud beta container node-pools create NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
     --enable-queued-provisioning \
    --accelerator type=GPU_TYPE,count=AMOUNT,gpu-driver-version=DRIVER_VERSION \
    --machine-type=MACHINE_TYPE \
    --enable-autoscaling  \
    --num-nodes=0   \
    --total-max-nodes TOTAL_MAX_NODES  \
    --location-policy=ANY  \
    --reservation-affinity=none  \
    --no-enable-autorepair

다음을 바꿉니다.

  • NODEPOOL_NAME: 선택한 노드 풀의 이름입니다.
  • CLUSTER_NAME: 클러스터의 이름
  • LOCATION: 클러스터의 Compute Engine 리전입니다(예: us-central1).
  • GPU_TYPE: GPU 유형입니다.
  • AMOUNT: 노드 풀의 노드에 연결할 GPU 수입니다.
  • DRIVER_VERSION: 설치할 NVIDIA 드라이버 버전입니다. 다음 중 하나일 수 있습니다.
    • default: GKE 버전의 기본 드라이버 버전을 설치합니다.
    • latest: GKE 버전에 사용 가능한 최신 드라이버 버전을 설치합니다. Container-Optimized OS를 사용하는 노드에서만 사용할 수 있습니다.
  • TOTAL_MAX_NODES: 전체 노드 풀에 대해 자동으로 확장되는 최대 노드 수입니다.
  • MACHINE_TYPE: 노드의 Compute Engine 머신 유형입니다. Accelerator 최적화 머신 유형을 선택하는 것이 좋습니다.

선택적으로 다음 플래그를 사용할 수 있습니다.

  • --no-enable-autoupgrade: 권장. 노드 자동 업그레이드를 사용 중지합니다. 출시 채널에 등록되지 않은 GKE 클러스터에서만 지원됩니다. 자세한 내용은 기존 노드 풀의 노드 자동 업그레이드 사용 중지를 참조하세요.
  • --node-locations=COMPUTE_ZONES: GKE가 GPU 노드를 만드는 하나 이상의 영역을 쉼표로 구분한 목록입니다. 영역은 클러스터와 동일한 리전에 있어야 합니다. 사용 가능한 GPU가 있는 영역을 선택합니다.
  • --enable-gvnic: 이 플래그는 GPU 노드 풀에서 gVNIC를 사용 설정하여 네트워크 트래픽 속도를 높입니다.

이 명령어는 다음 구성을 사용하여 노드 풀을 만듭니다.

  • GKE를 사용하면 큐에 추가된 프로비저닝 및 클러스터 자동 확장을 사용 설정할 수 있습니다.
  • 노드 풀에는 처음에 노드가 0개 있습니다.
  • --enable-queued-provisioning 플래그는 동적 워크로드 스케줄러를 사용 설정하고 노드 풀에 cloud.google.com/gke-queued taint를 추가합니다.
  • --no-enable-autorepair--no-enable-autoupgrade 플래그는 노드의 자동 복구 및 업그레이드를 사용 중지하므로 복구되거나 업그레이드된 노드에서 실행되는 워크로드가 중단될 수 있습니다. 출시 채널에 등록되지 않은 클러스터에서만 노드 자동 업그레이드를 사용 중지할 수 있습니다.

기존 노드 풀 업데이트 및 동적 워크로드 스케줄러 사용 설정

기존 노드 풀에 동적 워크로드 스케줄러를 사용 설정합니다. 노드 풀을 올바르게 구성하기 위해 기본 요건을 검토합니다.

기본 요건

  • --reservation-affinity=none 플래그로 노드 풀을 만들어야 합니다. 노드 풀 생성 후에는 예약 어피니티를 변경할 수 없으므로 이 플래그는 나중에 동적 워크로드 스케줄러를 사용 설정할 때 필요합니다.

  • 클러스터가 올바르게 작동하려면 동적 워크로드 스케줄러 처리를 사용 설정하지 않은 상태에서 노드 풀을 최소 하나 이상 유지해야 합니다.

  • 노드 풀이 비어 있는지 확인합니다. 노드가 0이 되도록 노드 풀의 크기를 조절할 수 있습니다.

  • 자동 확장이 사용 설정되어 있고 올바르게 구성되어 있는지 확인합니다.

  • 자동 복구가 사용 중지되어 있는지 확인합니다.

기존 노드 풀에 동적 워크로드 스케줄러 사용 설정

gcloud CLI를 사용하여 기존 노드 풀에 동적 워크로드 스케줄러를 사용 설정할 수 있습니다.

gcloud beta container node-pools update NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
     --enable-queued-provisioning

다음을 바꿉니다.

  • NODEPOOL_NAME: 선택한 노드 풀의 이름
  • CLUSTER_NAME: 클러스터의 이름
  • LOCATION: 클러스터의 Compute Engine 리전(예: us-central1)

이 노드 풀 업데이트 명령어는 다음과 같은 구성 변경사항을 적용합니다.

  • --enable-queued-provisioning 플래그는 동적 워크로드 스케줄러를 사용 설정하고 노드 풀에 cloud.google.com/gke-queued taint를 추가합니다.

필요한 경우 다음 노드 풀 설정을 업데이트할 수도 있습니다.

  • 노드 자동 업그레이드 사용 중지: 동적 워크로드 스케줄러를 사용하는 경우 노드 풀 업그레이드가 지원되지 않으므로 노드 자동 업그레이드를 사용 중지하는 것이 좋습니다. 노드 자동 업그레이드를 사용 중지하려면 GKE 클러스터가 출시 채널에 등록되지 않았는지 확인합니다.
  • GPU 노드 풀에서 gVNIC 사용 설정: Google Virtual NIC(gVNIC)는 GPU 노드의 네트워크 트래픽 속도를 높입니다.

동적 워크로드 스케줄러의 노드 풀을 만들기 위해 노드 자동 프로비저닝 사용 설정

노드 자동 프로비저닝을 사용하여 버전 1.29.2-gke.1553000 이상이 실행되는 클러스터에 대해 동적 워크로드 스케줄러의 노드 풀을 관리할 수 있습니다. 노드 자동 프로비저닝을 사용 설정하고 동적 워크로드 스케줄러를 사용 설정하면 GKE가 연결된 워크로드에 필요한 리소스로 노드 풀을 만듭니다.

노드 자동 프로비저닝을 사용 설정하려면 다음 설정을 고려하고 GPU 한도 구성의 단계를 완료합니다.

동적 워크로드 스케줄러를 사용하여 일괄 워크로드 실행

동적 워크로드 스케줄러를 사용하려면 Kueue를 사용하는 것이 좋습니다. Kueue는 작업을 큐에 추가하여 여러 팀 간에 리소스가 공정하게 공유되도록 할당량과 계층 구조에 따라 작업의 대기 시기 및 시작 시기를 결정합니다. 따라서 큐에 추가된 VM을 사용하는 데 필요한 설정이 간소화됩니다.

자체 내부 일괄 예약 도구 또는 플랫폼을 사용할 때는 Kueue 없는 동적 워크로드 스케줄러를 사용할 수 있습니다. Kueue 없는 작업에 대해 동적 워크로드 스케줄러를 구성하려면 Kueue 없는 작업에 대한 동적 워크로드 스케줄러를 참조하세요.

Kueue 있는 작업에 대한 동적 워크로드 스케줄러

다음 섹션에서는 Kueue를 포함하는 작업에 대한 동적 워크로드 스케줄러를 구성하는 방법을 보여줍니다. 다음과 같은 일반적인 노드 풀 설정을 구성할 수 있습니다.

  • 동적 워크로드 스케줄러 노드 풀 설정
  • 예약 및 동적 워크로드 스케줄러 노드 풀 설정

이 섹션에서는 ai-on-gke 저장소의 dws-examples 디렉터리에 있는 샘플을 사용합니다. Google은 Apache2 라이선스에 따라 dws-examples 디렉터리에 샘플을 게시했습니다.

개발 환경 준비

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

    git clone https://github.com/GoogleCloudPlatform/ai-on-gke
    cd ai-on-gke/tutorials-and-examples/workflow-orchestration/dws-examples
    
  2. 클러스터에 최신 Kueue 버전을 설치합니다.

    VERSION=v0.7.0
    kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/manifests.yaml
    

Kueue 설치에 대한 자세한 내용은 설치를 참조하세요.

동적 워크로드 스케줄러 노드 풀 전용 설정용 Kueue 리소스 만들기

다음 매니페스트를 사용하여 dws-cluster-queue라는 클러스터 수준 큐dws-local-queue라는 LocalQueue 네임스페이스를 만듭니다. 이 네임스페이스에서 dws-cluster-queue 큐를 참조하는 작업은 동적 워크로드 스케줄러를 사용하여 GPU 리소스를 가져옵니다.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: "default-flavor"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: AdmissionCheck
metadata:
  name: dws-prov
spec:
  controllerName: kueue.x-k8s.io/provisioning-request
  parameters:
    apiGroup: kueue.x-k8s.io
    kind: ProvisioningRequestConfig
    name: dws-config
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ProvisioningRequestConfig
metadata:
  name: dws-config
spec:
  provisioningClassName: queued-provisioning.gke.io
  managedResources:
  - nvidia.com/gpu
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  name: "dws-cluster-queue"
spec:
  namespaceSelector: {} 
  resourceGroups:
  - coveredResources: ["cpu", "memory", "nvidia.com/gpu"]
    flavors:
    - name: "default-flavor"
      resources:
      - name: "cpu"
        nominalQuota: 10000  # Infinite quota.
      - name: "memory"
        nominalQuota: 10000Gi # Infinite quota.
      - name: "nvidia.com/gpu"
        nominalQuota: 10000  # Infinite quota.
  admissionChecks:
  - dws-prov
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: "default"
  name: "dws-local-queue"
spec:
  clusterQueue: "dws-cluster-queue"
---

LocalQueue를 배포합니다.

kubectl create -f ./dws-queues.yaml

출력은 다음과 비슷합니다.

resourceflavor.kueue.x-k8s.io/default-flavor created
admissioncheck.kueue.x-k8s.io/dws-prov created
provisioningrequestconfig.kueue.x-k8s.io/dws-config created
clusterqueue.kueue.x-k8s.io/dws-cluster-queue created
localqueue.kueue.x-k8s.io/dws-local-queue created

다른 네임스페이스에서 동적 워크로드 스케줄러를 사용하는 작업을 실행하려면 위의 템플릿을 사용하여 추가 LocalQueues를 만들 수 있습니다.

작업 실행

다음 매니페스트에서 샘플 작업은 동적 워크로드 스케줄러를 사용합니다.

apiVersion: batch/v1
kind: Job
metadata:
  name: sample-job
  namespace: default
  labels:
    kueue.x-k8s.io/queue-name: dws-local-queue
  annotations:
    provreq.kueue.x-k8s.io/maxRunDurationSeconds: "600"
spec:
  parallelism: 1
  completions: 1
  suspend: true
  template:
    spec:
      nodeSelector:
        cloud.google.com/gke-nodepool: NODEPOOL_NAME
      tolerations:
      - key: "nvidia.com/gpu"
        operator: "Exists"
        effect: "NoSchedule"
      containers:
      - name: dummy-job
        image: gcr.io/k8s-staging-perf-tests/sleep:v0.0.3
        args: ["120s"]
        resources:
          requests:
            cpu: "100m"
            memory: "100Mi"
            nvidia.com/gpu: 1
          limits:
            cpu: "100m"
            memory: "100Mi"
            nvidia.com/gpu: 1
      restartPolicy: Never

이 매니페스트에는 동적 워크로드 스케줄러 구성과 관련된 다음 필드가 포함됩니다.

  • kueue.x-k8s.io/queue-name: dws-local-queue 라벨은 Kueue가 해당 작업을 조정할 책임이 있다는 것을 GKE에 알려줍니다. 이 라벨은 작업이 대기 중인 큐도 정의합니다.
  • suspend: true 플래그는 GKE에 작업 리소스를 만들지만 포드를 아직 예약하지 않도록 지시합니다. 노드가 작업을 실행할 준비가 되면 Kueue는 해당 플래그를 false로 변경합니다.
  • nodeSelector는 지정된 노드 풀에서만 작업을 예약하도록 GKE에 지시합니다. 이 값은 큐에 추가된 프로비저닝이 사용 설정된 노드 풀의 이름인 NODEPOOL_NAME과 일치해야 합니다.
  1. 작업을 실행합니다.

    kubectl create -f ./job.yaml
    

    출력은 다음과 비슷합니다.

    job.batch/sample-job created
    
  2. 작업 상태를 확인합니다.

    kubectl describe job sample-job
    

    출력은 다음과 비슷합니다.

    Events:
      Type    Reason            Age    From                        Message
      ----    ------            ----   ----                        -------
      Normal  Suspended         5m17s  job-controller              Job suspended
      Normal  CreatedWorkload   5m17s  batch/job-kueue-controller  Created Workload: default/job-sample-job-7f173
      Normal  Started           3m27s  batch/job-kueue-controller  Admitted by clusterQueue dws-cluster-queue
      Normal  SuccessfulCreate  3m27s  job-controller              Created pod: sample-job-9qsfd
      Normal  Resumed           3m27s  job-controller              Job resumed
      Normal  Completed         12s    job-controller              Job completed
    

또한 Kueue가 통합된 동적 워크로드 스케줄러는 다음과 같이 오픈소스 생태계에서 사용할 수 있는 다른 워크로드 유형도 지원합니다.

  • RayJob
  • JobSet v0.5.2 이상
  • Kubeflow MPIJob, TFJob, PyTorchJob.
  • 워크플로 조정자가 자주 사용하는 Kubernetes 포드
  • Flux 미니 클러스터

이 지원에 대한 자세한 내용은 Kueue의 일괄 사용자를 참조하세요.

예약 및 동적 워크로드 스케줄러 노드 풀 설정용 Kueue 리소스 만들기

다음 매니페스트를 사용하여 두 개의 서로 다른 노드 풀(reservation-nodepooldws-nodepool)에 연결된 두 개의 ResourceFlavors를 만들 수 있습니다. 이러한 노드 풀의 이름은 예시적인 이름일 뿐입니다. 노드 풀 구성에 따라 이러한 이름을 수정합니다. 또한 ClusterQueue 구성을 사용하면 수신되는 작업이 reservation-nodepool을 사용하려고 시도하고, 용량이 없으면 이러한 작업에서 동적 워크로드 스케줄러를 사용하여 GPU 리소스를 가져옵니다.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: "reservation"
spec:
  nodeLabels:
    cloud.google.com/gke-nodepool: "reservation-nodepool" # placeholder value
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: "dws"
spec:
  nodeLabels:
    cloud.google.com/gke-nodepool: "dws-nodepool" # placeholder value
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  name: "cluster-queue"
spec:
  namespaceSelector: {} # match all.
  resourceGroups:
  - coveredResources: ["cpu", "memory", "nvidia.com/gpu"]
    flavors:
    - name: "reservation" # first we try reservation
      resources:
      - name: "cpu"
        nominalQuota: 9
      - name: "memory"
        nominalQuota: 36Gi
      - name: "nvidia.com/gpu"
        nominalQuota: 9
    - name: "dws"         # if reservation is saturated we try dws
      resources:
      - name: "cpu"
        nominalQuota: 10000   # Infinite quota.
      - name: "memory"
        nominalQuota: 10000Gi # Infinite quota.
      - name: "nvidia.com/gpu"
        nominalQuota: 10000   # Infinite quota.
  admissionChecksStrategy:
    admissionChecks:
      - name: "dws-prov"
        onFlavors: [dws]
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: "default"
  name: "user-queue"
spec:
  clusterQueue: "cluster-queue"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: AdmissionCheck
metadata:
  name: dws-prov
spec:
  controllerName: kueue.x-k8s.io/provisioning-request
  parameters:
    apiGroup: kueue.x-k8s.io
    kind: ProvisioningRequestConfig
    name: dws-config
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ProvisioningRequestConfig
metadata:
  name: dws-config
spec:
  provisioningClassName: queued-provisioning.gke.io
  managedResources:
  - nvidia.com/gpu

다음 명령어를 사용하여 매니페스트를 배포합니다.

kubectl create -f ./dws_and_reservation.yaml

출력은 다음과 비슷합니다.

resourceflavor.kueue.x-k8s.io/reservation created
resourceflavor.kueue.x-k8s.io/dws created
clusterqueue.kueue.x-k8s.io/cluster-queue created
localqueue.kueue.x-k8s.io/user-queue created
admissioncheck.kueue.x-k8s.io/dws-prov created
provisioningrequestconfig.kueue.x-k8s.io/dws-config created

작업 실행

이전 설정과 달리 이 매니페스트에는 nodeSelector 필드가 포함되지 않으며, ClusterQueue의 여유 용량에 따라 Kueue에서 해당 필드를 채웁니다.

apiVersion: batch/v1
kind: Job
metadata:
  generateName: sample-job-
  namespace: default
  labels:
    kueue.x-k8s.io/queue-name: user-queue
  annotations:
    provreq.kueue.x-k8s.io/maxRunDurationSeconds: "600"
spec:
  parallelism: 1
  completions: 1
  suspend: true
  template:
    spec:
      tolerations:
      - key: "nvidia.com/gpu"
        operator: "Exists"
        effect: "NoSchedule"
      containers:
      - name: dummy-job
        image: gcr.io/k8s-staging-perf-tests/sleep:v0.0.3
        args: ["120s"]
        resources:
          requests:
            cpu: "100m"
            memory: "100Mi"
            nvidia.com/gpu: 1
          limits:
            cpu: "100m"
            memory: "100Mi"
            nvidia.com/gpu: 1
      restartPolicy: Never
  1. 작업을 실행합니다.

    kubectl create -f ./job-without-node-selector.yaml
    

    출력은 다음과 비슷합니다.

    job.batch/sample-job-v8xwm created
    

작업에서 사용하는 노드 풀을 찾으려면 작업에서 사용하는 ResourceFlavor를 알아야 합니다.

문제 해결

Kueue 문제 해결에 대한 자세한 내용은 Kueue에서 프로비저닝 요청 문제 해결을 참조하세요.

Kueue 없는 작업의 동적 워크로드 스케줄러

각 작업에 대한 ProvisioningRequest API를 통해 요청을 만듭니다. 동적 워크로드 스케줄러는 포드를 시작하지 않고, 노드만 프로비저닝합니다.

  1. 다음 provisioning-request.yaml 매니페스트를 만듭니다.

    apiVersion: v1
    kind: PodTemplate
    metadata:
      name: POD_TEMPLATE_NAME
      namespace: NAMESPACE_NAME
      labels:
        cloud.google.com/apply-warden-policies: "true"
    template:
      spec:
        nodeSelector:
            cloud.google.com/gke-nodepool: NODEPOOL_NAME
        tolerations:
            - key: "nvidia.com/gpu"
              operator: "Exists"
              effect: "NoSchedule"
        containers:
            - name: pi
              image: perl
              command: ["/bin/sh"]
              resources:
                limits:
                  cpu: "700m"
                  nvidia.com/gpu: 1
                requests:
                  cpu: "700m"
                  nvidia.com/gpu: 1
        restartPolicy: Never
    ---
    apiVersion: autoscaling.x-k8s.io/v1beta1
    kind: ProvisioningRequest
    metadata:
      name: PROVISIONING_REQUEST_NAME
      namespace: NAMESPACE_NAME
    spec:
      provisioningClassName: queued-provisioning.gke.io
      parameters:
        maxRunDurationSeconds: "MAX_RUN_DURATION_SECONDS"
      podSets:
      - count: COUNT
        podTemplateRef:
          name: POD_TEMPLATE_NAME
    

    다음을 바꿉니다.

    • NAMESPACE_NAME: Kubernetes 네임스페이스 이름입니다. 네임스페이스는 포드 네임스페이스와 동일해야 합니다.
    • PROVISIONING_REQUEST_NAME: ProvisioningRequest 이름입니다. 포드 주석에서 이 이름을 참조합니다.
    • MAX_RUN_DURATION_SECONDS: 선택적으로 노드의 최대 런타임(초 단위)이며 기본값은 7일까지입니다. 자세한 내용은 동적 워크로드 스케줄러의 작동 방식을 참조하세요. 요청을 만든 후에는 이 값을 변경할 수 없습니다. 이 필드는 GKE 버전 1.28.5-gke.1355000 이상의 미리보기에서 사용할 수 있습니다.
    • COUNT: 요청된 포드 수입니다. 노드는 하나의 영역에 원자적으로 예약됩니다.
    • POD_TEMPLATE_NAME: Kubernetes의 표준 이름입니다. 프로비저닝 요청 PodSet에서 이 값에 대한 GKE 참조입니다.
    • NODEPOOL_NAME: 선택한 노드 풀의 이름입니다.
  1. 매니페스트를 적용합니다.

    kubectl apply -f provisioning-request.yaml
    

포드 구성

작업 사양에서 다음 주석을 사용하여 포드를 ProvisioningRequest에 연결합니다.

apiVersion: batch/v1
kind: Job
spec:
  template:
    metadata:
      annotations:
        cluster-autoscaler.kubernetes.io/consume-provisioning-request: PROVISIONING_REQUEST_NAME
        cluster-autoscaler.kubernetes.io/provisioning-class-name: "queued-provisioning.gke.io"
    spec:
      ...

포드 주석 키 cluster-autoscaler.kubernetes.io/consume-provisioning-request는 사용할 ProvisioningRequest를 정의합니다. GKE는 consume-provisioning-requestprovisioning-class-name 주석을 사용하여 다음을 수행합니다.

  • 동적 워크로드 스케줄러로 프로비저닝된 노드에서만 포드를 예약합니다.
  • 클러스터 자동 확장 처리에서 포드와 동적 워크로드 스케줄러 간의 리소스 요청 중복을 방지합니다.
  • safe-to-evict: false 주석을 삽입하여 클러스터 자동 확장 처리가 노드 간에 포드를 이동하고 일괄 계산을 중단하지 않도록 합니다. 포드 주석에서 safe-to-evict: true를 지정하여 이 동작을 변경할 수 있습니다.

동적 워크로드 스케줄러 상태 관찰

동적 워크로드 스케줄러의 상태는 포드를 예약할 수 있는지 여부를 정의합니다. Kubernetes 감시를 사용하여 변경사항을 효율적으로 관찰하거나 Kubernetes 객체의 상태 추적에 이미 사용하는 다른 도구를 사용할 수 있습니다. 다음 표에서는 동적 워크로드 스케줄러의 가능한 상태와 가능한 각 결과를 설명합니다.

동적 워크로드 스케줄러 상태 설명 가능한 결과
대기 중 요청이 아직 확인 및 처리되지 않았습니다. 처리 후 요청이 Accepted 또는 Failed 상태로 전환됩니다.
Accepted=true 요청이 수락되어 리소스를 사용할 수 있을 때까지 기다리는 중입니다. 리소스가 발견되었고 노드가 프로비저닝된 경우 요청이 Provisioned 상태로 전환되고, 불가능한 경우 Failed 상태로 전환됩니다.
Provisioned=true 노드가 준비되었습니다. 10분 안에 포드를 시작하여 프로비저닝된 리소스를 소비해야 합니다. 이 시간이 지나면 클러스터 자동 확장 처리에서 노드를 필요하지 않은 것으로 간주하여 삭제합니다.
Failed=true 오류로 인해 노드를 프로비저닝할 수 없습니다. Failed=true는 종결 상태입니다. 조건의 ReasonMessage 필드에 있는 정보를 기준으로 조건 문제를 해결합니다. 새 동적 워크로드 스케줄러 요청을 만들고 다시 시도합니다.
Provisioned=false 노드가 아직 프로비저닝되지 않았습니다.

Reason=NotProvisioned인 경우 모든 리소스를 사용할 수 있기 전의 임시 상태입니다.

Reason=QuotaExceeded인 경우 이 이유와 조건의 Message 필드에 있는 정보를 기준으로 조건 문제를 해결합니다. 할당량을 추가로 요청해야 할 수 있습니다. 자세한 내용은 동적 워크로드 스케줄러가 할당량으로 제한되는지 확인 섹션을 참조하세요. 이 Reason은 GKE 버전 1.29.2-gke.1181000 이상에서만 사용할 수 있습니다.

포드 시작

동적 워크로드 스케줄러 요청이 Provisioned=true 상태에 도달하면 작업을 실행하여 포드를 시작할 수 있습니다. 이렇게 하면 kube-scheduler 및 클러스터 자동 확장 처리 성능에 영향을 줄 수 있는 대기 또는 실패한 요청에 예약할 수 없는 포드가 확산되는 것을 방지할 수 있습니다.

또는 예약할 수 없는 포드가 있어도 무방하다면 동적 워크로드 스케줄러와 동시에 포드를 만들 수 있습니다.

동적 워크로드 스케줄러 요청 취소

요청이 프로비저닝되기 전에 취소하려면 ProvisioningRequest를 삭제하면 됩니다.

kubectl delete provreq PROVISIONING_REQUEST_NAME -n NAMESPACE

대부분의 경우 ProvisioningRequest를 삭제하면 노드 생성이 중지됩니다. 하지만 상황에 따라(예: 노드가 이미 프로비저닝된 경우) 노드가 계속 생성될 수 있습니다. 이러한 경우 포드가 생성되지 않으면 클러스터 자동 확장 처리는 10분 후에 노드를 삭제합니다.

동적 워크로드 스케줄러의 작동 방식

ProvisioningRequest API를 사용하여 동적 워크로드 스케줄러는 다음을 수행합니다.

  1. 모든 필수 노드를 한 번에 사용할 준비가 될 때까지 워크로드가 확정되지 않은 시간 동안 기다릴 수 있다고 GKE에 알려줍니다.
  2. 클러스터 자동 확장 처리는 요청을 수락하고 필요한 노드 수를 계산하여 단일 단위로 처리합니다.
  3. 이 요청은 필요한 모든 리소스를 단일 영역에서 사용할 수 있을 때까지 기다립니다. 1.29.1-gke.1708000 이상 버전을 실행하는 클러스터의 경우 대기 시간을 줄이기 위해 사용 가능한 용량에 관한 정보를 사용하여 이 영역이 선택됩니다. 이전 버전을 실행하는 클러스터의 경우 이 정보 없이 영역이 선택되었으므로 대기 시간이 훨씬 더 긴 영역에서 큐가 발생할 수 있습니다.
  4. 클러스터 자동 확장 처리는 사용 가능한 경우 필요한 노드를 한 번에 프로비저닝합니다.
  5. 워크로드의 모든 포드는 새로 프로비저닝된 노드에서 함께 실행될 수 있습니다.
  6. maxRunDurationSeconds 매개변수를 설정하여 워크로드를 실행하는 데 더 적은 시간이 필요함을 나타내는 경우 프로비저닝된 노드는 런타임이 7일 이내로 제한됩니다. 자세한 내용은 VM 런타임 제한(미리보기)을 참조하세요. 이 기능은 GKE 버전 1.28.5-gke.1355000 이상에서 사용할 수 있습니다. 그 이후에는 노드와 노드에서 실행되는 포드가 선점됩니다. 포드가 더 빨리 완료되고 노드가 사용되지 않으면 클러스터 자동 확장 처리는 자동 확장 프로필에 따라 노드를 삭제합니다.
  7. 노드는 동적 워크로드 스케줄러 간에 재사용되지 않습니다. 각 ProvisioningRequest는 새로운 7일 런타임으로 새 노드 생성을 주문합니다.

할당량

동적 워크로드 스케줄러 요청으로 프로비저닝된 모든 VM은 선점형 할당량을 사용합니다.

Accepted 상태인 ProvisioningRequests의 개수는 전용 할당량으로 제한됩니다. 프로젝트마다 할당량을 구성하며 리전별로 하나의 할당량 구성이 있습니다.

Google Cloud 콘솔에서 할당량 확인

Google Cloud 콘솔에서 할당량 한도의 이름 및 현재 사용량을 확인하려면 다음 단계를 수행합니다.

  1. Google Cloud 콘솔의 할당량 페이지로 이동합니다.

    할당량으로 이동

  2. 필터 상자에서 측정항목 속성을 선택하고 active_resize_requests를 입력한 다음 Enter 키를 누릅니다.

기본값은 100입니다. 할당량을 늘리려면 할당량 한도 상향 요청 가이드에 나열된 단계를 따르세요.

동적 워크로드 스케줄러가 할당량으로 제한되는지 확인

동적 워크로드 스케줄러 요청이 처리되는 데 예상보다 오래 걸리는 경우 요청이 할당량으로 제한되지 않는지 확인합니다. 할당량을 추가로 요청해야 할 수 있습니다.

버전 1.29.2-gke.1181000 이상을 실행하는 클러스터의 경우 특정 할당량 제한으로 인해 요청이 처리되지 않는지 확인합니다.

kubectl describe provreq PROVISIONING_REQUEST_NAME \
    --namespace NAMESPACE

출력은 다음과 유사합니다.

…
Last Transition Time:  2024-01-03T13:56:08Z
    Message:               Quota 'NVIDIA_P4_GPUS' exceeded. Limit: 1.0 in region europe-west4.
    Observed Generation:   1
    Reason:                QuotaExceeded
    Status:                False
    Type:                  Provisioned
…

이 예시에서는 europe-west4 리전에 할당량이 충분하지 않으므로 GKE가 노드를 배포할 수 없습니다.

동적 워크로드 스케줄러를 사용하여 워크로드가 있는 노드 풀에 대한 중단 설정 구성

노드 풀에서 모든 노드 또는 대부분의 노드의 가용성이 필요한 워크로드는 제거에 민감합니다. ProvisioningRequest API를 사용하여 프로비저닝된 노드의 자동 복구 또는 업그레이드는 지원되지 않으며, 이는 이러한 작업이 해당 노드에서 실행 중인 모든 워크로드를 삭제하고 워크로드를 예약할 수 없게 만들기 때문입니다.

동적 워크로드 스케줄러를 사용하여 워크로드 실행 중단을 최소화하려면 다음 조치를 취하는 것이 좋습니다.

  • 클러스터의 출시 채널 등록에 따라 노드 자동 업그레이드로 인해 워크로드가 중단되지 않도록 다음 권장사항을 따르세요.
  • 노드 자동 복구를 사용 중지합니다.
  • 유지보수 기간 및 제외를 사용하여 실행 중인 워크로드의 중단을 최소화하고 GKE에서 자동 유지보수를 위해 노드 풀을 중단할 수 있는 기간을 확보합니다. 이러한 유지보수 도구를 사용하는 경우 GKE가 노드 풀을 중단할 수 있는 특정 기간을 설정해야 하므로 실행 중인 워크로드가 없을 때 이 기간을 설정하는 것이 좋습니다.
  • 노드 풀을 최신 상태로 유지하려면 활성 동적 워크로드 스케줄러 요청이 없고 노드 풀이 비어 있는 경우 노드 풀을 수동으로 업그레이드하는 것이 좋습니다.

제한사항

  • 포드 간 안티-어피니티는 지원되지 않습니다. 클러스터 자동 확장 처리는 노드 프로비저닝 중에 포드 간 안티어피니티 규칙을 고려하지 않으므로 워크로드를 예약하지 못할 수 있습니다. 이 문제는 2개 이상의 동적 워크로드 스케줄러 객체의 노드가 동일한 노드 풀에 프로비저닝된 경우에 발생할 수 있습니다.
  • GPU 노드만 지원됩니다.
  • 동적 워크로드 스케줄러에서는 예약이 지원되지 않습니다. 노드 풀을 만들 때 --reservation-affinity=none을 지정해야 합니다. 동적 워크로드 스케줄러는 클러스터 자동 확장의 ANY 위치 정책만 필요로 하고 지원합니다.
  • 단일 동적 워크로드 스케줄러 요청은 단일 노드 풀의 영역당 최대 노드 수인 VM을 최대 1000개까지 만들 수 있습니다.
  • GKE는 Compute Engine ACTIVE_RESIZE_REQUESTS 할당량을 사용하여 큐에서 대기 중인 동적 워크로드 스케줄러 요청 수를 제어합니다. 기본적으로 이 할당량은 Google Cloud 프로젝트 수준에서 100개로 제한됩니다. 이 할당량을 초과하는 동적 워크로드 스케줄러 요청을 만들려고 하면 새 요청이 실패합니다.
  • 동적 워크로드 스케줄러를 사용하는 노드 풀은 노드가 함께 프로비저닝되므로 중단에 민감합니다. 자세한 내용은 동적 워크로드 스케줄러를 사용하여 워크로드가 있는 노드 풀에 대한 중단 설정 구성을 참조하세요.
  • Google Cloud 콘솔에 나열된 추가 단기 VM이 표시될 수 있습니다. 이 동작은 필요한 모든 머신을 프로비저닝할 수 있는 용량을 사용할 수 있을 때까지 Compute Engine이 VM을 만들고 즉시 삭제할 수 있기 때문입니다.
  • 동적 워크로드 스케줄러 통합은 PodSet를 하나만 지원합니다. 여러 포드 템플릿을 혼합하려면 가장 많은 리소스를 요청한 템플릿을 사용합니다. 서로 다른 GPU 유형이 있는 VM과 같이 서로 다른 머신 유형을 혼합하는 것은 지원되지 않습니다.

다음 단계