Skip to document
pieroot log
Markdown Preview

GPU 환경 구축을 위한 Docker와 NVIDIA Container Toolkit 완벽 가이드: 효율적인 리소스 관리와 딥러닝 최적화

Frontmatter

Docker는 경량 컨테이너 기술로, NVIDIA Container Toolkit을 통해 GPU 자원을 관리할 수 있다. GPU 가상화 방식에는 VM 환경에서의 Passthrough와 vGPU가 있으며, Docker 환경에서는 CUDA 드라이버를 매핑하여 GPU에 접근한다. 운영 환경에서는 CPU, 메모리, GPU, 디스크 제한을 설정하여 시스템 안정성을 보장해야 한다.

GPU 환경 구축을 위한 Docker와 NVIDIA Container Toolkit 완벽 가이드: 효율적인 리소스 관리와 딥러닝 최적화

Docker란?


Docker는 Linux 컨테이너를 만들고 사용할 수 있도록 하는 컨테이너화 기술입니다.
가상화 기술과 비교하면 이해하기 쉬운데, 간단히 정리해볼게요.
notion image

가상화 vs 컨테이너

1. 가상화 (Virtualization)

하이퍼바이저(Hypervisor)를 사용하여 Host OS 위에 Guest OS를 올려 각 시스템을 완전히 격리하는 방식입니다.
  • 장점: 하드웨어 수준의 완벽한 분리로 보안성이 높습니다. 기존 인프라를 그대로 가상화하여 옮기기 좋습니다.
  • 단점: 각 VM마다 OS가 포함되므로 무겁고(Resource Overhead), 부팅 시간이 깁니다.

2. 컨테이너 (Container)

Host OS의 커널(Kernel)을 공유하면서, 애플리케이션과 필요한 라이브러리/종속성만 격리하여 실행하는 방식입니다.
  • 장점: 가볍고 빠릅니다. CI/CD 파이프라인에서 신속한 배포가 가능합니다.
  • 단점: 커널을 공유하므로 커널 취약점에 노출될 수 있고, Host OS와 다른 종류의 OS(예: Linux 위에 Windows)를 실행하는 데 제약이 있습니다.
핵심 정리
  • 가상화(VM): 완벽한 격리 (보안 중시), 무겁고 느림
  • 컨테이너(Docker): 가벼운 격리 (효율성 중시), 빠르고 가벼움
  • 둘 다 Host OS의 CPU, RAM, Disk를 공유하지만, 격리 수준이 다릅니다.

GPU 가상화


GPU를 활용한 딥러닝/ML 환경을 구축할 때, GPU 자원을 어떻게 할당하느냐가 핵심입니다.

1. 가상화(VM) 환경에서의 GPU

VMware, VirtualBox, Xen 같은 가상화 환경에서는 NVIDIA GRID vGPU 패키지를 사용하여 GPU 자원을 관리할 수 있습니다.
적용 방식은 두 가지로 나뉘니다:
  • Passthrough: 하나의 VM이 하나의 GPU를 직접 할당받는 방식 (1:1 매핑)
  • vGPU: 하나의 물리 GPU를 여러 VM에 나눠 할당하는 방식 (1:N 매핑)
GPU 지원 제한
  • 서버급 GPU (Tesla, A100 등): NVIDIA GRID vGPU 설치 시 VM에서 접근 가능
  • 소비자급 GPU (GeForce): VM에서 공식 지원 안 됨
notion image
vGPU 사용 시 동일한 arch 로만 나눌 수 있음
vGPU 사용 시 동일한 arch 로만 나눌 수 있음

2. 컨테이너(Docker) 환경에서의 GPU

Docker는 NVIDIA Container Toolkit을 사용하여 GPU 자원에 접근할 수 있습니다.
notion image
Host OS의 CUDA Driver를 컨테이너 내부의 CUDA Toolkit과 매핑하여, 애플리케이션이 GPU에 접근할 수 있게 합니다.

