Kueue를 사용한 일괄 시스템 배포


이 튜토리얼에서는 Kueue를 사용해 일괄 시스템을 배포하여 Google Kubernetes Engine (GKE)의 큐에 추가된 작업을 수행하는 방법을 보여줍니다. 이 튜토리얼을 완료하여 선입 선출(FIFO) 모델에서 작업을 실행하도록 GKE 및 Kueue를 설정하는 방법을 알아보세요.

배경

작업은 머신러닝, 렌더링, 시뮬레이션, 분석, CI/CD 및 유사한 워크로드 등 완료될 때까지 실행되는 애플리케이션입니다.

Kueue는 기본 Kubernetes 스케줄러, 작업 컨트롤러, 클러스터 자동 확장 처리와 함께 작동하여 엔드 투 엔드 일괄 시스템을 제공하는 클라우드 네이티브 작업 스케줄러입니다. Kueue는 작업을 큐에 추가하여 여러 팀 간에 리소스가 공정하게 공유되도록 할당량과 계층 구조에 따라 작업의 대기 시기 및 시작 시기를 결정합니다.

Kueue의 특징은 다음과 같습니다.

  • 리소스가 여러 다른 종류로 이루어지며 교환 및 확장이 가능한 클라우드 아키텍처에 최적화되어 있습니다.
  • 탄력적인 할당량을 관리하고 작업을 큐에 추가하는 것을 관리할 수 있는 API 집합을 제공합니다.
  • 자동 확장, 포드 예약, 작업 수명 주기 관리와 같은 기존 기능은 다시 구현되지 않습니다.
  • Kueue에는 Kubernetes batch/v1.Job API가 기본적으로 지원됩니다.
  • 다른 작업 API와 통합할 수 있습니다.

Kueue는 특정 Kubernetes Job API와 혼동되지 않도록 모든 API로 정의된 작업을 워크로드로 참조합니다.

목표

이 튜토리얼은 Kubernetes에서 일괄 시스템을 구현하려는 클러스터 운영자 및 기타 사용자를 대상으로 합니다. 이 튜토리얼에서는 두 테넌트 팀의 공유 클러스터를 설정합니다. 팀마다 작업을 만들고 해당하는 할당량으로 제어되는 동일한 전역 리소스를 공유하는 자체 네임스페이스가 있습니다.

이 가이드는 다음 과정을 다룹니다.

  1. GKE 클러스터 만들기
  2. ResourceFlavor 만들기
  3. ClusterQueue 만들기
  4. LocalQueue 만들기
  5. 작업을 만들고 허용된 워크로드 관찰하기

비용

이 튜토리얼에서는 다음과 같은 Google Cloud 구성요소를 사용하며 여기에는 비용이 청구될 수 있습니다.

가격 계산기를 사용하여 예상 사용량을 기준으로 예상 비용을 산출합니다.

이 튜토리얼을 마친 후 비용이 계속 청구되지 않도록 자신이 만든 리소스를 삭제하세요. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

프로젝트 설정

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

    Go to project selector

  3. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  4. GKE API 사용 설정

    API 사용 설정

  5. In the Google Cloud console, on the project selector page, click Create project to begin creating a new Google Cloud project.

    Go to project selector

  6. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  7. GKE API 사용 설정

    API 사용 설정

Google Cloud CLI 기본값 설정

  1. Google Cloud 콘솔에서 Cloud Shell 인스턴스를 시작합니다.
    Cloud Shell 열기

  2. 이 샘플 앱의 소스 코드를 다운로드합니다.

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    cd kubernetes-engine-samples/batch/kueue-intro
    
  3. 기본 환경 변수를 설정합니다.

    gcloud config set project PROJECT_ID
    gcloud config set compute/region COMPUTE_REGION
    

    다음 값을 바꿉니다.

GKE 클러스터 만들기

  1. kueue-autopilot이라는 GKE Autopilot 클러스터를 만듭니다.

    gcloud container clusters create-auto kueue-autopilot \
      --release-channel "rapid" --region COMPUTE_REGION
    

    Autopilot 클러스터는 완전 관리형이며 자동 확장이 기본 제공됩니다. GKE Autopilot에 대해 자세히 알아보세요.

    Kueue는 노드 자동 프로비저닝 및 일반 자동 확장 노드 풀이 있는 GKE Standard도 지원합니다.

    클러스터가 생성된 후의 결과는 다음과 비슷합니다.

      NAME: kueue-autopilot
      LOCATION: us-central1
      MASTER_VERSION: 1.26.2-gke.1000
      MASTER_IP: 35.193.173.228
      MACHINE_TYPE: e2-medium
      NODE_VERSION: 1.26.2-gke.1000
      NUM_NODES: 3
      STATUS: RUNNING
    

    여기서 kueue-autopilotSTATUSRUNNING입니다.

  2. 클러스터의 사용자 인증 정보를 가져옵니다.

    gcloud container clusters get-credentials kueue-autopilot
    
  3. 클러스터에 Kueue를 설치합니다.

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

    VERSION을 Kueue의 최신 버전으로 바꿉니다. Kueue 버전에 대한 자세한 내용은 Kueue 출시를 참조하세요.

  4. Kueue 포드가 준비될 때까지 기다립니다.

    watch kubectl -n kueue-system get pods
    

    계속하려면 다음과 비슷한 출력이 표시되어야 합니다.

    NAME                                        READY   STATUS    RESTARTS   AGE
    kueue-controller-manager-66d8bb946b-wr2l2   2/2     Running   0          3m36s
    
  5. team-ateam-b라는 새 네임스페이스 2개를 만듭니다.

    kubectl create namespace team-a
    kubectl create namespace team-b
    

