토폴로지 인지 워크로드 스케줄링(TAS)

토폴로지 인지 워크로드 스케줄링(TAS)

분산 AI·ML 트레이닝처럼 파드 사이 통신 지연을 최소화해야 하는 워크로드는, 파드들이 서로 멀리 흩어져 있으면 성능이 크게 떨어져요. 이때 쓸 수 있는 게 Workload API의 Topology-Aware Scheduling(토폴로지 인지 스케줄링, 줄여서 TAS)이에요. 같은 PodGroup 안의 모든 파드를 특정 토폴로지 도메인(예: 서버 랙이나 존) 안에 함께 배치해, 파드 간 통신 지연을 줄이고 워크로드가 인프라 곳곳으로 조각나는 걸 막아 줘요. 이 기능은 쿠버네티스 v1.36부터 알파로 들어왔고 기본적으로는 꺼져 있어요.

출처: 쿠버네티스 공식 문서 — Topology-Aware Workload Scheduling

gang 스케줄링 정책과 함께 쓰기

gang 스케줄링 정책을 쓰는 PodGroup에 TAS를 적용하면, 스케줄러가 전체 파드 그룹의 배치(placement)를 한 번에 시뮬레이션해요. 리소스를 확정하기 전에 지정된 minCount만큼의 파드가 같은 토폴로지 도메인에 함께 들어갈 수 있는지를 보장하는 거예요. 분산 AI·ML 트레이닝처럼 파드 근접성이 엄격히 요구되는 워크로드에 권장되는 방식이에요.

파드가 이미 스케줄된 PodGroup에 새 파드가 추가되면(예: 파드가 다시 만들어지는 경우), 스케줄러는 새로 들어오는 모든 파드를 기존 파드가 살고 있는 바로 그 토폴로지 도메인에 강제로 배치해요. 그 도메인에 새 파드를 받을 용량이 부족하면, 아예 minCount보다 적은 파드가 스케줄되더라도 그 파드들은 pending으로 남아요.

참고

v1.36 기준으로 TAS는 워크로드나 파드의 선점(preemption)을 트리거하지 않아요. 선점 없이 실현 가능한 배치를 찾지 못하면 PodGroup은 스케줄 불가(unschedulable) 상태가 돼요.

basic 스케줄링 정책과 함께 쓰기

basic 정책과 함께 TAS를 쓰면 동작이 일관적이지 않을 수 있어요. 스케줄러가 PodGroup 스케줄링 사이클에 들어갈 때 파드의 일부만 관찰할 수 있어서, 배치 가능성도 전체 PodGroup이 아니라 관찰된 파드들에 대해서만 평가되거든요. 이 제약을 부분적으로 완화하려면 스케줄링 게이트를 써서, PodGroup 안의 모든 파드가 스케줄링 큐에 들어올 때까지 PodGroup 스케줄링을 보류시킬 수 있어요. 전체 PodGroup에 대한 실현 가능한 배치를 찾지 못하면 일부 파드만 스케줄될 수 있고, 그 파드들은 스케줄링 제약을 충족하는 게 보장돼요.

API 구성: 스케줄링 제약

모든 PodGroup(또는 PodGroupTemplate)은 선택적으로 schedulingConstraints 필드를 선언할 수 있어요. 이 필드는 배치 기반 PodGroup 스케줄링 알고리즘에 의해 해석돼요. PodGroupTemplate에 제약이 정의되어 있으면 참조하는 PodGroup으로 복사돼요.

토폴로지 제약

PodGroup의 토폴로지 제약을 정의하려면 key를 설정해야 해요. 이 key는 목표 토폴로지 도메인(예: 랙, 존)을 나타내는 쿠버네티스 노드 레이블이에요. 스케줄러는 PodGroup 안의 모든 파드가 같은 토폴로지 도메인을 공유하는 노드에 놓이도록 엄격히 강제해요.

토폴로지 제약이 있는 PodGroup 예시:

apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: example-podgroup
spec:
  schedulingPolicy:
    gang:
      minCount: 4
  schedulingConstraints:
    topology:
      - key: topology.example.com/rack

멀티 레벨 토폴로지 인지 스케줄링

v1.37부터 알파(v1.37 알파, 기본 비활성)로 들어온 이 기능을 쓰려면 cluster의 관련 컴포넌트들에서 CompositePodGroup 기능 게이트를 켜야 해요. 복잡한 워크로드는 파드를 클러스터 인프라의 여러 레벨에 함께 배치해야 할 수 있어요. 예를 들어 워크로드 전체는 하나의 가용 영역 안에서 돌아야 하는데, 그 안의 서로 다른 부분들은 특정 서버 랙 안에 엄격히 함께 있어야 하는 식이죠. 이런 멀티 레벨 co-location 요구를 CompositePodGroup API와 그룹 계층의 각 레벨에 토폴로지 제약을 지정하는 방식으로 표현할 수 있어요. 이 API를 쓰려면 CompositePodGroup 기능 게이트와 scheduling.k8s.io/v1alpha3 API 그룹을 활성화해야 해요.

