- 들어가며 — 한 장을 여럿이 쓰는 두 가지 방법
- time-slicing — 시간을 나눈다
- MIG — 하드웨어를 나눈다
- 격리 수준의 차이가 만드는 결과
- 무엇을 언제 고르나
- 마치며 — 공유는 자원 문제가 아니라 신뢰 문제다
- 직접 해보기
- 시리즈
- 참고 자료
들어가며 — 한 장을 여럿이 쓰는 두 가지 방법
앞 글에서 GPU는 확장 리소스라 정수로만 요청되고, 하드웨어에 격리 장치가 없어 그냥 나눠 쓸 수 없다는 이야기를 했습니다. 그런데 실무에서는 나눠 써야 할 이유가 계속 생깁니다. 노트북 크기의 추론 모델 여러 개를 한 장에 올리고 싶고, 개발자 여덟 명에게 카드 한 장씩 줄 예산은 없습니다.
NVIDIA가 제공하는 답은 두 가지고, 둘은 이름만 비슷할 뿐 성질이 다릅니다. 하나는 시간을 나누고 하나는 하드웨어를 나눕니다. 고르는 기준은 성능이 아니라 격리입니다.
메트릭 이름과 설정은 2026-08-12에 공식 문서·저장소에서 확인했습니다. 버전에 따라 다를 수 있으니 사용 중인 버전에서 다시 확인하세요.
time-slicing — 시간을 나눈다
time-slicing은 디바이스 플러그인이 물리 GPU 하나를 여러 개의 복제본으로 광고하게 만드는 설정입니다. 하드웨어는 전혀 바뀌지 않습니다. 스케줄러가 보는 숫자만 늘어납니다.
공식 문서가 보여 주는 ConfigMap 구조는 이렇습니다.
apiVersion: v1
kind: ConfigMap
metadata:
name: time-slicing-config
data:
any: |-
version: v1
flags:
migStrategy: none
sharing:
timeSlicing:
renameByDefault: false
failRequestsGreaterThanOne: false
resources:
- name: nvidia.com/gpu
replicas: 4
핵심 필드는 세 개입니다. replicas는 카드 한 장을 몇 개로 광고할지 정합니다. renameByDefault는 그 복제본을 원래 이름으로 광고할지 공유 전용 이름으로 광고할지 고릅니다. 값이 참이면 광고되는 리소스가 nvidia.com/gpu.shared로 바뀝니다. 거짓이면 이름은 nvidia.com/gpu 그대로입니다. failRequestsGreaterThanOne은 한 컨테이너가 복제본을 두 개 이상 요청했을 때 실패시킬지를 정합니다.
renameByDefault가 실무에서 가장 위험한 스위치입니다. 거짓으로 두면 기존 매니페스트가 손대지 않았는데도 어느 날부터 공유 GPU를 받게 됩니다. 참으로 두면 이름이 바뀌므로 공유를 원하는 파드는 매니페스트를 고쳐야 하고, 그 대신 사고가 조용히 나지 않습니다.
적용은 ClusterPolicy를 통해 합니다.
kubectl create -n gpu-operator -f time-slicing-config.yaml
kubectl patch clusterpolicies.nvidia.com/cluster-policy \
-n gpu-operator --type merge \
-p '{"spec": {"devicePlugin": {"config": {"name": "time-slicing-config-all", "default": "any"}}}}'
노드마다 다른 설정을 주고 싶으면 노드에 nvidia.com/device-plugin.config 라벨을 붙여 ConfigMap의 어느 키를 쓸지 지정합니다. 복제 배수는 nvidia.com/gpu.replicas 라벨로 확인할 수 있습니다.
그리고 문서가 굵게 강조하는 한 문장이 있습니다. MIG와 달리 복제본 사이에는 메모리 격리도 장애 격리도 없다는 것입니다. 이 문장의 실무적 의미는 뒤에서 다시 다룹니다.
MIG — 하드웨어를 나눈다
MIG는 GPU를 하드웨어 수준에서 여러 인스턴스로 쪼갭니다. 인스턴스마다 메모리 슬라이스와 연산 자원이 물리적으로 분리되므로, 문서 표현대로 CUDA 애플리케이션에 분리되고 안전한 GPU 인스턴스를 제공합니다. 대신 조건이 있습니다. Ampere 이후 아키텍처 기반 GPU에서만 동작합니다. A100이 대표적인 예로 문서에 나옵니다.
GPU Operator에서 MIG는 노드 라벨로 조작합니다.
# 노드가 MIG를 지원하는지 확인
kubectl get nodes -L nvidia.com/mig.capable,nvidia.com/mig.strategy
# 프로파일 적용
kubectl label nodes <노드이름> nvidia.com/mig.config=all-1g.5gb --overwrite
# 적용 상태 추적 (pending / rebooting / success / failed)
kubectl get node <노드이름> -o jsonpath='{.metadata.labels.nvidia\.com/mig\.config\.state}{"\n"}'
nvidia.com/mig.config.state가 상태 머신 역할을 합니다. 라벨을 붙인 직후 pending으로 갔다가, 필요하면 rebooting을 거쳐 success나 failed로 끝납니다. 실무에서 이 라벨을 안 보고 기다리다 시간을 버리는 경우가 많습니다.
리소스가 어떻게 광고되는지는 전략에 따라 갈립니다. single 전략은 노드의 모든 GPU에서 MIG가 켜져 있고 프로파일이 통일된 경우를 다루고, mixed 전략은 그렇지 않은 경우를 다룹니다. mixed에서는 프로파일별로 리소스가 갈라져서, 저장소 문서 기준으로 A100 40GB에서는 nvidia.com/mig-1g.5gb, nvidia.com/mig-2g.10gb, nvidia.com/mig-3g.20gb, nvidia.com/mig-7g.40gb가, A100 80GB에서는 nvidia.com/mig-1g.10gb, nvidia.com/mig-2g.20gb, nvidia.com/mig-3g.40gb, nvidia.com/mig-7g.80gb가 나타납니다. 프로파일별 개수는 nvidia.com/mig-1g.10gb.count 같은 라벨로도 노출됩니다.
Helm 차트의 기본 전략은 mig.strategy: single입니다. MIG Manager에 커스텀 설정을 주려면 ConfigMap에 config.yaml이라는 키가 반드시 있어야 한다고 차트 주석이 명시합니다.
격리 수준의 차이가 만드는 결과
두 방식의 차이를 표로 정리하면 이렇습니다.
| 항목 | time-slicing | MIG |
|---|---|---|
| 나누는 대상 | 시간 | 하드웨어 |
| 메모리 격리 | 없음 | 있음 |
| 장애 격리 | 없음 | 있음 |
| 지원 하드웨어 | 사실상 제한 없음 | Ampere 이후 |
| 적용 방식 | ConfigMap과 ClusterPolicy | 노드 라벨과 MIG Manager |
| 노드 재시작 | 불필요 | 프로파일 전환 시 필요할 수 있음 |
| 광고되는 리소스 | 원래 이름 또는 공유 전용 이름 | 프로파일별로 분리된 이름 |
가장 중요한 줄은 격리 두 줄입니다. time-slicing에서 복제본 하나가 VRAM을 다 먹으면 같은 카드의 다른 복제본이 메모리 할당에 실패합니다. 스케줄러 관점에서는 두 파드 모두 정상적으로 자원을 받았는데, 실제로는 한쪽이 다른 쪽을 굶기고 있는 상태입니다. 더 나쁜 것은 장애 격리가 없다는 쪽입니다. 한 워크로드가 GPU를 비정상 상태로 만들면 같은 카드의 모든 복제본이 함께 무너집니다.
그래서 판단 기준이 나옵니다. 복제본끼리 서로 신뢰할 수 있는가. 같은 팀의 같은 서비스를 여러 개 띄우는 것이라면 신뢰할 수 있습니다. 서로 다른 팀, 서로 다른 고객, 혹은 사용자가 코드를 올리는 노트북 환경이라면 신뢰할 수 없습니다.
무엇을 언제 고르나
정리하면 선택은 대체로 이렇게 갈립니다.
time-slicing이 맞는 경우는 개발과 실험 환경, 인터랙티브 노트북, 그리고 GPU를 아주 짧게 쓰는 배치 작업입니다. 공통점은 격리가 깨졌을 때 손해가 재시도로 끝난다는 것입니다. 신뢰 경계 안쪽이고, 사람이 보고 있고, 실패해도 다시 돌리면 됩니다.
MIG가 맞는 경우는 프로덕션 추론 서빙, 멀티테넌트, 그리고 지연 시간을 약속해야 하는 서비스입니다. 특히 SLO를 걸어야 하는 서비스라면 선택지가 사실상 하나입니다. 옆 인스턴스의 부하가 내 지연 시간에 영향을 주는 상태에서는 어떤 약속도 지킬 수 없습니다.
둘 다 아닌 경우도 흔합니다. 큰 모델을 서빙하는데 VRAM이 이미 빠듯하다면 나눌 것이 없습니다. 이때 필요한 것은 공유가 아니라 배치 크기와 KV 캐시 설정을 조정하는 일이고, 그 판단에는 관측 데이터가 필요합니다. 다음 두 글이 그 데이터를 어디서 얻는지 다룹니다.
마치며 — 공유는 자원 문제가 아니라 신뢰 문제다
GPU 공유를 자원 활용률 문제로만 보면 거의 항상 time-slicing으로 결론이 납니다. 설정이 간단하고 하드웨어를 가리지 않고 즉시 효과가 보이기 때문입니다. 그러다 어느 날 한 파드가 다른 파드를 죽이고, 원인을 찾는 데 하루가 걸립니다.
공유 방식은 활용률이 아니라 신뢰 경계로 고르는 것이 맞습니다. 같은 경계 안이면 시간을 나누고, 경계를 넘으면 하드웨어를 나눕니다. 하드웨어가 안 되면 나누지 않습니다. 이 순서를 지키면 나중에 설명하기 어려운 장애가 크게 줄어듭니다.
다음 글에서는 이렇게 구성한 GPU가 실제로 어떻게 쓰이고 있는지를 보는 방법, 즉 DCGM Exporter를 다룹니다.
직접 해보기
- K8s 실습 랩 — ConfigMap과 노드 라벨을 다루는 흐름을 직접 따라가 보세요.
- LLM GPU 메모리(VRAM) 계산기 — 모델을 몇 개나 한 장에 올릴 수 있는지 먼저 계산해 보세요.
- Kubestronaut 퀴즈 — 라벨과 셀렉터 개념을 문제로 점검해 보세요.
시리즈
참고 자료
- GPU Operator Time-Slicing 문서: https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/gpu-sharing.html
- GPU Operator MIG 문서: https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/gpu-operator-mig.html
- NVIDIA k8s-device-plugin 저장소: https://github.com/NVIDIA/k8s-device-plugin
- gpu-operator 저장소 values.yaml: https://github.com/NVIDIA/gpu-operator/blob/main/deployments/gpu-operator/values.yaml
현재 단락 (1/66)
앞 글에서 GPU는 확장 리소스라 정수로만 요청되고, 하드웨어에 격리 장치가 없어 그냥 나눠 쓸 수 없다는 이야기를 했습니다. 그런데 실무에서는 나눠 써야 할 이유가 계속 생깁니다...