proxmox의 강력한 기능을 체감한 나는 이 쌈뽕한 운영체제를 연구실 컴퓨터에도 설치할 결심을 했다.
proxmox 위에서 돌아가는 연구용, NAS용, 프로젝트용, 갖고놀기용으로 생성된 가상 환경들이 있고, 이들 중 연구용 및 프로젝트용 환경에서는 머신 러닝 가속을 위해 GPU를 사용할 수 있어야 했다. 따라서 초기 설정이 조금 복잡했다.
앞으로 자주 설치 및 초기 설정을 진행할 것 같아 이 참에 블로그에 설치 과정을 정리해보려 한다.
설치 과정은 크게 어려운 것이 없다. hostname 설정에서 조금 헤멜 수 있으나, 필자의 경우 도메인을 구매해둔 것이 있어 별 탈 없이 잘 넘어갔다.
proxmox를 처음 설치하고 apt update를 날리면 업데이트가 진행되지 않는다. 이는 구독이 필요한 유료 저장소가 기본적으로 apt list에 등록되어 있고, 이 저장소에서 401 unauthorized 응답을 반환하기 때문이다.
따라서 proxmox를 설치하고 가장 처음 해야 할 일은 연간 10만원을 내고 구독을 하거나 이 구독 저장소를 등록 해제하는 것이다.
proxmox도 데비안 기반이고 apt 패키지 관리자도 완전히 똑같은 물건이므로 여느 데비안 계열 배포판에서 하듯이 저장소 관리를 진행하면 된다.
구독 저장소의 URL이 담긴 파일의 위치는 다음과 같고(/etc/apt/sources.list.d/pve-enterprise.list, /etc/apt/sources.list.d/ceph.list), 해당 파일에 있는 모든 행을 주석처리하면 된다.

그 다음 무료 저장소인 no-subscription 저장소를 등록해주자.
필자의 경우 /etc/apt/sources.list.d/no-subscription.list를 만들고 다음 행을 작성하였다.
deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription
그 다음 apt update를 날리면 잘 진행될 것이다.
기왕 좋은 컴퓨터에 proxmox를 설치하는 김에, 윈도우 VM도 설치하고 GPU passthrough도 설정하여 맛있는 환경을 구축해보려 했다. 그런데 VM 환경에서 GPU passthrough를 설정하는 것이 조금 매우 많이 복잡했다.
먼저 VM에서 가상화된 GPU가 아닌 실제 GPU를 그대로 사용하려면 호스트 OS에 설치되어 있는 GPU에 대한 IOMMU(가상 머신에서 실제 디바이스에 접근할 수 있도록 디바이스의 주소를 매핑해주는 레이어라고 한다) 설정이 필요한데, 이 기능을 활성화하기 위해 부트로더와 커널 모듈 설정이 필요하다.
...하지만 VM에 GPU passthrough를 설정하려 하니 VM이 꼬여 제대로 동작하지 않았다. 며칠 씨름하다가 포기 윈도우는 다음에 설치해보는 걸로 하고 VM 대신 컨테이너에 GPU passthrough를 설정해보기로 마음을 먹었다.
다음 내용은 LXC 컨테이너에 GPU passthrough를 설정하는 과정이며, 같은 커널을 공유하므로 VM 대비 작업량이 확실히 적다.
드라이버 빌드 시 현재 동작하고 있는 커널의 헤더를 사용하기 때문에, 커널을 미리 최신 버전으로 업데이트해주자.
# apt update
# apt upgrade
그 다음 현재 동작 중인 버전의 커널 헤더를 설치해야 한다. 먼저 현재 커널 버전을 확인해보자.
# uname -r

그 다음, apt-cache 명령으로 앞서 확인한 버전의 헤더 패키지 이름을 검색해보자.
$ apt-cache search pve-headers-x.x.xx-x

또는 다음 명령어로 바로 찾을 수 있다.

찾은 커널 헤더 패키지를 설치해주자.
# apt install pve-headers-x.x.xx-x
마지막으로, gcc를 비롯한 빌드 도구도 미리 설치해두자.
# apt install build-essential
무료 사용자 중 혹시 위 과정에서 pve-headers-... 패키지를 찾을 수 없는 경우, apt에 무료 저장소 no-subscription를 등록하지 않았을 가능성이 높다.
proxmox에는 기본적으로 nvidia의 독점 드라이버가 설치되어 있지 않은 것 같았다. 따라서 먼저 자동 설치되어 있는 오픈소스 드라이버인 nouveau를 비활성화시킨 다음, 수동으로 nvidia 드라이버를 설치해주어야 한다.
modprobe를 통해 nouveau 드라이버를 로드하지 않도록 할 수 있다. /etc/modprobe.d 경로에 파일을 하나 만들고(예: blacklist.conf), 해당 파일에 다음 내용을 기록해두자.
blacklist nouveau