ResourceFlavor 만들기

ResourceFlavor는 노드 라벨 및 taint를 연결하여 클러스터에서 사용 가능한 노드의 변형을 나타내는 객체입니다. 예를 들어 ResourceFlavor를 사용하여 다양한 프로비저닝 보장(예: 스팟 vs 주문형), 아키텍처(예: x86 vs ARM CPU), 브랜드 및 모델(예: Nvidia A100 vs T4 GPU)의 VM을 나타낼 수 있습니다.

이 튜토리얼에서는kueue-autopilot 클러스터에 동종 리소스가 있습니다. 따라서 라벨 또는 taint 없이 CPU, 메모리, 임시 스토리지, GPU에 대해 단일 ResourceFlavor를 만듭니다.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: default-flavor # This ResourceFlavor will be used for all the resources
ResourceFlavor를 배포합니다.

kubectl apply -f flavors.yaml

ClusterQueue 만들기

ClusterQueue는 CPU, 메모리, GPU와 같은 리소스 풀을 관리하는 클러스터 범위 객체입니다. ResourceFlavor를 관리하고, 사용량을 제한하며, 워크로드가 허용되는 순서를 지정합니다.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  name: cluster-queue
spec:
  namespaceSelector: {} # Available to all namespaces
  queueingStrategy: BestEffortFIFO # Default queueing strategy
  resourceGroups:
  - coveredResources: ["cpu", "memory", "nvidia.com/gpu", "ephemeral-storage"]
    flavors:
    - name: "default-flavor"
      resources:
      - name: "cpu"
        nominalQuota: 10
      - name: "memory"
        nominalQuota: 10Gi
      - name: "nvidia.com/gpu"
        nominalQuota: 10
      - name: "ephemeral-storage"
        nominalQuota: 10Gi

ClusterQueue를 배포합니다.

kubectl apply -f cluster-queue.yaml

소비 순서는 .spec.queueingStrategy에 의해 결정되며, 두 가지 구성이 있습니다.

  • BestEffortFIFO

    • 기본 큐 추가 전략 구성입니다.
    • 워크로드 허용은 선입 선출(FIFO) 규칙을 따르지만 큐 맨 위에 워크로드를 허용하기에 할당량이 충분하지 않으면 줄의 다음 항목이 시도됩니다.
  • StrictFIFO

    • FIFO 시맨틱스를 보장합니다.
    • 큐 맨 위에 있는 워크로드는 워크로드가 허용될 수 있을 때까지 큐 추가를 차단할 수 있습니다.

cluster-queue.yaml에서 cluster-queue라는 새 ClusterQueue를 만듭니다. 이 ClusterQueue는 flavors.yaml에서 생성된 버전으로 cpu, memory, nvidia.com/gpu, ephemeral-storage의 4개 리소스를 관리합니다. 이 할당량은 워크로드 포드 사양의 요청에서 사용됩니다.

각 버전에는 .spec.resourceGroups[].flavors[].resources[].nominalQuota으로 표현되는 사용량 한도가 포함됩니다. 여기에서는 ClusterQueue가 다음과 같은 경우에만 워크로드를 허용합니다.

  • CPU 요청 합계가 10보다 작거나 같습니다.
  • 메모리 요청 합계가 10Gi보다 작거나 같습니다.
  • GPU 요청 합계가 10보다 작거나 같습니다.
  • 사용한 스토리지의 합계가 10Gi보다 작거나 같습니다.

LocalQueue 만들기

LocalQueue는 네임스페이스에 있는 사용자의 워크로드를 허용하는 네임스페이스 객체입니다. 다른 네임스페이스의 LocalQueue가 리소스 할당량을 공유할 수 있는 동일한 ClusterQueue를 가리킬 수 있습니다. 이 경우 네임스페이스 team-ateam-b의 LocalQueue가 .spec.clusterQueue 아래의 동일한 ClusterQueue cluster-queue를 가리킵니다.

apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: team-a # LocalQueue under team-a namespace
  name: lq-team-a
spec:
  clusterQueue: cluster-queue # Point to the ClusterQueue
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: team-b # LocalQueue under team-b namespace
  name: lq-team-b
spec:
  clusterQueue: cluster-queue # Point to the ClusterQueue

