DRA API 객체

DRA API 객체 (DRA API Objects)

이 페이지에서는 동적 리소스 할당(DRA)이 장치를 분류하고, 요청하고, 할당하기 위해 사용하는 쿠버네티스 API 종류(kind)를 설명해요.

출처: Kubernetes 공식 문서 — DRA API Objects

DRA 용어 (DRA terminology)

DRA는 핵심 할당 기능을 제공하기 위해 다음 쿠버네티스 API 종류를 사용해요. 이 API 종류들은 모두 resource.k8s.io/v1 API 그룹에 포함돼 있어요.

  • DeviceClass: 요청할 수 있는 장치의 범주를 정의하고, 요청(claim)에서 특정 장치 속성을 어떻게 선택할지를 정의해요. DeviceClass의 파라미터는 ResourceSlice에 있는 장치 0개 이상과 일치할 수 있어요. DeviceClass에서 장치를 요청하려면 ResourceClaim이 특정 장치 속성을 선택해요.
  • ResourceClaim: 클러스터에 연결된 리소스(예: 장치)에 대한 접근 요청을 나타내요. ResourceClaim은 Pod에 특정 리소스에 대한 접근 권한을 제공해요. ResourceClaim은 워크로드 운영자가 만들 수도 있고, ResourceClaimTemplate을 바탕으로 쿠버네티스가 생성할 수도 있어요.
  • ResourceClaimTemplate: 쿠버네티스가 워크로드의 Pod별 ResourceClaim을 만들 때 사용하는 템플릿을 정의해요. ResourceClaimTemplate은 Pod에 각각 분리된 유사한 리소스에 대한 접근 권한을 제공해요. 템플릿에서 쿠버네티스가 생성한 각 ResourceClaim은 특정 Pod에 바인딩돼요. Pod가 종료되면 쿠버네티스는 해당 ResourceClaim을 삭제해요.
  • ResourceSlice: 노드에 연결된 하나 이상의 리소스(예: 장치)를 나타내요. 드라이버가 클러스터에서 ResourceSlice를 만들고 관리해요. ResourceClaim이 생성되어 Pod에서 사용되면, 쿠버네티스는 ResourceSlice를 사용해 요청된 리소스에 접근할 수 있는 노드를 찾아요. 쿠버네티스는 ResourceClaim에 리소스를 할당하고, 그 리소스에 접근할 수 있는 노드에 Pod를 스케줄링해요.

DeviceClass

DeviceClass를 사용하면 클러스터 관리자나 장치 드라이버가 클러스터에 있는 장치의 범주를 정의할 수 있어요. DeviceClass는 운영자에게 어떤 장치를 요청할 수 있고 어떻게 요청할 수 있는지 알려줘요. CEL(Common Expression Language)을 사용해 특정 속성을 기준으로 장치를 선택할 수도 있어요. DeviceClass를 참조하는 ResourceClaim은 그 DeviceClass 안에서 특정 구성을 요청할 수 있어요.

DeviceClass를 만들려면 클러스터에서 DRA 설정하기를 참고하세요.

ResourceClaim과 ResourceClaimTemplate

ResourceClaim은 워크로드가 필요한 리소스를 정의해요. 모든 ResourceClaim은 DeviceClass를 참조하고 그 DeviceClass에서 장치를 선택하는 요청(requests) 을 가져요. ResourceClaim은 특정 요구사항을 충족하는 장치를 걸러내는 셀렉터(selectors) 와, 요청을 충족할 수 있는 장치를 제한하는 제약(constraints) 도 사용할 수 있어요. ResourceClaim은 워크로드 운영자가 만들 수도 있고, ResourceClaimTemplate을 바탕으로 쿠버네티스가 생성할 수도 있어요. ResourceClaimTemplate은 쿠버네티스가 Pod의 ResourceClaim을 자동 생성할 때 사용하는 템플릿을 정의해요.

ResourceClaim과 ResourceClaimTemplate의 사용 사례

