Skip to content
cover-devops

쿠버네티스에서 GPU 리소스를 효율적으로 활용하는 방법

  • DevOps

📅 July 08, 2022

⏱️3 min read

GPU는 강력한 연산 기능을 제공하지만 비용이 많이 들기 때문에 제한된 리소스를 효율적으로 활용하는 것이 중요합니다. 이번 글에서는 NVIDIA GPU의 리소스 공유를 지원하기 위한 방법으로 Time SlicingMIG에 대해 정리해보려 합니다.


GPU 리소스가 낭비되고 있다?

gpu util

여러 아키텍쳐(암페어, 파스칼 등)로 구성된 GPU들을 모아 쿠버네티스 노드 풀을 구성하고 사용자들은 GPU 리소스를 할당받아 사용하는 환경이라고 가정해보겠습니다. 사용자들은 GPU 할당을 못 받는 상황임에도 실제 GPU 사용량을 측정해보면 생각보다 낮게 유지되고 있는 경우가 있습니다. 워크로드에 따라 필요한 리소스가 다르기 때문입니다.

노트북 환경은 항상 개발을 하는게 아니기 때문에 idle 상태로 대기하는 시간이 많습니다. 작은 배치 사이즈로 운영되는 인퍼런스의 경우, 트래픽에 따라 사용량이 달라질 수 있습니다. 따라서 이런 상황에서는 항상 리소스를 점유하기 보다 필요할 때 bursting 가능한 방식으로 운영하는 것이 효율적입니다.

apiVersion: v1
kind: Pod
metadata:
  name: cuda-vector-add
spec:
  restartPolicy: OnFailure
  containers:
    - name: cuda-vector-add
      image: "k8s.gcr.io/cuda-vector-add:v0.1"
      resources:
        limits:
          nvidia.com/gpu: 1 # GPU 1개 요청하기

쿠버네티스에서는 디바이스 플러그인을 통해 Pod가 GPU 리소스를 요청할 수 있습니다. 하지만 Pod는 하나 이상의 GPU만 요청할 수 있으며 CPU와 달리 GPU의 일부(fraction)를 요청하는 것은 불가능합니다. 예를 들어 간단한 실험에 최신 버전의 고성능 GPU 1개를 온전히 할당 받는 것은 낭비입니다. NVIDIA 문서에서는 SW/HW 관점에서 GPU 리소스를 효율적으로 사용하기 위해 다양한 방법을 소개합니다. 그 중 Time SlicingMIG에 대해 알아보겠습니다.


Time Slicing

Time Slicing은 GPU의 시간 분할 스케줄러입니다. 파스칼 아키텍쳐부터 지원하는 compute preemption 기능을 활용한 방법입니다. 각 컨테이너는 공평하게 timeslice를 할당받게 되지만 전환할 때 context switching 비용이 발생합니다.

kind: ConfigMap
metadata:
  name: time-slicing-config
  namespace: gpu-operator
data:
  a100-40gb: |-
    version: v1
    sharing:
      timeSlicing:
        resources:
        - name: nvidia.com/gpu
          replicas: 8
        - name: nvidia.com/mig-1g.5gb
          replicas: 1
  tesla-t4: |-
    version: v1
    sharing:
      timeSlicing:
        resources:
        - name: nvidia.com/gpu
          replicas: 4

NVIDIA GPU Operator에서는 위와 같이 ConfigMap을 사용하거나 node label을 통해 설정할 수 있습니다. 설정한 이후에 노드를 확인해보면 아래와 같이 리소스에 값이 추가된 것을 확인할 수 있습니다.

$ kubectl describe node $NODE

status:
  capacity:
    nvidia.com/gpu: 8
  allocatable:
    nvidia.com/gpu: 8

최대 8개 컨테이너까지 timeslice 방식으로 shared GPU를 사용할 수 있다는 것을 의미합니다. 이 방법은 GPU 메모리 limit 설정을 강제하는 것이 아니기 때문에 OOM이 발생할 수도 있습니다. 이를 방지하려면 GPU를 사용하는 컨테이너 수를 모니터링하고 TensorflowPyTorch 같은 프레임워크에서 총 GPU 메모리 제한 설정이 필요합니다.


Multi instance GPU (MIG)

mig

MIG는 A100과 같은 암페어 아키텍처 기반 GPU를 최대 7개의 개별 GPU 인스턴스로 분할해서 사용할 수 있는 기능입니다. 분할된 인스턴스를 파티션이라고 부르는데, 각 파티션은 물리적으로 격리되어 있기 때문에 안전하게 병렬로 사용할 수 있습니다.

part

위의 표와 같이 설정을 통해 파티션 크기를 조정할 수 있습니다. 표에서 unit은 하나의 파티션에 몇 개가 할당되는지를 의미합니다. A100의 경우, 최대 7개의 compute unit과 8개의 memory unit을 가질 수 있습니다 (각 5GB 메모리). 파티션은 <compute>g.<memory>gb 형식을 따르고 있습니다.

$ kubectl label nodes $NODE nvidia.com/mig.config=all-1g.5gb
$ kubectl describe node $NODE

status:
  capacity:
    nvidia.com/gpu: 7
  allocatable:
    nvidia.com/gpu: 7

이번에도 노드 설정 후, 값을 확인해보면 7이 들어가 있습니다.
1g.5gb 크기의 파티션을 7개까지 사용할 수 있다는 의미입니다.

apiVersion: v1
kind: Deployment
metadata:
  name: cuda-vectoradd
spec:
  replicas: 7
  template:
    spec:
      nodeSelector:
        nvidia.com/gpu.product: A100-SXM4-40GB-MIG-1g.5gb
    containers:
    - name: vectoradd
      image: nvidia/samples:vectoradd-cuda11.2.1
      resources:
        limits:
          nvidia.com/gpu: 1

위와 같이 MIG를 통해 Pod 마다 1개의 파티션을 갖도록 설정해서 7개의 replica 구성하는 것도 가능합니다. 이처럼 사용자는 MIG를 통해 GPU를 최대로 활용할 수 있습니다.


Time Slicing vs MIG

comp

두 방식을 비교해보면 위의 표와 같습니다. Time Slicing 방식은 7개 이상의 컨테이너를 사용할 수 있습니다. 따라서 bursting 워크로드에 적합한 방식이라고 볼 수 있습니다. 반면 MIG는 적은 양의 고정된 사용량을 가지는 워크로드에 적합합니다. A100은 MIG를 통해 분할하고 그 외의 GPU는 Time Slicing을 사용하는 방식으로 함께 사용할 수 있으니 워크로드에 맞는 방식을 선택하는 것이 중요합니다.


Reference

← PrevNext →
  • Powered by Contentful
  • COPYRIGHT © 2020 by @swalloow