DRA로 드라이버 설치하고 디바이스 할당하기

DRA로 드라이버 설치하고 디바이스 할당하기 (Install Drivers and Allocate Devices with DRA)

이것은 쿠버네티스의 안정적(stable) 기능이며 v1.35 버전부터 그렇게 되어 있어요. v1.30 릴리스에서 처음 사용 가능해졌어요. 더 이상 이 기능이나 동작을 비활성화하거나 선택 해제할 수 없어요(잠겨 있음); 관련 기능 게이트 DynamicResourceAllocation에 값을 명시적으로 설정하면 쿠버네티스는 그것을 무시하지만 오류를 보고하지 않아요.

이 튜토리얼은 클러스터에 DRA(동적 리소스 할당, Dynamic Resource Allocation) 드라이버를 설치하고 DRA API와 함께 사용해 파드에 디바이스를 할당하는 방법을 보여 줘요. 이 페이지는 클러스터 관리자를 위한 것이에요.

DRA(동적 리소스 할당)는 클러스터가 하드웨어 요구 사항과 선호도에 대한 파드 기반 클레임을 충족시키기 위해 하드웨어 리소스의 가용성과 할당을 관리하게 해줘요. 이를 지원하기 위해 쿠버네티스 내장 컴포넌트(쿠버네티스 스케줄러, kubelet, kube-controller-manager 같은)와 디바이스 소유자의 서드파티 드라이버(DRA 드라이버라고 불림)의 혼합이 파드 수명 주기 전반에 걸쳐 리소스를 광고, 할당, 준비, 마운트, 상태 확인, 준비 해제, 정리할 책임을 공유해요. 이러한 컴포넌트는 resource.k8s.io API 그룹의 일련의 DRA 특정 API(DeviceClasses, ResourceSlices, ResourceClaims 및 파드 spec 자체의 새 필드 포함)를 통해 정보를 공유해요.

목표 (Objectives)

  • 예시 DRA 드라이버 배포하기.
  • DRA API를 사용해 하드웨어 클레임을 요청하는 파드 배포하기.
  • 클레임이 있는 파드 삭제하기.

출처: 문서

본문

시작하기 전에

클러스터는 RBAC를 지원해야 해요. 다른 권한 부여 메커니즘을 사용하는 클러스터로 이 튜토리얼을 시도할 수 있지만, 그 경우 역할과 권한을 정의하는 단계를 적응시켜야 해요.

쿠버네티스 클러스터가 있어야 하고, kubectl 명령줄 도구가 클러스터와 통신하도록 구성되어 있어야 해요. 이 튜토리얼을 제어 플레인 호스트로 작동하지 않는 최소 두 개의 노드가 있는 클러스터에서 실행하는 것을 권장해요. 아직 클러스터가 없다면 minikube로 만들거나 다음 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있어요:

  • iximiuz Labs
  • Killercoda
  • KodeKloud

이 튜토리얼은 Linux 노드에서 테스트되었으며, 다른 유형의 노드에서도 작동할 수 있어요.

버전을 확인하려면 kubectl version을 입력하세요.

클러스터가 현재 Kubernetes 1.37을 실행하고 있지 않다면 사용할 계획인 쿠버네티스 버전의 문서를 확인하세요.

초기 클러스터 상태 살펴보기

DRA가 활성화된 클러스터의 초기 상태를 관찰하는 데 시간을 쓸 수 있어요. 특히 이전에 이러한 API를 많이 사용해 본 적이 없다면요. 이 튜토리얼을 위해 새 클러스터를 설정하고 드라이버가 설치되지 않고 아직 충족할 파드 클레임이 없다면, 이러한 명령의 출력은 어떤 리소스도 보여 주지 않을 거예요.

  • DeviceClasses 목록 가져오기:
kubectl get deviceclasses

출력은 다음과 비슷해요:

No resources found
  • ResourceSlices 목록 가져오기:
kubectl get resourceslices

출력은 다음과 비슷해요:

No resources found
  • ResourceClaims와 ResourceClaimTemplates 목록 가져오기.
kubectl get resourceclaims -A
kubectl get resourceclaimtemplates -A

출력은 다음과 비슷해요:

No resources found
No resources found

이 시점에서 DRA가 클러스터에서 활성화되고 올바르게 구성되었으며, 아직 어떤 DRA 드라이버도 DRA API에 어떤 리소스를 광고하지 않았음을 확인했어요.