NVIDIA Container Toolkit 설치


이제 Docker에서 GPU를 사용하기 위해 NVIDIA Container Toolkit을 설치해보겠습니다.
아래 과정은 Ubuntu 22.04 LTS 환경을 기준으로 작성되었습니다.
yaml
ubuntu 22.04
RTX 3060 vram 12GB
nvidia driver 550.54.15-server
cuda 12.4
환경
notion image

1. 사전 준비 (Prerequisites)

Docker가 설치된 서버에 NVIDIA Driver가 먼저 설치되어 있어야 합니다.
shell
$ nvidia-smi
notion image
CUDA 10.0 이후 버전부터는 NVIDIA Container Toolkit을 사용하며, 그 이전 버전은 nvidia-docker2를 사용해야 합니다.

2. 저장소 추가

Ubuntu 기준 GPG Key와 APT 저장소 리스트를 추가합니다.
shell
$ curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
  && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
    sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
    
    
$ sed -i -e '/experimental/ s/^#//g' /etc/apt/sources.list.d/nvidia-container-toolkit.list

3. 패키지 설치

저장소 갱신 후 패키지를 설치합니다.
shell
$ sudo apt update && sudo apt install -y nvidia-container-toolkit

4. Docker 재시작

패키지 설치 후 Docker Engine을 재시작해야 합니다.
shell
$ systemctl restart docker.service

5. 설치 확인

Docker 컨테이너에서 드라이버가 정상적으로 연결되는지 확인합니다.
shell
$ docker run -it --rm --gpus all ubuntu:22.04 nvidia-smi
nvidia-smi 출력이 정상적으로 나오면 연결이 성공한 것입니다.

Docker 리소스 제한 (Resource Limits)


Docker는 VM과 달리 커널을 공유하므로, 하나의 컨테이너가 시스템 자원(CPU, Memory)을 과도하게 점유하면 호스트 전체가 불안정해질 수 있습니다.
따라서 운영 환경(Production)에서는 반드시 리소스 제한을 설정해야 합니다.
왜 제한해야 할까요?
  • 특정 컨테이너의 메모리 누수(Memory Leak)가 호스트 OOM(Out Of Memory)을 유발하는 것을 방지
  • CPU 점유율 독점을 막아 다른 서비스의 성능 보장
아래는 자주 사용되는 주요 옵션들입니다.

1. CPU 제한


가장 직관적인 방법은 --cpus 옵션을 사용하는 것입니다.
shell
# 1.5개의 CPU 코어만 사용 가능 (예: 코어 1개 100% + 코어 1개 50%)
docker run --cpus="1.5" ubuntu

# 특정 코어(0번, 1번)만 사용하도록 지정
docker run --cpuset-cpus="0,1" ubuntu
  • --cpus: 사용할 CPU 코어의 개수를 제한합니다. (가장 권장되는 방식)
  • --cpuset-cpus: 특정 CPU 코어 번호를 지정합니다. (고성능 컴퓨팅 등 격리가 중요할 때 사용)
