콘텐츠로 이동

NaizVL 오프라인 키트 — 제작 가이드

외부망이 연결된 개발 서버에서 폐쇄망 운영 서버용 오프라인 설치 키트를 만드는 절차.

1. 대상 환경 (키트가 지원하는 운영 환경)

항목 값
OS Ubuntu 22.04 LTS (USB 설치)
GPU NVIDIA RTX A6000 × 2
CUDA 12.8 (키트 동봉 local apt repo)
Python 3.10 시스템 (venv 미사용)
모델 Qwen3-VL-8B-Instruct (~16GB)
키트 크기 ~25GB tar.gz
설치 후 디스크 ~40GB

2. 빌드 호스트 사전 준비

  1. 개발 서버에 qwen3-5-vl venv (서버 코드 + 의존성 완성)
  2. wget (대부분 기본 설치) — CUDA local repo .deb 자동 다운로드
  3. apt-rdepends — transitive 의존성 펼치기. 미설치 시 스크립트가 자동 설치 시도.
  4. (선택) GPG 서명용 키 — export GPG_KEY=<keyid>

NVIDIA 드라이버는 별도 다운로드 불필요. CUDA 12.8 local repo 가 cuda-drivers 메타를 포함.

3. 제작 명령

cd /home/naiz/NaizVL

# (선택) GPG 서명
export GPG_KEY=<your-gpg-keyid>

# 기본: SRC_ROOT/dist 에 산출물 생성
./deploy/make-offline-kit.sh v20260519-qwen3vl8b

# USB 에 직접 생성 (권장 파일시스템: exfat 또는 ext4)
./deploy/make-offline-kit.sh v20260519-qwen3vl8b \
    --output /media/naiz/KINGSTON64

# OUT_DIR 환경변수로도 지정 가능
OUT_DIR=/media/naiz/KINGSTON64 \
    ./deploy/make-offline-kit.sh v20260519-qwen3vl8b

# (선택) CUDA 버전 덮어쓰기 — 기본 12.8.0 / driver 570.86.10
# export CUDA_REPO_DEB="cuda-repo-ubuntu2204-12-8-local_12.8.0-570.86.10-1_amd64.deb"
# export CUDA_REPO_URL="https://developer.download.nvidia.com/.../$CUDA_REPO_DEB"

# (선택) 캐시된 CUDA .deb 강제 재다운로드
./deploy/make-offline-kit.sh v20260519-qwen3vl8b --no-cache-debs

USB 직접 생성 주의사항

  • 파일시스템: FAT32/vfat 은 단일 파일 4GB 제한으로 불가. exfat 또는 ext4:
    sudo mkfs.exfat /dev/sdX1   # exfat
    sudo mkfs.ext4  /dev/sdX1   # ext4 (Linux 전용)
    
  • 여유 공간: 30GB+ 권장 (tar ~25GB + 해시·서명).
  • 권한: 마운트 경로 쓰기 권한 확인 — sudo chown -R $USER /media/naiz/KINGSTON64
  • 완료 후 안전 분리: sync && sudo umount /media/naiz/KINGSTON64

첫 실행 시 $SRC_ROOT/dist/nvidia-debs/cuda-repo-*.deb (3~4GB) 다운로드. 이후 SSD 캐시 재사용으로 빠름.

4. 산출물

dist/
├── naizvl-offline-kit-v20260519-qwen3vl8b.tar.gz         (~25GB)
└── naizvl-offline-kit-v20260519-qwen3vl8b.tar.gz.sha256

tar 내부에 MANIFEST.sha256 + (GPG 서명 시) MANIFEST.sha256.asc 포함.

키트 내부 구조