그 다음, initramfs 업데이트를 진행하고 재부팅하면 모든 준비는 끝난다.
# update-initramfs -u
# reboot
nvidia 드라이버 다운로드 페이지에서 설치된 그래픽카드의 리눅스 드라이버를 검색하고, .run으로 끝나는 다운로드 링크를 복사해두자. RTX 3060을 사용하는 필자의 경우 링크가 다음과 같았다: https://us.download.nvidia.com/XFree86/Linux-x86_64/550.107.02/NVIDIA-Linux-x86_64-550.107.02.run
해당 링크를 wget으로 proxmox 환경에 다운로드해주자.
$ wget https://~~~~.run
그 다음, 드라이버 설치를 진행하자.
# chmod +x ~~~~.run
# /path/to/~~~~.run
필자는 proxmox에 GUI를 설치할 생각이 없으므로 nvidia-xconfig 유틸리티는 설치하지 않았다.
nvidia-smi로 드라이버가 잘 설치되었는지 확인하자.

apt 명령을 사용할 수도 있다. nvidia-driver-xxx 패키지를 설치하면 되는데, 본인이 장착한 그래픽카드에서 지원하는 드라이버 버전을 설치해야 한다.proxmox 부팅 시 드라이버를 잘 실행할 수 있도록 커널 모듈 설정을 추가한다. /etc/modules-load.d 경로에 파일을 하나 만들고(예: modules.conf), 해당 파일에 다음 내용을 기록해두자.
nvidia
nvidia-modeset
nvidia_uvm
그 다음 initramfs 업데이트를 진행하자.
# update-initramfs -u
다음으로 GPU passthrough가 previlaged 컨테이너에서도 잘 작동할 수 있게 드라이버의 권한을 설정해주자. /etc/udev/rules.d 경로에 파일을 하나 만들고(예: 70-nvidia.rules), 해당 파일에 다음 내용을 기록해두자.
KERNEL=="nvidia", RUN+="/bin/bash -c '/usr/bin/nvidia-smi -L && /bin/chmod 666 /dev/nvidia*'"
KERNEL=="nvidia_modeset", RUN+="/bin/bash -c '/usr/bin/nvidia-modprobe -c0 -m && /bin/chmod 666 /dev/nvidia-modeset*'"
KERNEL=="nvidia_uvm", RUN+="/bin/bash -c '/usr/bin/nvidia-modprobe -c0 -u && /bin/chmod 666 /dev/nvidia-uvm*'"

재부팅한 다음 nvidia-smi로 드라이버 정상 작동 여부를 확인하면 호스트 쪽에서의 작업은 모두 끝났다.
컨테이너에서 해야 할 것은 두 가지다. 먼저 device passthrough를 설정한 다음, 컨테이너 OS에서 GPU 드라이버를 설치하면 된다.
proxmox web ui로 접속한 다음 컨테이너를 하나 생성한다. 생성한 컨테이너의 Resources 페이지로 가서 Add-device passthrough를 선택하여 GPU를 추가한다.

위 방법으로 다음 디바이스를 추가한다.
/dev/nvidia0
/dev/nvidiactl
/dev/nvidia-modeset
/dev/nvidia-uvm
/dev/nvidia-uvm-tools
/dev/nvram
컨테이너를 재부팅한 다음, 컨테이너 내부 쉘에 접속하여 2.2. nvidia 독점 드라이버 설치를 참고하여 드라이버를 다운받는다.
드라이버 설치 프로그램 실행 시 명령 인수로 반드시 --no-kernel-module 옵션을 주어야 한다.
apt로 설치하는 경우, nvidia-headless-xxx 패키지를 설치하면 된다.설치를 마친 다음 내부 쉘에서 nvidia-smi 명령을 입력하여 정상 동작을 확인하면 작업이 모두 끝난다.
필자는 llama3 모델을 돌릴 작정으로 GPU passthrough를 설정한 컨테이너를 하나 파고, pytorch를 설치한 다음 모델을 돌려봤다.
결론은... 잘 돌아갔다! 또한 GPU passthrough가 설정된 컨테이너 여러 개를 동시 실행해도 잘 되는 것 같았다.
이제 환경 격리 뿐만 아니라 하드웨어 자원도 서로 공유하는 형태의 가상 환경을 구동할 수 있게 되었다. 향후 연구실 딥러닝 서버 구축 시 GPU passthrough를 활용할 수 있을 듯 하다.