예시 DRA 드라이버 설치

DRA 드라이버는 클러스터의 각 노드에서 실행되어 그 노드의 하드웨어와 쿠버네티스의 내장 DRA 컴포넌트를 인터페이스하는 서드파티 애플리케이션이에요. 설치 절차는 선택한 드라이버에 따라 달라지지만, 클러스터의 모든 또는 일부 노드(셀렉터나 유사 메커니즘 사용)에 DaemonSet으로 배포될 가능성이 커요.

드라이버의 문서에서 특정 설치 지침을 확인하세요. 여기에는 Helm 차트, 매니페스트 집합 또는 다른 배포 도구가 포함될 수 있어요.

이 튜토리얼은 kubernetes-sigs/dra-example-driver 저장소에서 찾을 수 있는 예시 드라이버를 사용해 드라이버 설치를 설명해요. 이 예시 드라이버는 파드가 상호작용하도록 시뮬레이션된 GPU를 쿠버네티스에 광고해요.

드라이버 설치를 위한 클러스터 준비

정리를 단순화하려면 dra-tutorial이라는 네임스페이스를 만들어요:

  • 네임스페이스 만들기:
kubectl create namespace dra-tutorial

프로덕션 환경에서는 드라이버 공급업체나 자체 조직의 이전에 릴리스되거나 검증된 이미지를 사용할 가능성이 크며, 노드는 드라이버 이미지가 호스팅되는 이미지 레지스트리에 접근할 수 있어야 해요. 이 튜토리얼에서는 공개적으로 릴리스된 dra-example-driver 이미지를 사용해 DRA 드라이버 이미지에 대한 접근을 시뮬레이션할 거예요.

  • 클러스터 노드 중 하나에서 다음을 실행해 이미지에 접근할 수 있는지 확인해요:
docker pull registry.k8s.io/dra-example-driver/dra-example-driver:v0.2.0

DRA 드라이버 컴포넌트 배포

이 튜토리얼에서는 중요한 예시 리소스 드라이버 컴포넌트를 kubectl로 개별적으로 설치할 거예요.

  • 이 DRA 드라이버가 지원하는 디바이스 유형을 나타내는 DeviceClass를 만들어요:
apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
  name: gpu.example.com
spec:
  selectors:
  - cel:
      expression: "device.driver == 'gpu.example.com'"
kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/deviceclass.yaml
  • 드라이버가 이 클러스터의 쿠버네티스 API와 상호작용할 권한을 얻는 데 사용할 ServiceAccount, ClusterRole, ClusterRoleBinding을 만들어요:

Service Account 만들기:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: dra-example-driver-service-account
  namespace: dra-tutorial
  labels:
    app.kubernetes.io/name: dra-example-driver
    app.kubernetes.io/instance: dra-example-driver
kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/serviceaccount.yaml