각 팀에서 자체 네임스페이스의 LocalQueue에 워크로드를 전송합니다. 그러면 ClusterQueue가 리소스를 할당합니다.

LocalQueue를 배포합니다.

kubectl apply -f local-queue.yaml

작업을 만들고 허용된 워크로드 관찰하기

apiVersion: batch/v1
kind: Job
metadata:
  namespace: team-a # Job under team-a namespace
  generateName: sample-job-team-a-
  annotations:
    kueue.x-k8s.io/queue-name: lq-team-a # Point to the LocalQueue
spec:
  ttlSecondsAfterFinished: 60 # Job will be deleted after 60 seconds
  parallelism: 3 # This Job will have 3 replicas running at the same time
  completions: 3 # This Job requires 3 completions
  suspend: true # Set to true to allow Kueue to control the Job when it starts
  template:
    spec:
      nodeSelector:
        cloud.google.com/gke-accelerator: "nvidia-tesla-t4" # Specify the GPU hardware
      containers:
      - name: dummy-job
        image: gcr.io/k8s-staging-perf-tests/sleep:latest
        args: ["10s"] # Sleep for 10 seconds
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
            ephemeral-storage: "512Mi"
            nvidia.com/gpu: "1"
          limits:
            cpu: "500m"
            memory: "512Mi"
            ephemeral-storage: "512Mi"
            nvidia.com/gpu: "1"
      restartPolicy: Never

작업은 team-a 네임스페이스 아래에 생성됩니다. 이 작업은 LocalQueue lq-team-a를 가리킵니다. GPU 리소스를 요청하려면 nodeSelectornvidia-tesla-t4로 설정됩니다.

작업은 10초 동안 동시에 절전 모드로 전환되는 3개의 포드로 구성됩니다. ttlSecondsAfterFinished에 따라 60초 후에 작업이 삭제됩니다.

이 작업에는 포드가 3개 있으므로 1,500milliCPU, 메모리 1,536Mi, 임시 스토리지 1,536Mi, GPU 3개가 필요합니다.

또한 네임스페이스가 team-b에 속하는 job-team-b.yaml 파일 아래에 작업이 생성되고, 서로 다른 요구사항을 가진 다른 팀을 나타내는 요청이 포함됩니다.

자세한 내용은 Autopilot에서 GPU 워크로드 배포를 참조하세요.

  1. 새 터미널에서 2초마다 새로고침되는 ClusterQueue 상태를 관찰합니다.

    watch -n 2 kubectl get clusterqueue cluster-queue -o wide
    
  2. 새 터미널에서 노드 상태를 관찰합니다.

    watch -n 2 kubectl get nodes -o wide
    
  3. 새 터미널에서 10초마다 네임스페이스 team-ateam-b에서 LocalQueue에 대한 작업을 만듭니다.

    ./create_jobs.sh job-team-a.yaml job-team-b.yaml 10
    
  4. 큐에 추가되고 ClusterQueue에 허용된 작업, GKE Autopilot을 사용해 가져온 노드를 관찰합니다.

  5. team-a 네임스페이스에서 작업을 가져옵니다.

    kubectl -n team-a get jobs
    

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

    NAME                      COMPLETIONS   DURATION   AGE
    sample-job-team-b-t6jnr   3/3           21s        3m27s
    sample-job-team-a-tm7kc   0/3                      2m27s
    sample-job-team-a-vjtnw   3/3           30s        3m50s
    sample-job-team-b-vn6rp   0/3                      40s
    sample-job-team-a-z86h2   0/3                      2m15s
    sample-job-team-b-zfwj8   0/3                      28s
    sample-job-team-a-zjkbj   0/3                      4s
    sample-job-team-a-zzvjg   3/3           83s        4m50s
    
  6. 이전 단계에서 작업 이름을 복사하고 Workloads API를 통해 작업의 허용 상태와 이벤트를 관찰합니다.

    kubectl -n team-a describe workload JOB_NAME
    
  7. 대기 중인 작업이 ClusterQueue에서 증가하기 시작하면 실행 중인 스크립트에서 CTRL + C를 눌러 스크립트를 종료합니다.

  8. 모든 작업이 완료되면 노드가 축소되는 것을 확인할 수 있습니다.

삭제

이 튜토리얼에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요.

프로젝트 삭제

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

    리소스 관리로 이동

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

개별 리소스 삭제

  1. Kueue 할당량 시스템을 삭제합니다.

    kubectl delete -n team-a localqueue lq-team-a
    kubectl delete -n team-b localqueue lq-team-b
    kubectl delete clusterqueue cluster-queue
    kubectl delete resourceflavor default-flavor
    
  2. Kueue 매니페스트를 삭제합니다.

    VERSION=VERSION
    kubectl delete -f \
      https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/manifests.yaml
    
  3. 다음과 같이 클러스터를 삭제합니다.

    gcloud container clusters delete kueue-autopilot --region=COMPUTE_REGION
    

다음 단계