Air-Gapped GPU Driver Installation
Building a Repository From the Transfer and Installing
한국어 원문으로 표시합니다.
한 줄 요약
반입한 .deb 묶음을 저장소로 만들면 dpkg 로 하나씩 순서를 맞춰 설치하는 대신 apt 에게 맡길 수 있다. 그것이 반입 방식의 표준이다.
왜 이게 필요했나
반입한 파일을 dpkg -i *.deb 로 한 번에 설치하면 순서 때문에 실패한다. 순서를 맞춰 하나씩 하면 되지만, 패키지가 30개면 그것도 일이다. 그리고 무엇보다 다음에 다시 할 때 그 순서를 기억해야 한다.
저장소로 만들면 이 문제가 사라진다. apt 가 그래프를 풀고 순서를 정한다. 그리고 그 저장소는 계속 재사용된다.
어떻게 동작하나
절차
# 1. 반입분을 한곳에 모은다
mkdir -p /srv/airgap/pool && cp /media/usb/*.deb /srv/airgap/pool/
# 2. 색인을 만든다
cd /srv/airgap && dpkg-scanpackages pool /dev/null > pool/Packages
gzip -kf pool/Packages
# 3. 저장소로 등록한다
echo 'deb [trusted=yes] file:/srv/airgap/pool ./' > /etc/apt/sources.list.d/airgap.list
apt-get update
# 4. 먼저 시뮬레이션
apt-get install -s nvidia-driver-550
# 5. 실제 설치
apt-get install -y nvidia-driver-550
4번을 건너뛰지 마라. -s(simulate)는 실제로 아무것도 바꾸지 않고 계획만 출력한다. 여기서 Inst 로 시작하는 줄이 설치될 패키지이고, 의존성이 안 풀리면 The following packages have unmet dependencies 가 나온다. 이 출력이 곧 반입이 성공했는지에 대한 답이다.
안 풀렸을 때 읽는 법
The following packages have unmet dependencies:
libnvidia-container-tools : Depends: libnvidia-container1 (>= 1.16.2-1) but it is not installable
읽는 법: 왼쪽이 요구하는 쪽, 오른쪽이 없는 것. not installable 은 저장소에 그 이름이 아예 없다는 뜻이고, but 1.0 is to be installed 는 있긴 한데 버전이 안 맞는다는 뜻이다. 이 구분이 2차 반입 목록을 만드는 근거가 된다.
저장소 정보를 명확히
deb [trusted=yes] file:/srv/airgap/pool ./
[trusted=yes] 는 서명 없는 저장소를 신뢰한다는 선언이다. 실습이나 임시 저장소가 아니라면 반드시 서명해야 한다. 운영 환경에서는 자체 GPG 키로 Release 파일에 서명하고 [signed-by=/usr/share/keyrings/...] 로 키를 지정한다.
그리고 저장소 이름이나 경로에 스냅샷 날짜를 넣어 두면 6개월 뒤 조사할 때 큰 도움이 된다.
설치 후 확인
dpkg -l 'nvidia*' 'libnvidia*' | grep '^ii' | wc -l
dpkg -l | grep -c '^i[^i]' # ii 가 아닌 것 (문제 있는 상태)
apt-get -f install # 미해결이 있으면 정리
ii 가 아닌 상태(iU, iF 등)가 하나라도 있으면 설치가 완전히 끝나지 않은 것이다.
드라이버·CUDA·컨테이너 툴킷의 관계
세 가지가 각각 다른 것이고, 버전 규칙도 다릅니다. 이 구분이 안 되면 "CUDA 를 깔았는데 안 된다" 로 하루가 갑니다.
[ 호스트 ]
NVIDIA 드라이버 (커널 모듈 + libcuda.so) ← 여기만 커널에 붙는다
nvidia-container-toolkit ← 컨테이너에 장치를 넣어 준다
↓
[ 컨테이너 ]
CUDA 런타임 (libcudart) ← 이미지 안에 들어 있다
cuDNN, PyTorch …
컨테이너 안에 드라이버를 넣지 않습니다. 커널 모듈은 호스트 것 하나뿐이고,
툴킷이 /dev/nvidia* 와 호스트의 libcuda.so 를 컨테이너에 넣어 줍니다.
버전 규칙은 드라이버가 CUDA 보다 같거나 높아야 한다는 것입니다(전방 호환). 드라이버 550 이면 CUDA 12.4 까지 됩니다. 그래서 이미지의 CUDA 버전을 올릴 때 호스트 드라이버부터 확인합니다.
nvidia-smi # 오른쪽 위에 드라이버와 CUDA 상한이 나온다
cat /proc/driver/nvidia/version
커널을 올리면 모듈이 사라진다
가장 자주 겪는 사고입니다. apt upgrade 로 커널이 올라가면 그 커널용 NVIDIA
모듈이 없어 재부팅 뒤 GPU 가 사라집니다.
# DKMS 가 새 커널에 맞춰 다시 빌드해 준다 — 이것이 설치돼 있어야 한다
dkms status
nvidia/550.90.07, 6.8.0-45-generic, x86_64: installed
# 커널을 고정하는 방법(폐쇄망에서는 이쪽이 안전하다)
apt-mark hold linux-image-generic linux-headers-generic
폐쇄망에서는 DKMS 빌드에 필요한 헤더와 컴파일러가 반입돼 있어야 합니다. 그래서 커널 고정 이 더 안전한 선택인 경우가 많습니다.
Secure Boot 가 막을 때
Secure Boot 가 켜져 있으면 서명되지 않은 커널 모듈이 로드되지 않습니다. 증상은
"설치는 성공했는데 nvidia-smi 가 장치를 못 찾는다" 입니다.
mokutil --sb-state # SecureBoot enabled 이면 이 문제일 수 있다
dmesg | grep -i 'nvidia\|taint\|module verification'
세 가지 중 하나를 고릅니다: MOK 키를 등록해 모듈에 서명하거나, 배포판이 서명한 드라이버 패키지를 쓰거나, Secure Boot 를 끕니다. 폐쇄망에서 MOK 등록은 콘솔에서 사람이 재부팅 중에 입력해야 하므로, 원격만 가능한 환경이면 미리 계획 해야 합니다.
현장에서 만나는 모습
2차 반입이 필연이라고 생각하고 절차를 짠다. 아무리 잘 계산해도 첫 반입에서 빠지는 것이 나온다. 그래서 성숙한 조직은 "1차 반입 후 시뮬레이션 → 부족분 목록 자동 생성 → 2차 반입" 을 절차로 못박아 둔다. 부족분 목록을 사람이 손으로 만들면 또 빠진다.
설치 로그를 남긴다. apt-get install 의 출력과 /var/log/apt/history.log 를 반입 기록과 함께 보관한다. 나중에 롤백할 때 어떤 트랜잭션을 되돌려야 하는지 알 수 있다.
다음 실습에서 할 것
1차 반입분으로 저장소를 세워 드라이버 설치를 성공시키고, 툴킷 설치는 실패하는 것을 확인한 뒤, 부족분(2차 반입분)을 추가해 다시 성공시킨다. 실제 폐쇄망 절차 그대로다.