naizvl-offline-kit-<version>/
├── 00-system/
│   ├── nvidia-driver-*.deb
│   ├── cuda-repo-ubuntu2204-12-8-local_*.deb
│   └── dependencies/*.deb           # libgl1, ffmpeg, gcc-12, python3.10-dev 등
├── 01-python/
│   ├── requirements.lock
│   └── wheels/*.whl                 # scipy / scikit-learn / flash-attn 포함
├── 02-app/                          # 최소 운영 키트 (~45 KB)
│   ├── naizvl_server_replica.py
│   ├── config.example.yaml
│   └── systemd/naizvl.service
├── 03-models/
│   └── Qwen3-VL-8B-Instruct/        # ~16GB
├── install.sh
├── VERSION
├── BUILD_DATE
├── MANIFEST.sha256
└── MANIFEST.sha256.asc              # GPG_KEY 지정 시

5. APT 패키지 정책

make-offline-kit.sh 의 APT_PKGS 가 명시 포함하는 핵심 패키지:

패키지 이유
python3 python3.10 python3.10-venv python3-pip 시스템 python. python3 메타는 가상 의존성 제공자.
libpython3.10 target ISO 의 stdlib upgrade 시 broken 방지.
python3.10-dev libpython3.10-dev vLLM 의 Triton JIT 가 런타임에 cuda_utils.c 를 gcc 로 빌드 → #include <Python.h> 필요. (2026-05-19 추가)
libgl1 libglib2.0-0 libsm6 libxext6 libxrender1 ffmpeg OpenCV·이미지 디코딩 런타임.
dkms dpkg-dev make build-essential nvidia 드라이버 dkms 빌드 체인.
gcc-12 g++-12 cpp-12 22.04.5 ISO default kernel (6.8.0-40-generic) 이 gcc-12 로 빌드 → kernel header Makefile 이 -ftrivial-auto-var-init=zero 사용 → gcc-11 로는 dkms compile fail. (2026-05-19 추가)
linux-headers-$(uname -r) dkms 모듈 컴파일 시 필요.

apt-rdepends 가 transitive (Depends + PreDepends) 펼침. Recommends/Suggests 는 제외 → GUI 패키지·테마 불필요한 살이 안 붙음.

6. Python wheel 정책

REQUIRED_EXTRAS — freeze 미포함 패키지 자동 보강

# make-offline-kit.sh
REQUIRED_EXTRAS=(scipy scikit-learn)
  • scipy / scikit-learn: transformers.generation.candidate_generator 가 sklearn.metrics 사용. 미포함 시 PYTHONNOUSERSITE=1 운영 환경에서 ModuleNotFoundError.
  • 각 항목은 빌드 환경에 없으면 pip install 후 requirements.lock 에 자동 추가.

LOCAL_WHEEL_CACHE — 수동 빌드 wheel 통합

PyPI 에 사전 빌드 wheel 이 없는 패키지 (flash-attn 등) 는 별도 빌드 후 wheels_cache/ 에 두면 자동으로 키트 wheels/ 에 포함.

# 기본 위치 (환경변수로 override 가능)
export LOCAL_WHEEL_CACHE=/home/naiz/qwen3-5-vl/wheels_cache
ls $LOCAL_WHEEL_CACHE/
# → flash_attn-2.8.3-cp310-cp310-linux_x86_64.whl

make-offline-kit.sh 가 이 폴더의 모든 .whl 을: 1. 키트의 01-python/wheels/ 로 복사 2. requirements.lock 에 <pkg>==<ver> 자동 추가

flash-attn 빌드 절차 (개발 서버, 인터넷·GPU 필요)

source /home/naiz/qwen3-5-vl/.qwen3-5-vl/bin/activate

# 캐시 충돌 방지 — 이전 flash_attn 모두 정리
pip uninstall -y flash-attn flash_attn 2>/dev/null
find ~/.cache/pip -name "flash_attn*" -delete
pip cache purge
rm -f /home/naiz/qwen3-5-vl/wheels_cache/flash_attn-*.whl

# 빌드 의존성
pip install -U packaging wheel ninja setuptools

# 환경 변수 — 멀티 GPU arch 지원
export TORCH_CUDA_ARCH_LIST="8.0;8.6;8.9;9.0+PTX"   # A100·Ampere·Ada·Hopper + 미래
export MAX_JOBS=8                                    # CPU 코어 수에 맞춤
export FLASH_ATTENTION_FORCE_BUILD=TRUE
export TMPDIR=/tmp/flash_build_tmp
mkdir -p "$TMPDIR" /home/naiz/qwen3-5-vl/wheels_cache/

# 빌드 — 캐시·사전 wheel 모두 차단, 강제 컴파일 (30~50분)
pip wheel flash-attn==2.8.3 \
    --no-cache-dir --no-binary flash-attn \
    --no-build-isolation --no-deps --verbose \
    -w /home/naiz/qwen3-5-vl/wheels_cache/ 2>&1 | tee /tmp/flash_build.log

# 검증
WHEEL=$(ls /home/naiz/qwen3-5-vl/wheels_cache/flash_attn-*.whl | head -1)
pip install --force-reinstall --no-deps "$WHEEL"
python3 -c "
import flash_attn
from flash_attn.ops.triton.rotary import apply_rotary
from flash_attn import flash_attn_func
import torch
q = torch.randn(1,4,8,64, device='cuda', dtype=torch.bfloat16)
print('flash_attn', flash_attn.__version__, 'on', torch.cuda.get_device_name(0), 'OK')
"

TORCH_CUDA_ARCH_LIST 권장 조합

운영 범위 TORCH_CUDA_ARCH_LIST 예상 wheel 크기
현재 환경만 (A6000) "8.6" ~30 MB
Ampere 이후 일반 "8.0;8.6;8.9;9.0" ~80 MB
권장 (광범위 + 미래 호환) "8.0;8.6;8.9;9.0+PTX" ~112 MB
모든 데이터센터 GPU "7.5;8.0;8.6;8.9;9.0+PTX" ~130 MB

→ +PTX 는 마지막 SM 에 PTX (asm) 도 포함, 미래 GPU 도 JIT 컴파일로 동작.

빌드 정보 보존

cat > /home/naiz/qwen3-5-vl/wheels_cache/flash_attn-2.8.3.BUILD_INFO.md << EOF
# flash-attn 2.8.3 빌드 정보
- 빌드일: $(date -Iseconds)
- torch: $(python3 -c "import torch; print(torch.__version__)")
- CUDA toolkit (nvcc): $(nvcc --version | grep release)
- cxx11_abi: $(python3 -c "import torch; print(torch._C._GLIBCXX_USE_CXX11_ABI)")
- TORCH_CUDA_ARCH_LIST: $TORCH_CUDA_ARCH_LIST
- 호환 GPU: A100, A6000, RTX 30xx, RTX 40xx, L4/L40, H100, +미래(PTX)
EOF

torch 또는 CUDA 업그레이드 후엔 ABI 일치 보장을 위해 반드시 재빌드 필요.

7. 02-app 정책 (운영 코드 최소화)

운영에 필요한 파일만 명시 복사 — naizvl_server_replica.py · config.example.yaml · systemd/naizvl.service 3개. 평가·튜닝·데이터셋·로그·문서 제외 → 이전 5.3GB → ~45KB 축소.

향후 서버 코드가 여러 파일로 분리되면 make-offline-kit.sh 의 명시 복사 목록에 추가해야 합니다.

8. 업데이트 전략

변경 범위 방법
코드만 (naizvl_server_replica.py) 파일만 USB → rsync → systemctl restart
모델 교체 03-models/ tar → 디렉토리 교체 → config.yaml.checkpoint 수정 → 재기동
의존성 변경 (wheel/apt) 키트 전체 재제작 권장

9. 버전 관리 규칙

파일명: naizvl-offline-kit-<YYYYMMDD>-<model>[-<hotfix>].tar.gz

예: - v20260422-qwen3vl8b — 초기 배포 - v20260519-qwen3vl8b — gcc-12 / python3.10-dev fix 포함 - v20260501-qwen3vl8b-hotfix1 — 같은 모델 + 코드 핫픽스 - v20260615-qwen3_5-9b — 모델 교체 시

키트 내부 VERSION / BUILD_DATE 로 추적.

10. venv 정책

환경 Python 배포 방식
개발 서버 (키트 제작) qwen3-5-vl venv make-offline-kit.sh 가 venv 의 pip freeze 결과로 requirements.lock 및 wheel 수집
대상 서버 (설치) 시스템 Python 3.10 venv 생성하지 않음. sudo pip3 install --no-index … 로 system-wide

근거 - 폐쇄망 전용 서버는 Python 용도가 이 애플리케이션 단독 - venv 미사용 → systemd unit 경로 단순 (/usr/bin/python3.10), 관리 포인트 감소 - Ubuntu 22.04 는 PEP 668 미적용 → pip install 에 별도 플래그 불필요

11. 관련 문서

  • INSTALL.md — 운영 서버 설치 가이드 (USB Ubuntu 설치부터)
  • README.md — 변경 이력 + 인덱스
  • ../research.md §20 (NaizVL 저장소 참고) — 서버 전체 구조 스냅샷
  • ../eval/README.md (NaizVL 저장소 참고) — 평가 도구