사용하는 방식은 요구사항에 따라 달라져요.

  • ResourceClaim: 여러 Pod가 특정 장치에 대한 접근 권한을 공유하고 싶을 때 사용해요. 직접 만든 ResourceClaim의 수명주기를 수동으로 관리해요.
  • ResourceClaimTemplate: Pod가 각각 분리된 유사하게 구성된 장치에 독립적으로 접근하길 원할 때 사용해요. 쿠버네티스는 ResourceClaimTemplate의 사양에 따라 ResourceClaim을 생성해요. 생성된 각 ResourceClaim의 수명은 해당 Pod의 수명에 묶여 있어요.
  • PodGroup ResourceClaimTemplate: PodGroup이 각각 분리된 유사하게 구성된 장치에 독립적으로 접근하고, 그 장치를 Pod들이 공유할 수 있게 하려면 사용해요. 쿠버네티스는 ResourceClaimTemplate의 사양을 바탕으로 PodGroup마다 ResourceClaim 하나를 생성해요. 생성된 각 ResourceClaim의 수명은 해당 PodGroup의 수명에 묶여 있어요. 이 기능은 DRAWorkloadResourceClaims 기능 게이트가 활성화되어 있어야 해요.

워크로드를 정의할 때 CEL(Common Expression Language)을 사용해 특정 장치 속성이나 용량을 걸러낼 수 있어요. 필터링에 사용할 수 있는 파라미터는 장치와 드라이버에 따라 달라져요.

Pod에서 특정 ResourceClaim을 직접 참조한다면, 그 ResourceClaim이 Pod와 같은 네임스페이스에 이미 존재해야 해요. 네임스페이스에 ResourceClaim이 없다면 Pod는 스케줄링되지 않아요. 이 동작은 PersistentVolumeClaim이 그것을 참조하는 Pod와 같은 네임스페이스에 존재해야 하는 것과 비슷해요.

Pod에서 자동 생성된 ResourceClaim을 참조할 수도 있지만 권장하지는 않아요. 자동 생성된 ResourceClaim은 생성을 촉발한 Pod나 PodGroup의 수명에 묶여 있기 때문이에요.

이 방법들 중 하나로 리소스를 요청하는 법을 배우려면 DRA로 워크로드에 장치 할당하기를 참고하세요.

우선순위 목록 (Prioritized list)

기능 상태: 쿠버네티스 v1.36부터 안정화(stable), 기본 활성화

ResourceClaim이나 ResourceClaimTemplate의 요청에 우선순위가 있는 하위 요청(subrequest) 목록을 제공할 수 있어요. 그러면 스케줄러는 할당할 수 있는 첫 번째 하위 요청을 선택해요. 이렇게 하면 기본 선택이 불가능할 때 워크로드가 사용할 수 있는 대체 장치를 지정할 수 있어요.

아래 예시에서 ResourceClaimTemplate은 색상이 검은색이고 크기가 큼(large)인 장치를 요청했어요. 그 속성을 가진 장치가 없다면 Pod는 스케줄링될 수 없어요. 우선순위 목록 기능을 사용하면 두 번째 대안을 지정할 수 있는데, 이 대안은 색상이 흰색이고 크기가 작은 장치 두 개를 요청해요. 크고 검은 장치가 있다면 그것이 할당되고, 없다면 작고 흰 장치 두 개가 있다고 해도 Pod는 여전히 실행될 수 있어요.

apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
  name: prioritized-list-claim-template
spec:
  spec:
    devices:
      requests:
      - name: req-0
        firstAvailable:
        - name: large-black
          deviceClassName: resource.example.com
          selectors:
          - cel:
              expression: |-
                device.attributes["resource-driver.example.com"].color == "black" &&
                device.attributes["resource-driver.example.com"].size == "large"
        - name: small-white
          deviceClassName: resource.example.com
          selectors:
          - cel:
              expression: |-
                device.attributes["resource-driver.example.com"].color == "white" &&
                device.attributes["resource-driver.example.com"].size == "small"
          count: 2