ClusterRole 만들기:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: dra-example-driver-role
rules:
- apiGroups: ["resource.k8s.io"]
  resources: ["resourceclaims"]
  verbs: ["get"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get"]
- apiGroups: ["resource.k8s.io"]
  resources: ["resourceslices"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/clusterrole.yaml

ClusterRoleBinding 만들기:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: dra-example-driver-role-binding
subjects:
- kind: ServiceAccount
  name: dra-example-driver-service-account
  namespace: dra-tutorial
roleRef:
  kind: ClusterRole
  name: dra-example-driver-role
  apiGroup: rbac.authorization.k8s.io
kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/clusterrolebinding.yaml
  • DRA 드라이버용 PriorityClass를 만들어요. PriorityClass는 클레임이 있는 파드에 대한 중요한 수명 주기 작업을 담당하는 DRA 드라이버 컴포넌트의 선점(preemption)을 방지해요. 파드 우선순위와 선점에 대해 더 배우려면 여기를 참조하세요.
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: dra-driver-high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for DRA driver pods only."
kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/priorityclass.yaml
  • 위에서 프로비저닝한 권한으로 예시 드라이버 바이너리를 실행하도록 구성된 DaemonSet으로 실제 DRA 드라이버를 배포해요. DaemonSet은 이전 단계에서 ServiceAccount에 부여한 권한을 가져요.
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: dra-example-driver-kubeletplugin
  namespace: dra-tutorial
  labels:
    app.kubernetes.io/name: dra-example-driver
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: dra-example-driver
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app.kubernetes.io/name: dra-example-driver
    spec:
      priorityClassName: dra-driver-high-priority
      serviceAccountName: dra-example-driver-service-account
      securityContext: {}
      containers:
      - name: plugin
        securityContext:
          privileged: true
        image: registry.k8s.io/dra-example-driver/dra-example-driver:v0.2.0
        imagePullPolicy: IfNotPresent
        command: ["dra-example-kubeletplugin"]
        resources: {}
        # Production drivers should always implement a liveness probe
        # For the tutorial we simply omit it
        # livenessProbe:
        #   grpc:
        #     port: 51515
        #     service: liveness
        #   failureThreshold: 3
        #   periodSeconds: 10
        env:
        - name: CDI_ROOT
          value: /var/run/cdi
        - name: KUBELET_REGISTRAR_DIRECTORY_PATH
          value: "/var/lib/kubelet/plugins_registry"
        - name: KUBELET_PLUGINS_DIRECTORY_PATH
          value: "/var/lib/kubelet/plugins"
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        # Simulated number of devices the example driver will pretend to have.
        - name: NUM_DEVICES
          value: "9"
        - name: HEALTHCHECK_PORT
          value: "51515"
        volumeMounts:
        - name: plugins-registry
          mountPath: "/var/lib/kubelet/plugins_registry"
        - name: plugins
          mountPath: "/var/lib/kubelet/plugins"
        - name: cdi
          mountPath: /var/run/cdi
      volumes:
      - name: plugins-registry
        hostPath:
          path: "/var/lib/kubelet/plugins_registry"
      - name: plugins
        hostPath:
          path: "/var/lib/kubelet/plugins"
      - name: cdi
        hostPath:
          path: /var/run/cdi
kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/daemonset.yaml

DaemonSet은 기반 CDI(컨테이너 디바이스 인터페이스, Container Device Interface) 디렉터리와 상호작용하고 kubelet/plugins 디렉터리를 통해 kubelet에 소켓을 노출하는 데 필요한 볼륨 마운트로 구성돼요.

DRA 드라이버 설치 확인

  • 모든 워커 노드에서 DRA 드라이버 DaemonSet의 파드 목록을 가져와요:
kubectl get pod -l app.kubernetes.io/name=dra-example-driver -n dra-tutorial

출력은 다음과 비슷해요:

NAME                                     READY   STATUS    RESTARTS   AGE
dra-example-driver-kubeletplugin-4sk2x   1/1     Running   0          13s
dra-example-driver-kubeletplugin-cttr2   1/1     Running   0          13s
  • 각 노드의 로컬 DRA 드라이버의 초기 책임은 ResourceSlices API에 메타데이터를 게시해 그 노드에서 파드에 사용 가능한 디바이스를 클러스터에 업데이트하는 것이에요. 그 API를 확인해 드라이버가 있는 각 노드가 나타내는 디바이스 클래스를 광고하고 있는지 볼 수 있어요.

사용 가능한 ResourceSlices 확인:

kubectl get resourceslices

출력은 다음과 비슷해요:

NAME                                 NODE           DRIVER            POOL           AGE
kind-worker-gpu.example.com-k69gd    kind-worker    gpu.example.com   kind-worker    19s
kind-worker2-gpu.example.com-qdgpn   kind-worker2   gpu.example.com   kind-worker2   19s

이 시점에서 예시 DRA 드라이버를 성공적으로 설치하고 초기 구성을 확인했어요. 이제 DRA를 사용해 파드를 스케줄링할 준비가 됐어요.

리소스 클레임과 파드 배포

DRA를 사용해 리소스를 요청하려면 파드가 필요로 하는 리소스를 정의하는 ResourceClaims나 ResourceClaimTemplates를 만들어요. 예시 드라이버에서 메모리 용량 속성이 mock GPU 디바이스에 대해 노출돼요. 이 섹션은 CEL(Common Expression Language)을 사용해 ResourceClaim에서 요구 사항을 표현하고, 파드 스펙에서 그 ResourceClaim을 선택하고, 리소스 할당을 관찰하는 방법을 보여 줘요.

이 튜토리얼은 DRA ResourceClaim의 기본 예시 하나만 보여 줘요. ResourceClaims에 대해 더 배우려면 동적 리소스 할당을 읽어보세요.

ResourceClaim 만들기

이 섹션에서는 ResourceClaim을 만들고 파드에서 그것을 참조해요. 클레임이 무엇이든 deviceClassName은 필수 필드이며, 요청 범위를 특정 디바이스 클래스로 좁혀요. 요청 자체는 그 디바이스 클래스를 관리하는 드라이버가 광고할 수 있는 속성을 참조하는 CEL 표현식을 포함할 수 있어요.

이 예시에서는 10Gi가 넘는 메모리 용량을 광고하는 어떤 GPU든 요청을 만들 거예요. 예시 드라이버에서 용량을 노출하는 속성은 device.capacity['gpu.example.com'].memory 형태를 취해요. 또한 클레임 이름이 some-gpu로 설정되어 있다는 점에 유의하세요.

apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
  name: some-gpu
  namespace: dra-tutorial
spec:
  devices:
    requests:
    - name: some-gpu
      exactly:
        deviceClassName: gpu.example.com
        selectors:
        - cel:
            expression: "device.capacity['gpu.example.com'].memory.compareTo(quantity('10Gi')) >= 0"
kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/example/resourceclaim.yaml

그 ResourceClaim을 참조하는 파드 만들기

아래는 방금 만든 ResourceClaim some-gpuspec.resourceClaims.resourceClaimName 필드에서 참조하는 파드 매니페스트예요. 그 클레임의 로컬 이름 gpu는 그런 다음 spec.containers.resources.claims.name 필드에서 사용되어 클레임을 파드의 기반 컨테이너에 할당해요.

apiVersion: v1
kind: Pod
metadata:
  name: pod0
  namespace: dra-tutorial
  labels:
    app: pod
spec:
  containers:
  - name: ctr0
    image: ubuntu:24.04
    command: ["bash", "-c"]
    args: ["export; trap 'exit 0' TERM; sleep 9999 & wait"]
    resources:
      claims:
      - name: gpu
  resourceClaims:
  - name: gpu
    resourceClaimName: some-gpu
kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/example/pod.yaml

파드가 배포되었는지 확인해요:

kubectl get pod pod0 -n dra-tutorial

출력은 다음과 비슷해요:

NAME   READY   STATUS    RESTARTS   AGE
pod0   1/1     Running   0          9s

DRA 상태 살펴보기

파드를 만든 후 클러스터는 ResourceClaim을 충족할 수 있는 노드에 그 파드를 스케줄링하려고 해요. 이 튜토리얼에서 DRA 드라이버는 모든 노드에 배포되어 있고 모든 노드에서 mock GPU를 광고하며, 모두 파드의 클레임을 충족할 충분한 용량을 광고하므로 쿠버네티스는 이 파드를 어떤 노드에든 스케줄링할 수 있고 그 노드의 어떤 mock GPU든 할당할 수 있어요.

쿠버네티스가 파드에 mock GPU를 할당하면, 예시 드라이버는 할당된 각 컨테이너에 환경 변수를 추가해 실제 리소스 드라이버가 어떤 GPU를 주입했을지, 어떻게 구성되었을지 나타내므로 그 환경 변수를 확인해 시스템이 파드를 어떻게 처리했는지 볼 수 있어요.

  • 할당된 mock GPU의 이름을 보고하는 파드 로그를 확인해요:
kubectl logs pod0 -c ctr0 -n dra-tutorial | grep -E "GPU_DEVICE_[0-9]+=" | grep -v "RESOURCE_CLAIM"

출력은 다음과 비슷해요:

declare -x GPU_DEVICE_0="gpu-0"
  • ResourceClaim 객체의 상태를 확인해요:
kubectl get resourceclaims -n dra-tutorial

출력은 다음과 비슷해요:

NAME       STATE                AGE
some-gpu   allocated,reserved   34s

이 출력에서 STATE 열은 ResourceClaim이 allocated(할당됨)되고 reserved(예약됨)되었음을 보여 줘요.

  • some-gpu ResourceClaim의 세부 사항을 확인해요. ResourceClaim의 status 스탠자는 할당된 디바이스와 그것이 예약된 파드에 대한 정보가 있어요:
kubectl get resourceclaim some-gpu -n dra-tutorial -o yaml

출력은 다음과 비슷해요:

 1 apiVersion: resource.k8s.io/v1
 2 kind: ResourceClaim
 3 metadata:
 4   creationTimestamp: "2025-08-20T18:17:31Z"
 5   finalizers:
 6   - resource.kubernetes.io/delete-protection
 7   name: some-gpu
 8   namespace: dra-tutorial
 9   resourceVersion: "2326"
10   uid: d3e48dbf-40da-47c3-a7b9-f7d54d1051c3
11 spec:
12   devices:
13     requests:
14     - exactly:
15         allocationMode: ExactCount
16         count: 1
17         deviceClassName: gpu.example.com
18         selectors:
19         - cel:
20             expression: device.capacity['gpu.example.com'].memory.compareTo(quantity('10Gi'))
21               >= 0
22       name: some-gpu
23 status:
24   allocation:
25     devices:
26       results:
27       - device: gpu-0
28         driver: gpu.example.com
29         pool: kind-worker
30         request: some-gpu
31     nodeSelector:
32       nodeSelectorTerms:
33       - matchFields:
34         - key: metadata.name
35           operator: In
36           values:
37           - kind-worker
38   reservedFor:
39   - name: pod0
40     resource: pods
41     uid: c4dadf20-392a-474d-a47b-ab82080c8bd7
  • 드라이버가 디바이스 할당을 어떻게 처리했는지 확인하려면 드라이버 DaemonSet 파드의 로그를 가져와요:
kubectl logs -l app.kubernetes.io/name=dra-example-driver -n dra-tutorial

출력은 다음과 비슷해요:

I0820 18:17:44.131324       1 driver.go:106] PrepareResourceClaims is called: number of claims: 1
I0820 18:17:44.135056       1 driver.go:133] Returning newly prepared devices for claim 'd3e48dbf-40da-47c3-a7b9-f7d54d1051c3': [{[some-gpu] kind-worker gpu-0 [k8s.gpu.example.com/gpu=common k8s.gpu.example.com/gpu=d3e48dbf-40da-47c3-a7b9-f7d54d1051c3-gpu-0]}]

