쿠버네티스에서 GPU 한 장을 여러 파드가 나눠 쓰기: Time-Slicing vs MIG
냉냉장고를사다줘·2026년 8월 17일·조회 12
GPU 노드를 처음 붙이고 나면 곧 이런 상황을 만난다. A100 한 장이 노드에 꽂혀 있는데, 추론 파드 하나가 그걸 통째로 물고 있고 나머지 파드는 Pending으로 줄을 선다. GPU 메모리 사용률을 보면 3GB밖에 안 쓰는데도 그렇다. 쿠버네티스 기본 스케줄러에게 GPU는 정수 단위 자원이라 그렇다. 한 장은 한 파드에게 통째로 나간다.
결론부터 말하면, GPU 한 장을 여러 파드가 나눠 쓰는 방법은 크게 두 가지다. Time-Slicing은 GPU를 시간으로 쪼개 여러 파드가 번갈아 쓰게 하고, MIG(Multi-Instance GPU)는 하드웨어 수준에서 GPU를 물리적으로 분할한다. Time-Slicing은 격리가 없어 개발/테스트나 부하가 낮은 추론에 맞고, MIG는 메모리와 연산을 실제로 나눠 격리가 필요한 멀티테넌트 운영에 맞는다. 아래에서 각각을 NVIDIA GPU Operator로 설정하는 방법과 격리 차이, 선택 기준을 차례로 살펴본다.
1. 두 방식이 무엇인지부터
Time-Slicing은 GPU 하나를 여러 개의 가상 복제본(replica)으로 광고하는 방식이다. 물리 GPU는 그대로 하나지만, 디바이스 플러그인이 nvidia.com/gpu: 4처럼 여러 개인 척 노출한다. 실제 실행은 GPU가 컨텍스트를 시분할로 번갈아 처리한다. 즉 파드들이 GPU 시간을 나눠 쓰는 것이지, 메모리나 연산 코어를 나눠 갖는 게 아니다.
MIG는 Ampere 세대 이상(A100, A30, H100 등)에서 지원하는 하드웨어 파티셔닝이다. GPU를 GPU Instance(GI)라는 격리된 조각으로 쪼갠다. 각 조각은 전용 SM(연산 유닛), 전용 L2 캐시 슬라이스, 전용 메모리를 갖는다. 한 조각에서 무슨 일이 나든 다른 조각은 영향받지 않는다.
핵심 차이는 격리다. NVIDIA 문서도 Time-Slicing에 대해 "복제본 사이에 메모리나 결함 격리가 없다(no memory or fault-isolation between replicas)"고 못 박는다. 파드 하나가 GPU 메모리를 다 먹으면 같은 GPU를 쓰는 다른 파드가 OOM으로 죽는다. MIG는 그런 일이 없다.
2. 사전 준비: GPU Operator
두 방식 모두 NVIDIA GPU Operator를 깐 상태를 전제로 한다. Operator가 드라이버, 컨테이너 툴킷, 디바이스 플러그인, MIG Manager를 한 번에 관리해준다. Helm으로 설치한다.
설치 후 노드 라벨을 확인한다. GPU가 잡히면 nvidia.com/gpu.count, nvidia.com/gpu.product 같은 라벨이 붙는다.
kubectl get nodes -o json | jq '.items[].metadata.labels | with_entries(select(.key|startswith("nvidia.com")))'
여기서 한 번 걸리기 쉽다. GPU Operator 버전과 노드 커널 헤더가 안 맞으면 드라이버 데몬셋이 CrashLoopBackOff로 돈다. kubectl logs -n gpu-operator -l app=nvidia-driver-daemonset로 로그부터 확인한다. 클라우드 관리형 노드(EKS GPU AMI 등)를 쓰면 드라이버가 이미 깔려 있으니 --set driver.enabled=false로 Operator의 드라이버 설치를 끄는 편이 깔끔하다.
3. Time-Slicing 설정
Time-Slicing은 ConfigMap 하나와 ClusterPolicy 패치로 끝난다. 먼저 GPU 하나를 4개로 쪼개는 설정을 만든다.
kubectl get node <node-name> -o jsonpath='{.status.capacity.nvidia\.com/gpu}'
4
이제 파드 4개가 각각 nvidia.com/gpu: 1을 요청해도 GPU 한 장에 다 올라간다. 다만 이들은 GPU 메모리를 공유하므로, 큰 모델 하나를 로드하면 나머지 파드가 메모리를 못 잡을 수 있다는 걸 잊지 마라. 시분할은 시간만 나눌 뿐 메모리를 지켜주지 않는다.
프로필 이름은 조각 개수와 메모리 크기를 그대로 담고 있으며, 사용 가능한 조합은 GPU 모델마다 다르다.
4. MIG 설정
MIG는 전략(strategy) 개념부터 잡아야 한다. GPU Operator는 두 가지를 지원한다.
single: 노드의 모든 GPU가 같은 MIG 프로필로 동일하게 쪼개진다. 자원 이름은 nvidia.com/gpu 그대로 노출된다. 노드 전체를 한 종류 조각으로 쓸 때 단순하다.
mixed: 한 노드 안에서 GPU마다 다른 프로필을 섞거나, 일부만 MIG를 켤 수 있다. 자원 이름이 nvidia.com/mig-1g.5gb처럼 프로필별로 갈라져 노출된다.
설치 시점에 전략을 정한다. 이미 Operator가 깔려 있으면 재설치하거나 값을 패치한다.
프로필 이름의 규칙은 {GI개수}g.{메모리}gb다. A100 40GB를 예로 들면 대표 프로필은 이렇다. 사용 가능한 프로필과 최대 개수는 GPU 모델(A100 40GB/80GB, H100 등)에 따라 다르다.
1g.5gb: 조각 하나가 SM 1/7, 메모리 5GB. 최대 7개까지.
2g.10gb: 메모리 10GB. 최대 3개.
3g.20gb: 메모리 20GB. 최대 2개.
7g.40gb: GPU 전체. 1개(사실상 MIG 비분할과 동일).
라벨을 걸면 MIG Manager 파드가 작업을 시작한다. 진행 상태는 노드 라벨로 추적한다.
kubectl get node <node-name> -o jsonpath='{.metadata.labels.nvidia\.com/mig\.config\.state}'
success
pending이나 rebooting에서 오래 멈춰 있으면 MIG Manager 로그를 본다. 흔한 원인은 GPU에 아직 프로세스가 붙어 있어 MIG 모드 전환이 막히는 경우다. MIG 모드를 켜려면 GPU를 완전히 비워야 한다. 실행 중인 GPU 파드가 있으면 먼저 내려야 한다.
메모리 격리: Time-Slicing은 없음(전 파드가 GPU 메모리 공유). MIG는 있음(조각마다 전용 메모리).
연산 격리: Time-Slicing은 없음(시간으로 번갈아 씀, 성능 간섭 발생). MIG는 있음(조각마다 전용 SM).
결함 격리: Time-Slicing은 없음(한 파드가 GPU를 죽이면 같이 죽음). MIG는 있음(조각 단위 격리).
지원 GPU: Time-Slicing은 사실상 모든 NVIDIA GPU. MIG는 Ampere 이상(A100, A30, H100 등).
세분화 단위: Time-Slicing은 replicas 숫자만큼 임의로. MIG는 하드웨어가 정한 프로필 범위 내.
동적 변경: Time-Slicing은 ConfigMap 수정 후 플러그인 재시작. MIG는 GPU 리셋이 필요해 더 무겁다.
6. 워크로드별 선택 기준
고르는 기준은 단순하다. 격리가 필요하냐가 첫 갈림길이다.
Time-Slicing을 쓸 상황: 개발/테스트 환경에서 여러 사람이 GPU 노드를 나눠 쓸 때, 부하가 낮고 간헐적인 추론 파드를 여러 개 올릴 때, MIG를 지원하지 않는 구형 GPU(T4, V100 등)일 때. 신뢰하는 내부 팀이 같은 GPU를 쓰는 상황이면 격리 없이도 무방하다. 설정이 가볍고 GPU 종류를 안 가린다는 게 장점이다.
MIG를 쓸 상황: 여러 테넌트가 같은 GPU를 나눠 쓰는데 서로 간섭하면 안 될 때, SLA가 걸린 추론 서비스라 성능이 예측 가능해야 할 때, 파드마다 메모리 상한을 하드웨어로 보장해야 할 때. A100/H100처럼 크고 비싼 GPU를 여러 작은 워크로드로 잘게 쓸 때 특히 유리하다. "한 파드의 폭주가 옆 파드를 죽이면 안 된다"가 요구사항이면 답은 MIG다.
둘을 겹쳐 쓸 수도 있다. MIG로 GPU를 조각낸 다음 각 조각에 다시 Time-Slicing을 걸어 격리된 조각 안에서 시분할 오버서브스크립션을 하는 구성이다. GPU Operator의 migStrategy와 timeSlicing을 함께 설정하면 된다. 다만 운영 복잡도가 확 올라가니, 먼저 한 방식으로 충분한지부터 따져보는 걸 권한다.
정리하면, 격리가 필요 없고 GPU를 최대한 우겨넣는 게 목적이면 Time-Slicing, 격리와 성능 예측이 목적이면 MIG다. 그리고 어느 쪽이든 GPU Operator를 통하면 노드에 SSH로 들어가 nvidia-smi를 두들기는 수작업 없이 선언적으로 관리된다는 점이 크다.
자주 묻는 질문
Time-Slicing의 replicas 숫자를 늘리면 GPU 메모리도 그만큼 나눠지나?
아니다. replicas는 스케줄링 슬롯 수만 늘린다. GPU 메모리는 여전히 전 파드가 공유하며, 하드웨어 상한이 파드별로 걸리지 않는다. 큰 모델을 로드하는 파드가 메모리를 다 쓰면 같은 GPU의 다른 파드가 OOM으로 죽을 수 있다. 파드별 메모리 격리가 필요하면 MIG를 써야 한다.
MIG는 아무 NVIDIA GPU에서나 되나?
아니다. MIG는 Ampere 세대 이상에서만 지원한다. A100, A30, H100 등이 대상이다. T4나 V100 같은 이전 세대는 MIG를 지원하지 않으므로, 이 GPU에서 공유가 필요하면 Time-Slicing이 유일한 선택이다.
Time-Slicing ConfigMap을 바꿨는데 반영이 안 된다.
GPU Operator는 time-slicing ConfigMap의 변경을 자동 감지하지 않는다. 값을 수정한 뒤 nvidia-device-plugin-daemonset을 직접 재시작해야 한다. kubectl rollout restart -n gpu-operator daemonset/nvidia-device-plugin-daemonset 로 다시 굴리고 노드 capacity를 확인하면 된다.
mig.strategy의 single과 mixed는 어떻게 고르나?
노드의 모든 GPU를 같은 프로필로 동일하게 쪼갤 거면 single이 단순하다. 자원 이름이 nvidia.com/gpu 그대로 유지된다. 노드 안에서 GPU마다 다른 프로필을 섞거나 일부만 MIG를 켜려면 mixed를 쓴다. mixed에서는 자원 이름이 nvidia.com/mig-1g.5gb처럼 프로필별로 갈라진다.
MIG와 Time-Slicing을 같이 쓸 수 있나?
가능하다. MIG로 GPU를 격리된 조각으로 나눈 뒤, 각 조각에 다시 Time-Slicing을 걸어 조각 안에서 오버서브스크립션할 수 있다. GPU Operator에서 migStrategy와 timeSlicing을 함께 설정하면 된다. 다만 운영 복잡도가 올라가므로 한 방식으로 충분한지 먼저 검토하는 것이 좋다.