Pod가 클러스터의 여러 노드에 배치될 수 있다면, 스케줄러는 각 노드에 점수를 매길 때 우선순위 목록에서 선택된 하위 요청의 인덱스를 입력 중 하나로 사용해요. 그래서 더 높은 순위의 하위 요청에 요청된 장치를 할당할 수 있는 노드가, 낮은 순위의 하위 요청만 처리할 수 있는 노드보다 선택될 가능성이 높아져요.

이 결정은 Pod 단위로 이뤄져요. 따라서 Pod가 ReplicaSet이나 이와 유사한 그룹의 구성원이라면, 그룹의 모든 구성원이 같은 하위 요청을 선택할 거라고 기대하면 안 돼요. 워크로드가 이 점을 감당할 수 있어야 해요.

워크로드 ResourceClaim (Workload ResourceClaims)

기능 상태: 쿠버네티스 v1.37부터 베타(beta), 기본 비활성화

워크로드 API로 Pod를 구성하면, 개별 Pod 대신 PodGroup 전체에 ResourceClaim을 예약할 수 있고, 단일 Pod 대신 PodGroup용 ResourceClaimTemplate을 생성할 수 있어요. 그렇게 하면 PodGroup 안의 Pod들이 생성된 ResourceClaim에 할당된 장치에 대한 접근 권한을 공유할 수 있어요.

이 기능은 두 가지 문제를 겨냥해요.

  • ResourceClaim API의 status.reservedFor 목록은 항목 256개까지만 담을 수 있어요. kube-scheduler는 그 목록에 개별 Pod만 기록하므로, ResourceClaim을 공유할 수 있는 Pod는 256개뿐이에요. PodGroup을 status.reservedFor에 기록할 수 있게 하면 256개보다 훨씬 많은 Pod가 ResourceClaim을 공유할 수 있어요.
  • Pod는 정확한 이름을 알 때만 ResourceClaim을 공유할 수 있어요. Pod 그룹을 복제하는 복잡한 워크로드는, 각 그룹의 Pod가 공유하는 ResourceClaim을 그룹 집합이 확장·축소될 때 명시적으로 만들고 삭제해야 해요. PodGroup마다 ResourceClaim을 생성하면, 단일 ResourceClaimTemplate이 자동으로 복제되면서도 PodGroup 안의 Pod들이 공유할 수 있는 ResourceClaim들의 기반이 되어줘요.

PodGroup API는 Pod API의 spec.resourceClaims 필드와 같은 구조와 비슷한 의미를 가진 spec.resourceClaims 필드를 정의해요:

apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: training-group
  namespace: some-ns
spec:
  ...
  resourceClaims:
  - name: pg-claim
    resourceClaimName: my-pg-claim
  - name: pg-claim-template
    resourceClaimTemplateName: my-pg-template

Pod가 만든 claim처럼, resourceClaimName을 정의하는 PodGroup용 claim은 이름으로 ResourceClaim을 참조해요. resourceClaimTemplateName을 정의하는 claim은 ResourceClaimTemplate을 참조하는데, 이것은 PodGroup 전체에 대해 하나의 ResourceClaim으로 복제되어 Pod들이 공유할 수 있어요.

Pod가 name, resourceClaimName, resourceClaimTemplateName이 모두 자신의 PodGroup spec.resourceClaims 중 하나와 일치하는 claim을 정의하면, kube-scheduler는 Pod 대신 PodGroup에 ResourceClaim을 예약해요. Pod의 claim이 PodGroup이 만든 claim과 일치하지 않으면, kube-scheduler는 Pod에 ResourceClaim을 예약해요. 어느 경우든 예약은 ResourceClaim의 status.reservedFor에 기록돼요. PodGroup 예약과 그에 해당하는 리소스 할당은 그룹에 더 이상 Pod가 없더라도 PodGroup이 삭제될 때까지 ResourceClaim에 유지돼요.