이제 DRA를 사용해 디바이스를 클레임하는 파드를 성공적으로 배포했고, 파드가 적절한 노드에 스케줄링되었으며, 관련 DRA API 유형이 할당 상태로 업데이트되었음을 확인했어요.

클레임이 있는 파드 삭제하기

클레임이 있는 파드가 삭제되면 DRA 드라이버는 리소스를 할당 해제해 향후 스케줄링에 사용할 수 있게 해요. 이 동작을 검증하려면 이전 단계에서 만든 파드를 삭제하고 ResourceClaim과 드라이버의 해당 변경을 지켜봐요.

pod0 파드를 삭제해요:

kubectl delete pod pod0 -n dra-tutorial

출력은 다음과 비슷해요:

pod "pod0" deleted

DRA 상태 관찰

파드가 삭제되면 드라이버는 디바이스를 ResourceClaim에서 할당 해제하고 쿠버네티스 API의 ResourceClaim 리소스를 업데이트해요. ResourceClaim은 새 파드에서 참조될 때까지 pending 상태를 가져요.

  • some-gpu ResourceClaim의 상태를 확인해요:
kubectl get resourceclaims -n dra-tutorial

출력은 다음과 비슷해요:

NAME       STATE     AGE
some-gpu   pending   76s
  • 드라이버 로그를 확인해 드라이버가 이 클레임에 대한 디바이스 준비 해제를 처리했는지 확인해요:
kubectl logs -l app.kubernetes.io/name=dra-example-driver -n dra-tutorial

출력은 다음과 비슷해요:

I0820 18:22:15.629376       1 driver.go:138] UnprepareResourceClaims is called: number of claims: 1

이제 클레임이 있는 파드를 삭제했고, 드라이버가 기반 하드웨어 리소스를 준비 해제하고 DRA API를 업데이트해 리소스가 향후 스케줄링에 다시 사용 가능함을 반영하는 것을 관찰했어요.

정리

이 튜토리얼에서 만든 리소스를 정리하려면 다음 단계를 따르세요:

kubectl delete namespace dra-tutorial
kubectl delete deviceclass gpu.example.com
kubectl delete clusterrole dra-example-driver-role
kubectl delete clusterrolebinding dra-example-driver-role-binding
kubectl delete priorityclass dra-driver-high-priority

더 알아보기 (Learn more)

  • DRA에 대해 더 배우기.
  • DRA로 워크로드에 디바이스 할당하기.