옵션
설명
--cpus=<value>
컨테이너가 사용할 수 있는 사용 가능한 CPU 리소스의 양을 지정합니다. 예를 들어 호스트 시스템에 CPU가 2개 있고 를 설정한 경우 --cpus="1.5"컨테이너는 CPU의 최대 1.5개만 보장됩니다. 이는 --cpu-period="100000"및 설정과 동일합니다 --cpu-quota="150000".
--cpu-period=<value>
와 함께 사용되는 CPU CFS 스케줄러 기간을 지정합니다 --cpu-quota. 기본값은 100000마이크로초(100밀리초)입니다. 대부분의 사용자는 이를 기본값에서 변경하지 않습니다. 대부분의 사용 사례에서는 --cpus더 편리한 대안입니다.
--cpu-quota=<value>
컨테이너에 CPU CFS 할당량을 부과합니다. --cpu-period제한되기 전에 컨테이너가 제한되는 마이크로초 수입니다 . 따라서 효과적인 천장 역할을 합니다. 대부분의 사용 사례에서는 --cpus더 편리한 대안입니다.
--cpuset-cpus
컨테이너가 사용할 수 있는 특정 CPU 또는 코어를 제한합니다. CPU가 두 개 이상인 경우 컨테이너가 사용할 수 있는 쉼표로 구분된 목록 또는 하이픈으로 구분된 CPU 범위입니다. 첫 번째 CPU 번호는 0입니다. 유효한 값은 0-3(첫 번째, 두 번째, 세 번째 및 네 번째 CPU를 사용하는 경우) 또는 1,3(두 번째 및 네 번째 CPU를 사용하는 경우)일 수 있습니다.
--cpu-shares
컨테이너의 무게를 늘리거나 줄이려면 이 플래그를 기본값인 1024보다 크거나 작은 값으로 설정하고 호스트 시스템의 CPU 주기 중 더 많거나 적은 비율에 대한 액세스 권한을 부여하세요. 이는 CPU 주기가 제한된 경우에만 적용됩니다. 충분한 CPU 주기를 사용할 수 있으면 모든 컨테이너는 필요한 만큼의 CPU를 사용합니다. 그런 식으로 이것은 소프트 제한입니다. --cpu-sharesSwarm 모드에서 컨테이너가 예약되는 것을 방지하지 않습니다. 사용 가능한 CPU 주기에 대해 컨테이너 CPU 리소스의 우선순위를 지정합니다. 특정 CPU 액세스를 보장하거나 예약하지 않습니다.

2. Memory 제한


메모리 제한은 OOM Killer에 의해 프로세스가 종료되는 것을 방지하기 위해 중요합니다.
shell
# 메모리 512MB 제한 (스왑은 기본값 사용)
docker run --memory="512m" ubuntu

# 메모리 512MB, 스왑 1GB (메모리+스왑 총합) 제한
# 즉, 실제 RAM 512MB + SWAP 512MB 사용 가능
docker run --memory="512m" --memory-swap="1g" ubuntu

# 스왑 끄기 (메모리와 스왑을 동일하게 설정)
docker run --memory="512m" --memory-swap="512m" ubuntu
주의: --memory-swap은 --memory 값과 Swap 영역을 합친 총량입니다.
예를 들어 --memory="300m" --memory-swap="1g"라면, RAM 300MB + Swap 700MB를 사용하게 됩니다.
옵션
설명
-m또는--memory=
컨테이너가 사용할 수 있는 최대 메모리 양입니다. 이 옵션을 설정하는 경우 허용되는 최소값은 6m6MB입니다. 즉, 값을 6MB 이상으로 설정해야 합니다.
--memory-swap*
이 컨테이너가 디스크로 스왑할 수 있는 메모리 양입니다. 자세히 --memory-swap보다 .
--memory-swappiness
기본적으로 호스트 커널은 컨테이너에서 사용되는 익명 페이지의 일부를 교체할 수 있습니다. --memory-swappiness0에서 100 사이의 값으로 설정하여 이 백분율을 조정할 수 있습니다. 자세히 --memory-swappiness보다 .
--memory-reservation
--memoryDocker가 호스트 시스템에서 경합이나 메모리 부족을 감지할 때 활성화되는 것 보다 작은 소프트 제한을 지정할 수 있습니다 . 를 사용하는 경우 우선순위를 적용하려면 --memory-reservation보다 낮게 설정해야 합니다 . --memory이는 소프트 제한이므로 컨테이너가 제한을 초과하지 않는다는 것을 보장하지 않습니다.
--kernel-memory
컨테이너가 사용할 수 있는 최대 커널 메모리 양입니다. 허용되는 최소값은 입니다 6m. 커널 메모리는 교체할 수 없기 때문에 커널 메모리가 부족한 컨테이너는 호스트 시스템 리소스를 차단할 수 있으며, 이는 호스트 시스템과 다른 컨테이너에 부작용을 일으킬 수 있습니다. 자세히 --kernel-memory보다 .
--oom-kill-disable
기본적으로 OOM(메모리 부족) 오류가 발생하면 커널은 컨테이너의 프로세스를 종료합니다. 이 동작을 변경하려면 --oom-kill-disable옵션을 사용하십시오. 옵션 을 설정한 컨테이너에서만 OOM 킬러를 비활성화하세요 -m/--memory. 플래그 -m가 설정되지 않으면 호스트의 메모리가 부족해질 수 있으며 커널은 메모리를 확보하기 위해 호스트 시스템의 프로세스를 종료해야 할 수도 있습니다.