PodGroup claim과 일치하는 Pod claim이 resourceClaimTemplateName을 정의하면, PodGroup에 대해 ResourceClaim 하나가 생성돼요. 같은 claim을 정의하는 그룹의 다른 Pod들은 새 ResourceClaim 생성을 촉발하는 대신 그 생성된 ResourceClaim을 공유해요. resourceClaimTemplateName claim이 PodGroup claim과 일치하든 안 하든, 생성된 ResourceClaim의 이름은 Pod의 status.resourceClaimStatuses에 기록돼요.

ResourceClaimTemplate에 대한 일치하는 PodGroup claim은 DRAWorkloadResourceClaims 기능이 활성화되어 있을 때만 ResourceClaim 생성을 촉발해요. 기능이 비활성화되어 있으면 Pod별 ResourceClaim을 만드는 대신, kube-apiserverkube-controller-manager 사이에서 기능을 활성화·비활성화하는 클러스터 업그레이드나 롤아웃/롤백 중에 잘못된 Pod별 ResourceClaim이 생기지 않도록 ResourceClaim을 만들지 않아요.

PodGroup용 ResourceClaimTemplate에서 생성된 ResourceClaim은 PodGroup의 수명주기를 따라요. ResourceClaim은 PodGroup과 그 ResourceClaimTemplate이 모두 존재할 때 처음 생성돼요. ResourceClaim은 PodGroup이 삭제되고 더 이상 예약되지 않은 뒤에 삭제돼요.

다음 예시를 살펴볼게요:

apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: training-group
  namespace: some-ns
spec:
  ...
  resourceClaims:
  - name: pg-claim
    resourceClaimName: my-pg-claim
  - name: pg-claim-template
    resourceClaimTemplateName: my-pg-template
---
apiVersion: v1
kind: Pod
metadata:
  name: training-group-pod-1
  namespace: some-ns
spec:
  ...
  schedulingGroup:
    podGroupName: training-group
  resourceClaims:
  - name: pod-claim
    resourceClaimName: my-pod-claim
  - name: pod-claim-template
    resourceClaimTemplateName: my-pod-template
  - name: pg-claim
    resourceClaimName: my-pg-claim
  - name: pg-claim-template
    resourceClaimTemplateName: my-pg-template

이 예시에서 training-group PodGroup에는 training-group-pod-1이라는 Pod 하나가 있어요. Pod의 pod-claimpod-claim-template claim은 PodGroup이 만든 어떤 claim과도 일치하지 않아서, 이 claim들은 PodGroup의 영향을 받지 않아요: ResourceClaim my-pod-claim은 Pod에 예약되고, ResourceClaimTemplate my-pod-template에서 ResourceClaim이 생성되어 역시 Pod에 예약돼요. pg-claimpg-claim-template은 PodGroup이 만든 claim과 일치해요. ResourceClaim my-pg-claim은 PodGroup에 예약되고, ResourceClaimTemplate my-pg-template에서 ResourceClaim이 생성되어 역시 PodGroup에 예약돼요.

ResourceClaim을 워크로드 API 리소스와 연결하는 것은 kube-apiserver, kube-controller-manager, kube-scheduler, kubeletDRAWorkloadResourceClaims 기능 게이트로 제어돼요.

ResourceSlice

각 ResourceSlice는 풀(pool)에 있는 하나 이상의 장치를 나타내요. 이 풀은 장치 드라이버가 관리하는데, 드라이버가 ResourceSlice를 만들고 관리해요. 풀에 있는 리소스는 단일 ResourceSlice로 표현될 수도 있고 여러 ResourceSlice에 걸쳐 있을 수도 있어요.

