도커에서 vllm 사용 설정 가이드
도커에서 vllm 사용 설정 가이드
# 도커에서 gpu를 사용하기 위한 기본설정
호스트 쪽
✅ NVIDIA 드라이버
✅ Docker
✅ NVIDIA Container Toolkit (nvidia-container-toolkit)
이미지/컨테이너 쪽
✅ CUDA / cuDNN 라이브러리 포함된 베이스 이미지 (또는 vLLM/Qwen 공식 이미지)
1. 호스트(서버)에 필요한 것
(1) NVIDIA 드라이버 (반드시 호스트에만 설치)
nvidia-smi 잘 나오면 OK
컨테이너 안에는 드라이버 설치하면 안 됨
→ 드라이버는 “호스트 전용”, 컨테이너는 라이브러리(CUDA, cuDNN)만 있으면 됨.
(2) Docker + NVIDIA Container Toolkit
GPU를 Docker에 연결해주는 게 NVIDIA Container Toolkit 이라서 필요.
NVIDIA Container Toolkit (nvidia-container-toolkit) 툴킷은 도커 내부에 gpu를 사용할수 있게 해주는 브릿지 역할
# 패키지 저장소 추가 (OS별로 다름, 예시는 Ubuntu)
# sudo distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
# curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit.gpg
# curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
# sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit.gpg] https://#g' | \
# sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
# Docker에 NVIDIA 런타임 연동
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
이렇게 해두면:
CLI: docker run --gpus all nvidia/cuda:12.2.2-base nvidia-smi
compose: gpus: "all"
이 둘 다 GPU에 접근 가능해져.
2. 컨테이너(이미지) 안에 필요한 것
여긴 두 가지 개념만 기억하면 돼:
CUDA / cuDNN 런타임 라이브러리
예: nvidia/cuda:12.2.2-cudnn-runtime-ubuntu22.04 같은 베이스 이미지 쓰거나
Qwen에서 제공하는 qwen3-vl-vllm:cuda12.2, qwenllm/qwenvl:qwen3vl-cu128 같은 이미 GPU용으로 세팅된 이미지 쓰면 됨.
코드에서 GPU 사용
PyTorch, vLLM, TensorRT 등에서 알아서 cuda 디바이스를 잡아감
vLLM은 --tensor-parallel-size, --gpu-memory-utilization 같은 옵션으로 얼마나/어떻게 쓸지 조정
/* 설치 확인 방법 */
which nvidia-ctk 명령어 사용해서 아래와 같이 검색 되면 설치 된것임
cbw@userver91-41:/data/cbw$ which nvidia-ctk
/usr/bin/nvidia-ctk
/* 버전 확인 */
nvidia-ctk --version
cbw@userver91-41:/data/cbw$ nvidia-ctk --version
NVIDIA Container Toolkit CLI version 1.17.8
commit: f202b80a9b9d0db00d9b1d73c0128c8962c55f4d
또는 자세한 정보확인
dpkg -l | grep nvidia-container-toolkit
(qwen3) cbw@userver91-41:/data/cbw$ dpkg -l | grep nvidia-container-toolkit
ii nvidia-container-toolkit 1.17.8-1 amd64 NVIDIA Container toolkit
ii nvidia-container-toolkit-base 1.17.8-1 amd64 NVIDIA Container Toolkit Base
실제 Docker/Podman에서 GPU 연결되는지 테스트
툴킷이 “설치만” 된 게 아니라 컨테이너 런타임과 연결까지 잘 되어 있는지 보려면, 가능하면 인터넷 되는 쪽에서:
docker run --rm --gpus all nvidia/cuda:12.2.0-runtime-ubuntu22.04 nvidia-smi
# 또는 podman:
podman run --rm \
--hooks-dir=/usr/share/containers/oci/hooks.d \
nvidia/cuda:12.2.0-runtime-ubuntu22.04 \
nvidia-smi
# 모델/캐시용 디렉터리 준비 (호스트)
sudo mkdir -p /data/qwen3vl/models
sudo mkdir -p /data/qwen3vl/triton_cache
sudo mkdir -p /data/qwen3vl/hf_cache
sudo chown -R $USER:$USER /data/qwen3vl
모델 경로(호스트):
/data/qwen3vl/model/Qwen3-VL-32B-Instruct
Triton 커널 캐시(한 번 컴파일해놓고 재사용):
/data/qwen3vl/triton_cache
HF 토크나이저/기타 캐시:
/data/qwen3vl/hf_cache
# 여기에 Hugging Face에서 받은 모델 디렉터리를 그대로 복사
# (온라인 머신에서 git lfs clone 한 뒤 rsync/scp 등으로 복사)
# ex) Qwen/Qwen3-VL-32B-Instruct repo 전체를 아래 경로로
/data/qwen3vl/model/Qwen3-VL-32B-Instruct
/* 모델 다운로드 */
hf download Qwen/Qwen3-VL-32B-Instruct \
--local-dir /data/qwen3vl/models/Qwen3-VL-32B-Instruct
====================================
커스텀 Dockerfile로 직접 이미지 빌드하고 싶다면
혹시 공식 이미지가 드라이버/런타임 버전 문제로 동작 안 할 때를 대비해서,
CUDA 12.2 기반으로 직접 빌드
이 Dockerfile은 온라인 환경에서 한 번 빌드해 두고,
docker save/docker load로 오프라인 서버에 옮겨쓰는 용도라고 보면 됩니다.
=================================
Dockerfile
==================================
FROM nvidia/cuda:12.2.2-cudnn8-runtime-ubuntu22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
python3 python3-pip python3-venv git \
&& rm -rf /var/lib/apt/lists/*
RUN python3 -m pip install --upgrade pip
# vLLM + Qwen-VL utils (Qwen3-VL 레시피에서 권장) :contentReference[oaicite:9]{index=9}
RUN pip install "vllm>=0.11.0" "qwen-vl-utils==0.0.14"
WORKDIR /workspace
ENV TRITON_CACHE_DIR=/opt/triton_cache \
HF_HOME=/opt/hf_home \
OMP_NUM_THREADS=1 \
VLLM_WORKER_MULTIPROC_METHOD=spawn
# OpenAI 호환 API 서버를 엔트리포인트로
ENTRYPOINT ["python3", "-m", "vllm.entrypoints.openai.api_server"]
CMD ["--help"]
==============================
build
==============================
docker build -t qwen3-vl-vllm:cuda12.2 .
=============================
docker-compose.qwen3-vl.yml ( 공식이미지 )
=============================
version: "3.9"
services:
qwen3-vl-32b:
image: vllm/vllm-openai:latest # 필요 시 v0.8.x 같은 특정 태그로 고정 가능
container_name: qwen3-vl-32b
restart: unless-stopped
# GPU 사용
gpus: "all" # docker compose v2 기준 (--gpus all 과 동일)
shm_size: "16g" # 멀티프로세스/텐서 공유메모리용 (필수급) :contentReference[oaicite:5]{index=5}
ipc: host # PyTorch 공유 메모리 최적화
environment:
- TZ=Asia/Seoul
# Triton CUDA 커널 캐시 (JIT 한 번만 하고 재사용)
- TRITON_CACHE_DIR=/opt/triton_cache
# HF 토크나이저/모델 캐시 (오프라인이지만 로컬 캐시용)
- HF_HOME=/opt/hf_home
# 전처리 스레드 과도 사용 방지 (Qwen3-VL 가이드 권장) :contentReference[oaicite:6]{index=6}
- OMP_NUM_THREADS=1
# 멀티 프로세스 안정성
- VLLM_WORKER_MULTIPROC_METHOD=spawn
volumes:
# 모델 로컬 공유 (읽기전용)
- /data/qwen3vl/model/Qwen3-VL-32B-Instruct:/models/Qwen3-VL-32B-Instruct:ro
# 캐시들
- /data/qwen3vl/triton_cache:/opt/triton_cache
- /data/qwen3vl/hf_cache:/opt/hf_home
ports:
- "8000:8000"
command:
# 실제 vLLM OpenAI 서버에 넘기는 인자들
- "--model"
- "/models/Qwen3-VL-32B-Instruct"
# 클라이언트 입장에서 보이는 모델 이름 (API 호출 시 model= 이 이름)
- "--served-model-name"
- "Qwen3-VL-32B-Instruct"
# A100 80GB에 맞게 BF16 + 여유 메모리
- "--dtype"
- "bfloat16"
- "--gpu-memory-utilization"
- "0.90"
# 컨텍스트 길이 (필요하면 점점 늘려보면 됨)
- "--max-model-len"
- "8192"
# 동시 요청 수 (트래픽 보고 조정)
- "--max-num-seqs"
- "32"
# 비디오 안 쓴다면 메모리 절약 (이미지만)
- "--limit-mm-per-prompt.video"
- "0"
# 스케줄링 최적화 (Qwen3-VL 레시피에서 권장) :contentReference[oaicite:7]{index=7}
- "--async-scheduling"
# Qwen 쪽 커스텀 코드 로딩 허용 (HF 로컬 레포에도 포함돼 있음)
- "--trust-remote-code"
# OpenAI 호환 API 서버 바인딩
- "--host"
- "0.0.0.0"
- "--port"
- "8000"
=============================
docker build -t qwen3-vl-vllm:cuda12.2 . ( 버전에 맞게 컴파일 이미지 )
=============================
=============================
docker-compose.qwen3-vl.yml ( 컴파일이미지 )
=============================
version: "3.9"
services:
qwen3-vl-32b:
image: qwen3-vl-vllm:cuda12.2 # vllm/vllm-openai:latest 공식이미지
container_name: qwen3-vl-32b
restart: unless-stopped
# GPU 사용
gpus: "all" # docker compose v2 기준 (--gpus all 과 동일)
shm_size: "16g" # 멀티프로세스/텐서 공유메모리용 (필수급) :contentReference[oaicite:5]{index=5}
ipc: host # PyTorch 공유 메모리 최적화
environment:
- TZ=Asia/Seoul
# Triton CUDA 커널 캐시 (JIT 한 번만 하고 재사용)
- TRITON_CACHE_DIR=/opt/triton_cache
# HF 토크나이저/모델 캐시 (오프라인이지만 로컬 캐시용)
- HF_HOME=/opt/hf_home
# 전처리 스레드 과도 사용 방지 (Qwen3-VL 가이드 권장) :contentReference[oaicite:6]{index=6}
- OMP_NUM_THREADS=1
# 멀티 프로세스 안정성
- VLLM_WORKER_MULTIPROC_METHOD=spawn
volumes:
# 모델 로컬 공유 (읽기전용)
- /data/qwen3vl/model/Qwen3-VL-32B-Instruct:/models/Qwen3-VL-32B-Instruct:ro
# 캐시들
- /data/qwen3vl/triton_cache:/opt/triton_cache
- /data/qwen3vl/hf_cache:/opt/hf_home
ports:
- "8001:8001"
command:
# 실제 vLLM OpenAI 서버에 넘기는 인자들
- "--model"
- "/models/Qwen3-VL-32B-Instruct"
# 클라이언트 입장에서 보이는 모델 이름 (API 호출 시 model= 이 이름)
- "--served-model-name"
- "Qwen3-VL-32B-Instruct"
# A100 80GB에 맞게 BF16 + 여유 메모리
- "--dtype"
- "bfloat16"
- "--gpu-memory-utilization"
- "0.90"
# 컨텍스트 길이 (필요하면 점점 늘려보면 됨)
- "--max-model-len"
- "8192"
# 동시 요청 수 (트래픽 보고 조정)
- "--max-num-seqs"
- "32"
# 비디오 안 쓴다면 메모리 절약 (이미지만)
- "--limit-mm-per-prompt.video"
- "0"
# 스케줄링 최적화 (Qwen3-VL 레시피에서 권장) :contentReference[oaicite:7]{index=7}
- "--async-scheduling"
# Qwen 쪽 커스텀 코드 로딩 허용 (HF 로컬 레포에도 포함돼 있음)
- "--trust-remote-code"
# OpenAI 호환 API 서버 바인딩
- "--host"
- "0.0.0.0"
- "--port"
- "8001"
==========================
시작/중지용 쉘 스크립트
start_qwen3_vl.sh
==========================
#!/usr/bin/env bash
set -e
COMPOSE_FILE="docker-compose.qwen3-vl.yml"
# 로그 디렉터리 만들고 로그도 같이 남기고 싶으면 아래 추가
# mkdir -p /var/log/qwen3-vl
docker compose -f "$COMPOSE_FILE" pull || true # 이미지는 온라인에서 미리 받아두고, 오프라인에선 무시
docker compose -f "$COMPOSE_FILE" up -d
echo "Qwen3-VL-32B vLLM 서버가 백그라운드에서 올라갔습니다. (포트 8000)"
=====================================================
stop_qwen3_vl.sh
===================================================
#!/usr/bin/env bash
set -e
COMPOSE_FILE="docker-compose.qwen3-vl.yml"
docker compose -f "$COMPOSE_FILE" down
echo "Qwen3-VL-32B vLLM 서버를 중지했습니다."
===================================================
실행권한 부여
chmod +x start_qwen3_vl.sh stop_qwen3_vl.sh
/* 로그 확인 */
docker compose -f docker-compose.qwen3-vl.yml logs -f
====================
기동후 테스트
====================
curl http://182.162.91.41:8001/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen3-VL-32B-Instruct",
"messages": [
{"role": "user", "content": [
{"type": "text", "text": "안녕, 자기소개 해줘"}
]}
],
"max_tokens": 256
}'
모델은 호스트 /data/qwen3vl/model/Qwen3-VL-32B-Instruct 에 두고, 컨테이너에 read-only 마운트.
공식 vLLM OpenAI 이미지를 써서 간단히 운영:
A100 80GB 1장 + BF16 + --gpu-memory-utilization 0.9
--limit-mm-per-prompt.video 0, --async-scheduling 등으로 메모리/성능 최적화.
TRITON_CACHE_DIR, HF_HOME 를 호스트에 마운트해서 재기동 시 JIT/캐시 비용 최소화.
필요 시 systemd까지 걸어서 부팅 시 자동 기동.
이대로 먼저 올려보고,
실제 트래픽/지연시간/VRAM 사용량 보면서 max-model-len, max-num-seqs, gpu-memory-utilization 만 조정해 나가면 될 거예요.
====================================================================================
내 pc 저사양에서 간단 테스트
====================================================================================
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 575.64.01 Driver Version: 576.88 CUDA Version: 12.9 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 5070 Ti On | 00000000:02:00.0 On | N/A |
| 0% 39C P8 19W / 300W | 986MiB / 16303MiB | 1% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| 0 N/A N/A 35 G /Xwayland N/A |
+-----------------------------------------------------------------------------------------+
================================================================================
저사양 테스트 용(Qwen3-VL-4B-Instruct)
# 기본 디렉터리
sudo mkdir -p /data/qwen3vl4b/model
sudo mkdir -p /data/qwen3vl4b/triton_cache
sudo mkdir -p /data/qwen3vl4b/hf_cache
sudo chown -R $USER:$USER /data/qwen3vl4b
즉, HF에서 클론/다운로드한 그대로의 구조를
/data/qwen3vl4b/model/Qwen3-VL-4B-Instruct 여기에 복사해 둔다고 보면 돼.
hf download Qwen/Qwen3-VL-4B-Instruct \
--local-dir /data/qwen3vl4b/model/Qwen3-VL-4B-Instruct
docker-compose.qwen3-vl-4b.yml
==================================
version: "3.9"
services:
qwen3-vl-4b:
image: qwenllm/qwenvl:qwen3vl-cu128
container_name: qwen3-vl-4b
restart: unless-stopped
gpus: "all"
shm_size: "8g"
ipc: host
environment:
- HF_HOME=/opt/hf_home
- TRITON_CACHE_DIR=/opt/triton_cache
- OMP_NUM_THREADS=1
- VLLM_WORKER_MULTIPROC_METHOD=spawn
volumes:
# 로컬에 미리 받아둔 모델을 컨테이너로 마운트
- /data/qwen3vl4b/model/Qwen3-VL-4B-Instruct:/models/Qwen3-VL-4B-Instruct:ro
# 캐시들 (Triton kernel, HF 토크나이저 등)
- /data/qwen3vl4b/hf_cache:/opt/hf_home
- /data/qwen3vl4b/triton_cache:/opt/triton_cache
ports:
- "8000:8000"
command: >
bash -lc "vllm serve /models/Qwen3-VL-4B-Instruct
--host 0.0.0.0
--port 8000
--dtype bfloat16
--max-model-len 1024
--max-num-seqs 1
--max-num-batched-tokens 1024
--gpu-memory-utilization 0.8
--enforce-eager
--served-model-name Qwen3-VL-4B-Instruct
--trust-remote-code
--async-scheduling
--limit-mm-per-prompt.video 0"
=============================
# 최초 기동
docker compose -f docker-compose.qwen3-vl-4b.yml up -d
# 로그 확인
docker compose -f docker-compose.qwen3-vl-4b.yml logs -f
==============================
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen3-VL-4B-Instruct",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "안녕, Qwen3-VL-4B 테스트 중이야. 자기소개 해줘." }
]
}
],
"max_tokens": 256
}'
================================
VRAM/성능 튜닝 포인트 (5070 Ti 16GB 기준)
만약 VRAM 부족(OOM) 에러가 뜨면:
--max-model-len 4096 → 3072 또는 2048로 줄이기
--max-num-seqs 4 → 2로 줄이기
--gpu-memory-utilization 0.9 → 0.8 ~ 0.85 정도로 낮추기
반대로 여유 있으면:
--max-model-len을 8192까지 올려보면서 적정선 찾기
=======================================
신gpu 서버 테스트
============================
sudo mkdir -p /data/cbw/qwen3vl/model
sudo mkdir -p /data/cbw/qwen3vl/triton_cache
sudo mkdir -p /data/cbw/qwen3vl/hf_cache
/* 모델 다운로드 */
hf download Qwen/Qwen3-VL-32B-Instruct \
--local-dir /data/cbw/qwen3vl/model/Qwen3-VL-32B-Instruct
/* 도커 컴포즈 생성 모든 gpu 사용설정 */
docker-compose.qwen3-vl.yml
==================================
version: "3.9"
services:
qwen3-vl-32b:
image: qwen3-vl-vllm:cuda12.2 # vllm/vllm-openai:latest 공식이미지
container_name: qwen3-vl-32b
restart: unless-stopped
# GPU 사용
gpus: "all" # docker compose v2 기준 (--gpus all 과 동일)
shm_size: "16g" # 멀티프로세스/텐서 공유메모리용 (필수급) :contentReference[oaicite:5]{index=5}
ipc: host # PyTorch 공유 메모리 최적화
environment:
- TZ=Asia/Seoul
# Triton CUDA 커널 캐시 (JIT 한 번만 하고 재사용)
- TRITON_CACHE_DIR=/opt/triton_cache
# HF 토크나이저/모델 캐시 (오프라인이지만 로컬 캐시용)
- HF_HOME=/opt/hf_home
# 전처리 스레드 과도 사용 방지 (Qwen3-VL 가이드 권장) :contentReference[oaicite:6]{index=6}
- OMP_NUM_THREADS=1
# 멀티 프로세스 안정성
- VLLM_WORKER_MULTIPROC_METHOD=spawn
volumes:
# 모델 로컬 공유 (읽기전용)
- /data/cbw/qwen3vl/model/Qwen3-VL-32B-Instruct:/models/Qwen3-VL-32B-Instruct:ro
# 캐시들
- /data/cbw/qwen3vl/triton_cache:/opt/triton_cache
- /data/cbw/qwen3vl/hf_cache:/opt/hf_home
ports:
- "8001:8001"
command:
# 실제 vLLM OpenAI 서버에 넘기는 인자들
- "--model"
- "/models/Qwen3-VL-32B-Instruct"
# 클라이언트 입장에서 보이는 모델 이름 (API 호출 시 model= 이 이름)
- "--served-model-name"
- "Qwen3-VL-32B-Instruct"
# A100 80GB에 맞게 BF16 + 여유 메모리
- "--dtype"
- "bfloat16"
- "--gpu-memory-utilization"
- "0.90"
# 모든 gpu 사용
- "--tensor-parallel-size"
- "2"
# 컨텍스트 길이 (필요하면 점점 늘려보면 됨)
- "--max-model-len"
- "8192"
# 동시 요청 수 (트래픽 보고 조정)
- "--max-num-seqs"
- "32"
# 비디오 안 쓴다면 메모리 절약 (이미지만)
- "--limit-mm-per-prompt.video"
- "0"
# 스케줄링 최적화 (Qwen3-VL 레시피에서 권장) :contentReference[oaicite:7]{index=7}
- "--async-scheduling"
# Qwen 쪽 커스텀 코드 로딩 허용 (HF 로컬 레포에도 포함돼 있음)
- "--trust-remote-code"
# OpenAI 호환 API 서버 바인딩
- "--host"
- "0.0.0.0"
- "--port"
- "8001"
===================
start_qwen3_vl.sh
===================
#!/usr/bin/env bash
set -e
COMPOSE_FILE="docker-compose.qwen3-vl.yml"
docker compose -f "$COMPOSE_FILE" up -d
echo "Qwen3-VL-32B vLLM 서버가 백그라운드에서 올라갔습니다. (포트 8001)"
echo "docker compose -f docker-compose.qwen3-vl.yml logs -f"
=========================
stop_qwen3_vl.sh
==========================
#!/usr/bin/env bash
set -e
COMPOSE_FILE="docker-compose.qwen3-vl.yml"
docker compose -f "$COMPOSE_FILE" down
echo "Qwen3-VL-32B vLLM 서버를 중지했습니다."
댓글