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. 빌드 호스트 사전 준비
- 개발 서버에
qwen3-5-vlvenv (서버 코드 + 의존성 완성) wget(대부분 기본 설치) — CUDA local repo.deb자동 다운로드apt-rdepends— transitive 의존성 펼치기. 미설치 시 스크립트가 자동 설치 시도.- (선택) 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 저장소 참고) — 평가 도구