ResourceSlice는 장치 사용자와 스케줄러에게 유용한 정보를 제공하며, 동적 리소스 할당에 핵심적이에요. 모든 ResourceSlice는 다음 정보를 포함해야 해요.

  • 리소스 풀(Resource pool): 드라이버가 관리하는 하나 이상의 리소스 그룹이에요. 풀은 여러 ResourceSlice에 걸칠 수 있어요. 풀에 있는 리소스의 변경은 그 풀의 모든 ResourceSlice에 전파되어야 해요. 그 전파가 이뤄지도록 보장하는 책임은 풀을 관리하는 장치 드라이버에 있어요.
  • 장치(Devices): 관리 중인 풀에 있는 장치예요. ResourceSlice는 풀의 모든 장치를 나열할 수도 있고 일부만 나열할 수도 있어요. ResourceSlice는 속성, 버전, 용량 같은 장치 정보를 정의해요. 장치 사용자는 ResourceClaim이나 DeviceClass에서 장치 정보를 필터링해 할당할 장치를 선택할 수 있어요.
  • 노드(Nodes): 리소스에 접근할 수 있는 노드예요. 드라이버는 클러스터의 모든 노드, 단일 명명된 노드, 특정 노드 라벨이 있는 노드 등 어느 노드가 리소스에 접근할 수 있는지 선택할 수 있어요.

드라이버는 컨트롤러를 사용해 클러스터의 ResourceSlice를 드라이버가 게시해야 하는 정보와 조정(reconcile)해요. 이 컨트롤러는 클러스터 사용자가 ResourceSlice를 만들거나 수정하는 것 같은 수동 변경을 덮어써요.

다음 ResourceSlice 예시를 살펴볼게요:

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: cat-slice
spec:
  driver: "resource-driver.example.com"
  pool:
    generation: 1
    name: "black-cat-pool"
    resourceSliceCount: 1
  # allNodes 필드는 클러스터의 어떤 노드든 장치에 접근할 수 있는지 정의해요.
  allNodes: true
  devices:
  - name: "large-black-cat"
    attributes:
      color:
        string: "black"
      size:
        string: "large"
      cat:
        bool: true

이 ResourceSlice는 resource-driver.example.com 드라이버가 black-cat-pool 풀에서 관리해요. allNodes: true 필드는 클러스터의 어떤 노드든 장치에 접근할 수 있음을 나타내요. ResourceSlice에는 large-black-cat이라는 장치 하나가 있는데, 다음 속성을 가져요.

  • color: black
  • size: large
  • cat: true

DeviceClass는 이 속성들을 사용해 이 ResourceSlice를 선택할 수 있고, ResourceClaim은 그 DeviceClass에서 특정 장치를 걸러낼 수 있어요.

이름 짓기와 우선순위 (Naming and prioritization)

쿠버네티스 스케줄러가 할당을 위해 장치를 평가하는 순서는 ResourceSlice와 리소스 풀 이름의 사전순 정렬에 따라 결정돼요. 스케줄러는 first-fit 전략을 사용하는데, 즉 claim의 요구사항을 충족하는 첫 번째 사용 가능한 장치를 선택해요.

이 덕분에 풀과 ResourceSlice에 부여한 이름이 리소스 할당의 우선순위에 영향을 줄 수 있어요. 바인딩 조건이 없는 풀은 이름과 관계없이 항상 바인딩 조건이 있는 풀보다 먼저 평가된다는 점을 기억하세요.

k8s.io/dynamic-resources/kubeletplugin Go 패키지나 그 모듈의 ResourceSlice 컨트롤러로 만든 드라이버는, 드라이버가 지정한 순서대로 평가되도록 ResourceSlice 이름을 자동으로 처리해요.

관리자 접근 (Admin access)

기능 상태: 쿠버네티스 v1.36부터 안정화(stable), 기본 활성화

ResourceClaim이나 ResourceClaimTemplate의 요청을 유지보수·문제해결 작업을 위한 특권 기능이 있는 것으로 표시할 수 있어요. 관리자 접근이 있는 요청은 사용 중인 장치에 대한 접근 권한을 부여하고, 컨테이너에서 장치를 사용 가능하게 만들 때 추가 권한을 켤 수도 있어요:

apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
  name: large-black-cat-claim-template