멀티 레벨 토폴로지 제약 해석

CompositePodGroup 계층 안의 모든 그룹은 토폴로지 제약을 지정할 수 있어요. 이 제약은 그 그룹의 모든 하위 파드가 그 그룹의 제약과 일치하는 같은 토폴로지 도메인에 스케줄되도록 보장해요. 계층 스케줄링 중 스케줄러는 제약을 top-down(위에서 아래로) 방식으로 해석해요. 즉 자식 그룹을 스케줄링할 때 고려하는 토폴로지 도메인은 부모 그룹이 가정한 배치에 해당하는 도메인 안으로 한정돼요. 쿠버네티스는 토폴로지 레이블의 물리적 계층 순서에 엄격한 요구를 두지 않아요 — 토폴로지 key는 임의의 노드 레이블이니까요. 다만 부모에서 자식으로 토폴로지 제약을 지정하는 순서가 스케줄러가 토폴로지 도메인을 세분화하는 순서를 결정해요.

v1.37 기준으로 각 CompositePodGroup에는 토폴로지 제약을 하나만 지정할 수 있다는 점도 기억해 두세요.

예시

부모 CompositePodGroupTemplate이 워크로드 전체를 하나의 가용 영역(topology.example.com/zone)으로 제약하고, 두 자식 PodGroupTemplate(workers, driver)이 각자 파드를 그 영역 안의 서버 랙(topology.example.com/rack)으로 제약하도록 Workload를 구성해 볼게요:

apiVersion: scheduling.k8s.io/v1alpha3
kind: Workload
metadata:
  name: example-workload
spec:
  compositePodGroupTemplates:
  - name: root
    schedulingPolicy:
      gang:
        minGroupCount: 2
    schedulingConstraints:
      topology:
      - key: topology.example.com/zone
    podGroupTemplates:
    - name: workers
      schedulingPolicy:
        gang:
          minCount: 8
      schedulingConstraints:
        topology:
        - key: topology.example.com/rack
    - name: driver
      schedulingPolicy:
        gang:
          minCount: 1
      schedulingConstraints:
        topology:
        - key: topology.example.com/rack

Workload 오브젝트를 만들면 그에 해당하는 그룹 오브젝트가 다음과 같이 생성돼요. root 템플릿을 참조하는 루트 CompositePodGroup 하나와, 각각 루트 CompositePodGroup을 부모 그룹으로 참조하는 두 자식 PodGroup(workers, driver)이에요:

apiVersion: scheduling.k8s.io/v1alpha3
kind: CompositePodGroup
metadata:
  name: workload-root
spec:
  workloadRef:
    workloadName: example-workload
    templateName: root
  schedulingPolicy:
    gang:
      minGroupCount: 2
  schedulingConstraints:
    topology:
    - key: topology.example.com/zone
---
apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: workload-workers
spec:
  parentCompositePodGroupName: workload-root
  workloadRef:
    workloadName: example-workload
    templateName: workers
  schedulingPolicy:
    gang:
      minCount: 8
  schedulingConstraints:
    topology:
    - key: topology.example.com/rack
---
apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: workload-driver
spec:
  parentCompositePodGroupName: workload-root
  workloadRef:
    workloadName: example-workload
    templateName: driver
  schedulingPolicy:
    gang:
      minCount: 1
  schedulingConstraints:
    topology:
    - key: topology.example.com/rack

스케줄링 중 스케줄러는 먼저 workload-root를 위한 가용 영역을 고르고, 그 영역 안의 노드를 랙 단위로 세분화해 workload-workersworkload-driver가 그 영역 안에서 실현 가능한 랙 배치를 찾아요. 예를 들어 다섯 개의 노드가 이렇게 레이블되어 있다고 해 볼게요:

Node topology.example.com/zone topology.example.com/rack
node-a zone-1 rack-1
node-b zone-1 rack-1
node-c zone-1 rack-2
node-d zone-2 rack-1
node-e zone-2 rack-3

workload-root를 처리할 때 스케줄러는 topology.example.com/zone key를 기준으로 전체 클러스터 노드에서 후보 배치를 평가해요. zone-1node-a·node-b·node-c, zone-2node-d·node-e가 들어가죠. workload-workers의 후보 배치를 평가할 때는 workload-root가 가정한 배치 안의 노드만을 topology.example.com/rack key로 세분화해요. zone-1 안에서는 rack-1(node-a·node-b)과 rack-2(node-c), zone-2 안에서는 rack-1(node-d)과 rack-3(node-e)이 후보가 돼요. 형제인 workload-driver의 후보 배치도 두 그룹이 같은 토폴로지 key(topology.example.com/rack)를 쓰므로 workload-workers와 동일해요.

더 알아보기 (Learn more)