3. GPU 할당


--gpus 플래그를 사용하여 컨테이너에 할당할 GPU를 지정할 수 있습니다.
shell
# 모든 GPU 할당
docker run --gpus all nvidia/cuda:11.8.0-base-ubuntu22.04 nvidia-smi

# 특정 GPU 2개 할당
docker run --gpus 2 nvidia/cuda:11.8.0-base-ubuntu22.04 nvidia-smi

# 특정 GPU 지정 (Device ID 또는 UUID)
docker run --gpus '"device=0,2"' ...
docker run --gpus device=GPU-3a23c669-... ...
UUID 확인 방법:
shell
nvidia-smi -L
container 내부에 드라이버 연결이 되었는지 테스트하는 방법
shell
docker run -it --rm --gpus all ubuntu nvidia-smi
shell
+-------------------------------------------------------------------------------+
| NVIDIA-SMI 384.130            	Driver Version: 384.130                      	|
|-------------------------------+----------------------+------------------------+
| GPU  Name 	     Persistence-M| Bus-Id      	Disp.A | Volatile Uncorr. ECC   |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M.   |
|===============================+======================+========================|
|   0  GRID K520       	Off  |   00000000:00:03.0 Off  |                    N/A |
| N/A   36C	P0    39W / 125W |      	0MiB /  4036MiB  |          0%  	Default |
+-------------------------------+----------------------+------------------------+
+-------------------------------------------------------------------------------+
| Processes:                                                         GPU Memory |
|  GPU   	PID   Type   Process name                                  Usage  	  |
|===============================================================================|
|  No running processes found                                                   |
+-------------------------------------------------------------------------------+

4. Disk (Volume) 제한


Docker의 기본 Storage Driver는 오버레이 파일시스템을 사용하므로, 컨테이너 생성 시 디스크 용량을 직접 제한하는 옵션은 --storage-opt를 사용합니다.
하지만, 일반적으로는 Volume 생성 시 크기를 제한하는 방법이 더 자주 쓰입니다.
shell
# 1GB 크기의 볼륨 생성
docker volume create --driver local \
    --opt type=tmpfs \
    --opt device=tmpfs \
    --opt o=size=1024m \
    my_vol
참고: XFS 파일시스템을 사용하는 경우, --storage-opt size=10G 와 같은 옵션으로 컨테이너 루트 파일시스템 크기를 제한할 수 있습니다.

마무리


이 글에서는 Docker와 가상화의 차이점부터, NVIDIA Container Toolkit을 통한 GPU 활용, 그리고 운영 환경에서 필수적인 리소스 제한 방법까지 살펴보았습니다.
핵심 요약
  • Docker: 커널을 공유하는 경량 컨테이너 기술로, VM보다 빠르고 효율적입니다.
  • NVIDIA Container Toolkit: Docker에서 GPU를 사용하기 위한 필수 도구입니다.
  • 리소스 제한: --cpus, --memory, --gpus 등의 옵션으로 컨테이너별 자원을 제한할 수 있습니다.
GPU를 활용한 딥러닝/ML 환경을 구축할 때, 적절한 리소스 제한은 시스템 안정성과 여러 서비스 간의 공정한 자원 분배를 보장합니다. 이 글이 Docker GPU 환경 구축에 도움이 되었으면 좋겠습니다. 🐳