spec:
  spec:
    devices:
      requests:
      - name: req-0
        exactly:
          deviceClassName: resource.example.com
          allocationMode: All
          adminAccess: true

관리자 접근은 특권 모드라서 멀티 테넌트 클러스터에서 일반 사용자에게 부여하면 안 돼요. resource.kubernetes.io/admin-access: "true"(대소문자 구분) 라벨이 있는 네임스페이스에서 ResourceClaim이나 ResourceClaimTemplate 객체를 만들 권한이 있는 사용자만 adminAccess 필드를 사용할 수 있어요. 이렇게 해서 비관리자 사용자가 이 기능을 남용하지 못하게 해요.

관리자 접근은 kube-apiserver, kube-scheduler, kubeletDRAAdminAccess 기능 게이트로 제어돼요.

목록 유형 속성 (List type attributes)

기능 상태: 쿠버네티스 v1.36부터 알파(alpha), 기본 비활성화

이 기능은 ResourceSlice API를 개선해서, DRA 드라이버가 스칼라 값뿐 아니라 장치 속성의 목록(list) 값을 지정할 수 있게 해줘요. 예를 들어 CPU가 여러 PCIe 루트와 인접해 있을 때처럼 더 복잡한 내부 노드 토폴로지를 모델링할 때 유용해요.

ResourceClaim 작성자(최종 사용자) 입장에서 보면, 이 기능 덕분에 matchAttributedistinctAttribute가 이런 경우에 더 잘 작동해요.

  • matchAttribute — 두 속성이 동일할 필요 없이 비어 있지 않은 목록 교집합을 가져야 해요(스칼라 값은 항목 1개짜리 목록으로 취급돼요). 즉 한 드라이버가 PCIe 루트에 대해 단일 값을 게시하고 다른 드라이버가 목록을 게시한다면, 단일 값이 목록 어딘가에만 나타나면 제약이 충족돼요.
  • distinctAttribute — 속성 값이 쌍별로 서로소(pairwise-disjoint) 여야 해요(어떤 두 장치 사이에도 공유되는 값이 없어야 해요).

ResourceClaim 작성자가 CEL 표현식 안에서 목록일 수도 있는 속성을 사용할 수 있도록, 이 기능은 includes() CEL 함수도 도입해요.

# 스칼라 속성 (하위 호환)
# 가정: device.attributes["dra.example.com"].model = "model-a"
device.attributes["dra.example.com"].model.includes("model-a")  # true
device.attributes["dra.example.com"].model.includes("model-b")  # false

# 목록 유형 속성 (DRAListTypeAttributes 필요)
# 가정: device.attributes["dra.example.com"].supported-models= ["model-a", "model-b"]
device.attributes["dra.example.com"].supported-models.includes("model-a")  # true
device.attributes["dra.example.com"].supported-models.includes("model-c")  # false

기본적으로 각 DeviceAttribute는 정확히 하나의 스칼라 값(불리언, 정수, 문자열, 시맨틱 버전 문자열)을 보유해요. DRAListTypeAttributes 기능 게이트는 DeviceAttribute를 네 가지 목록 유형 필드로 확장해서, 장치가 단일 속성에 대해 여러 값을 광고할 수 있게 해줘요.

  • bools — 불리언 값 목록
  • ints — 64비트 정수 값 목록
  • strings — 문자열 목록(각각 최대 64자)
  • versions — semver.org 사양 2.0.0에 따른 시맨틱 버전 문자열 목록(각각 최대 64자)

장치당 개별 속성 값의 총 개수(스칼라 필드 + 모든 목록 요소 합)는 48개로 제한돼요. ResourceSlice의 어떤 장치가 이 기능이나 테인트(taints) 같은 다른 고급 기능을 사용하면, 그 ResourceSlice는 최대 64개 장치로 제한돼요.

목록 유형 문자열 속성을 사용해 여러 지원 모델을 광고하는 장치 예시를 볼게요:

kind: ResourceSlice
apiVersion: resource.k8s.io/v1
metadata:
  name: example-resourceslice
spec:
  nodeName: worker-1
  pool:
    name: pool
    generation: 1
    resourceSliceCount: 1
  driver: dra.example.com
  devices:
  - name: gpu-0
    attributes:
      dra.example.com/supported-models:
        strings:
        - model-a
        - model-b

목록 유형 속성은 kube-apiserverkube-schedulerDRAListTypeAttributes 기능 게이트로 제어돼요.

파생 속성 (Derived attributes)

기능 상태: 쿠버네티스 v1.37부터 알파(alpha), 기본 비활성화

matchAttributedistinctAttribute 제약은 보통 장치가 정확히 같은 이름으로 속성을 게시해야 해요. GPU 드라이버가 pcie_locality를 게시하고 NIC 드라이버가 pcie_root를 게시한다면(또는 numa0-pcie1 같은 문자열에 같은 정보를 넣는다면) 스케줄러는 이 둘이 같은 것을 나타내는지 알 수 없어요. 그래서 두 드라이버의 장치는 먼저 공유 속성 이름에 합의하지 않으면 함께 배치(co-locate)될 수 없어요.

derivedAttributes를 사용하면 드라이버가 공유 속성 이름을 표준화할 때까지 기다릴 필요 없이 이 간극을 인라인으로 메울 수 있어요. 요청의 .spec.devices.requests[].exactly.spec.devices.requests[].firstAvailable[] 아래에 derivedAttributes 항목을 하나 이상 추가해요. 각 항목은 해당 요청의 모든 후보 장치에 대해 스케줄러가 평가하는 CEL 표현식을 정의해요. 그 결과는 matchAttributedistinctAttribute 제약에서 드라이버가 제공한 장치 속성처럼 참조할 수 있는 가상 속성이 돼요.

apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
  name: gpu-nic-numa-alignment
spec:
  devices:
    requests:
    - name: gpu
      exactly:
        deviceClassName: gpu.example.com
        count: 1
        derivedAttributes:
        - name: derived/numa
          expression: device.attributes["gpu.example.com"].numa
    - name: nic
      exactly:
        deviceClassName: nic.example.com
        count: 1
        derivedAttributes:
        - name: derived/numa
          expression: device.attributes["nic.example.com"].numaNode
    constraints:
    - requests: ["gpu", "nic"]
      matchAttribute: derived/numa

이 예시에서 gpunic 드라이버는 다른 속성 이름(numanumaNode)으로 토폴로지 정보를 게시해요. 각 요청은 자기 장치의 속성에서 공통 derived/numa 값을 계산하고, matchAttribute 제약이 두 요청을 그 가상 속성에 정렬시켜요. 밑바탕이 되는 드라이버들이 공유 속성 이름에 합의한 적이 없어도 말이죠.

derivedAttributes에 대해 알아두면 좋은 몇 가지가 있어요.

  • 이름 짓기: name은 DNS 하위 도메인 뒤에 /와 C 식별자가 오는 형식이어야 해요. 드라이버가 제공하는 속성 이름과 같은 형식이에요(예: example.com/numaNode 또는 derived/numaNode). 이름이 드라이버가 이미 게시한 속성과 일치하면, 제약 일치를 위해 파생 속성의 값이 드라이버 제공 값을 가려요(shadow). 의도치 않은 가림을 피하려면 derived/처럼 어떤 드라이버도 쓰지 않을 도메인 접두사를 사용하세요. 요청당 파생 속성은 최대 32개까지 정의할 수 있어요.
  • 제약에 반드시 사용되어야 함: 모든 파생 속성은 그 속성을 정의하는 요청(또는 하위 요청)에 적용되는 matchAttributedistinctAttribute 제약 하나 이상에서 참조되어야 해요. 그렇지 않으면 ResourceClaim 검증이 실패해요.
  • 평가 범위와 순서: expression은 요청 자체의 CEL 셀렉터(.selectors[].cel)가 해당 장치를 이미 걸러낸 뒤, 후보 장치마다 한 번 평가돼요. 그래서 파생 속성은 셀렉터 표현식에서 참조할 수 없고, CEL 환경의 device.attributes로도 노출되지 않아요.
  • 반환 유형: expression은 스칼라(string, int, bool, 시맨틱 버전)로 평가되어야 하거나, DRAListTypeAttributes 기능 게이트도 활성화되어 있으면 그 스칼라 유형 중 하나의 목록으로 평가되어야 해요.
  • 비용 제한: 각 표현식에는 최대 길이와 추정 CEL 평가 비용 제한이 있어요. 그에 더해 ResourceClaim 안의 모든 derivedAttributes 표현식의 추정 비용 합계도 상한이 있어서, 단일 스케줄링 시도에 추가되는 총 오버헤드를 제한해요. 이 제한 중 하나라도 초과하면 ResourceClaim은 거부돼요.
  • 런타임 오류는 스케줄링을 중단: 후보 장치에 대해 표현식 평가가 실패하면(예: 장치가 없는 속성을 참조하는 경우) 스케줄러는 할당을 중단하고 Pod는 스케줄링에 실패해요. 그 장치를 조용히 건너뛰지 않아요. 속성을 읽기 전에 존재하는지 확인하는 식으로 방어적으로 표현식을 작성하세요.

파생 속성은 kube-apiserverkube-schedulerDRADerivedAttributes 기능 게이트로 제어돼요.

DRA 드라이버가 게시할 수 있는 표준 장치 속성 목록은 표준 장치 속성 참조를 보세요.

DRA에 의한 확장 리소스 할당 (Extended resource allocation by DRA)

기능 상태: 쿠버네티스 v1.37부터 안정화(stable), 기본 활성화

DeviceClass에 확장 리소스 이름(extended resource name)을 제공할 수 있어요. 그러면 스케줄러는 확장 리소스 요청에 대해 그 클래스와 일치하는 장치를 선택해요. 이렇게 하면 사용자는 Pod에서 확장 리소스 요청을 계속 사용해서, 장치 플러그인이 제공하는 확장 리소스나 DRA 장치 중 하나를 요청할 수 있어요. 같은 확장 리소스는 하나의 클러스터 노드에서 장치 플러그인이나 DRA 중 하나가 제공할 수 있어요. 같은 확장 리소스를 어떤 노드에서는 장치 플러그인이, 다른 노드에서는 DRA가 제공할 수도 있어요.

아래 예시에서 DeviceClass에는 example.com/gpu라는 extendedResourceName이 주어져 있어요. Pod가 확장 리소스 example.com/gpu: 2를 요청했다면, DeviceClass와 일치하는 장치가 두 개 이상 있는 노드에 스케줄링될 수 있어요.

apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
  name: gpu.example.com
spec:
  selectors:
  - cel:
      expression: device.driver == 'gpu.example.com' && device.attributes['gpu.example.com'].type
        == 'gpu'
  extendedResourceName: example.com/gpu

추가로, 사용자는 ResourceClaim을 명시적으로 만들지 않고도 특수 확장 리소스를 사용해 장치를 할당할 수 있어요. 확장 리소스 이름 접두사 deviceclass.resource.kubernetes.io/와 DeviceClass 이름을 사용해요. 이 방식은 extended resource name을 지정하지 않은 DeviceClass를 포함해 어떤 DeviceClass에서든 작동해요. 결과로 생성되는 ResourceClaim에는 해당 DeviceClass의 지정된 개수의 장치에 대한 ExactCount 요청이 포함돼요.

DRA에 의한 확장 리소스 할당은 kube-apiserver, kube-scheduler, kube-controller-manager, kubeletDRAExtendedResource 기능 게이트로 제어돼요.

확장 리소스 요청에 대한 실습 위주 안내는 컨테이너에 확장 리소스 할당하기를 참고하세요.