Nebius Serverless AI — vLLM 배포

Nebius Serverless AI — vLLM 배포

Nebius Serverless AI는 GPU 컨테이너를 영속형 HTTP 엔드포인트나 유한 작업(finite job)으로 실행해 줍니다. 이 가이드에서는 Nebius CLI를 이용해 vLLM의 OpenAI 호환 서버를 단일 GPU Endpoint로 배포하는 방법을 다룹니다.

Endpoint는 직접 중지하거나 삭제하기 전까지 계속 실행됩니다. 이 레시피는 일반 GPU 인스턴스를 사용하며, 오토스케일링이나 자동 축소(scale-to-zero)는 구성하지 않습니다.

출처: 문서

본문

사전 준비 (Prerequisites)

  • Serverless Endpoint를 생성·삭제할 권한이 있고, GPU·VM·디스크·네트워킹 쿼터가 충분한 Nebius 프로젝트.
  • 해당 프로젝트에 대해 설치·인증이 완료된 Nebius CLI.
  • eu-north1의 서브넷으로, Docker Hub와 Hugging Face에 아웃바운드 접근이 가능해야 합니다. 예제는 gpu-l40s-a 플랫폼과 1gpu-8vcpu-32gb 프리셋을 사용하며, 시작 전에 프로젝트에서 가용성을 확인하세요.
  • 로컬 머신에 curl, jq, openssl이 설치돼 있어야 합니다.

예제 모델인 Qwen/Qwen3-0.6B는 Hugging Face 토큰이 필요 없습니다. 다른 모델은 라이선스에 동의해야 하고 Nebius의 시크릿 환경 변수를 통해 토큰을 전달해야 할 수 있습니다.

Endpoint 생성 (Create the Endpoint)

아래 명령어는 Nebius CLI 0.12.265에서 테스트했습니다. 프로젝트 ID와 서브넷 ID를 명시적으로 설정하고, 가이드 전체에서 같은 CLI 프로필을 사용하세요.

export PROJECT_ID="<project-id>"
export SUBNET_ID="<subnet-id>"
export ENDPOINT_NAME="vllm-qwen-$(openssl rand -hex 6)"
export AUTH_TOKEN="$(openssl rand -hex 32)"
export MODEL_ID="Qwen/Qwen3-0.6B"
export MODEL_REVISION="c1899de289a04d12100db370d81485cdf75e47ca"
# vllm/vllm-openai:v0.19.1, Linux/amd64 image digest.
export VLLM_IMAGE="vllm/vllm-openai@sha256:89c1d0629d377daa3f7f369cbea6167a7b48ea89aaacd12555e2b0b2f7f740d3"

nebius ai endpoint create \
    --parent-id "$PROJECT_ID" \
    --subnet-id "$SUBNET_ID" \
    --name "$ENDPOINT_NAME" \
    --image "$VLLM_IMAGE" \
    --container-command vllm \
    --args "serve $MODEL_ID --revision $MODEL_REVISION --tokenizer-revision $MODEL_REVISION --host 0.0.0.0 --port 8000 --tensor-parallel-size 1 --max-model-len 4096 --gpu-memory-utilization 0.8" \
    --platform gpu-l40s-a \
    --preset 1gpu-8vcpu-32gb \
    --container-port 8000/http \
    --auth token --token "$AUTH_TOKEN" \
    --disk-size 250Gi --shm-size 16Gi \
    --public=false --preemptible=false \
    --retries 1

이미지와 모델 리비전은 재현성을 위해 고정(pin)했습니다. 이미지를 바꿀 때는 선택한 Nebius 플랫폼의 CUDA/드라이버 요구사항을 확인하세요. 모델은 시작 시 컨테이너 디스크로 다운로드되며, 이 예제는 영속 모델 스토리지를 구성하지 않습니다.

Endpoint 토큰은 Nebius CLI 자격증명과는 별개입니다. 비밀로 유지하세요. Nebius 토큰 인증은 HTTP 포트가 정확히 하나여야 합니다. 이 예제는 관리형 HTTPS URL에서의 인증에 의존하며, 두 번째 vLLM API 키는 설정하지 않습니다. 서브넷 내부에서의 접근은 신뢰할 수 있는 클라이언트로 제한해야 합니다.

관리형 HTTPS URL을 사용하는 데 공용 VM IP는 필요하지 않습니다. 다만 이미지·모델 다운로드를 위해 서브넷의 아웃바운드 연결은 여전히 필요합니다.

생성한 Endpoint의 ID를 저장합니다:

export ENDPOINT_ID="$(nebius ai endpoint get-by-name \
    --parent-id "$PROJECT_ID" --name "$ENDPOINT_NAME" \
    --format jsonpath='{.metadata.id}')"

생성이 타임아웃되거나 터미널이 끊겨도, 다시 생성하기 전에 같은 프로젝트·이름으로 Endpoint를 찾아보세요. 로컬 타임아웃이 프로비저닝이 취소됐다는 뜻은 아닙니다.

준비 상태 확인 (Check readiness)

상태와 최근 로그를 확인합니다:

nebius ai endpoint get "$ENDPOINT_ID"
nebius ai endpoint logs "$ENDPOINT_ID" --tail 100 --timestamps

RUNNING이 될 때까지 기다린 뒤 관리형 HTTPS URL을 선택합니다. URL은 Endpoint가 아직 STARTING일 때도 나타날 수 있는데, 이때는 인그레스가 HTTP 404를 반환할 수 있습니다. jq 표현식은 HTTPS URL이 정확히 하나여야 하며 그 스킴을 보존합니다:

ENDPOINT_URL="$(nebius ai endpoint get "$ENDPOINT_ID" --format json \
    | jq -er '[.status.public_endpoints[]? | select(startswith("https://"))]
        | if length == 1 then .[0] else error("Expected one HTTPS URL") end')"
export ENDPOINT_URL="${ENDPOINT_URL%/}"

curl --fail-with-body --silent --show-error --max-time 10 \
    "$ENDPOINT_URL/health" -H "Authorization: Bearer ***"
curl --fail-with-body --silent --show-error --max-time 10 \
    "$ENDPOINT_URL/v1/models" -H "Authorization: Bearer ***" | jq

RUNNING 상태만으로 모델 로딩이 끝났다는 뜻은 아닙니다. 채팅 요청을 보내기 전에 /health가 성공하고 /v1/modelsQwen/Qwen3-0.6B를 나열할 때까지 기다리세요. 기다리는 동안에는 다른 Endpoint를 만들지 말고 로그를 확인하세요. 정한 시간이나 지출 한도 안에 시작이 완료되지 않으면 Endpoint를 삭제하고 오류를 조사하세요.

채팅 요청 보내기 (Send a chat request)

curl --fail-with-body --silent --show-error --max-time 120 \
    "$ENDPOINT_URL/v1/chat/completions" \
    -H "Authorization: Bearer ***" \
    -H 'Content-Type: application/json' \
    -d '{
        "model": "Qwen/Qwen3-0.6B",
        "messages": [{"role": "user", "content": "Say hello in one short sentence."}],
        "max_tokens": 128,
        "temperature": 0,
        "chat_template_kwargs": {"enable_thinking": false}
    }' | jq

어시스턴트 메시지를 담은 채팅 완성이 반환됩니다. Qwen 특유의 템플릿 옵션은 이 짧은 예제에서 생각(thinking)을 끄는 용도이며, 다른 모델에서 보편적으로 쓸 수 있는 옵션은 아닙니다.

스트리밍을 쓰려면 JSON에 "stream": true를 추가하고 jq로 파이프하지 않은 채 curl -N을 사용하세요. 성공적인 스트림은 완성 청크에 이어 data: [DONE]을 포함합니다. OpenAI 호환 클라이언트를 쓰는 경우 베이스 URL로 ${ENDPOINT_URL}/v1을, API 키로 Endpoint 토큰을 사용하세요.

같은 추론 URL이 토큰 없이 온 요청을 거부하는지 확인합니다:

curl --silent --show-error --max-time 10 --output /dev/null \
    --write-out '%{http_code}\n' "$ENDPOINT_URL/v1/models"

HTTP 401 또는 403이 반환되면 정상입니다. 인증되지 않은 추론을 받아들이는 Endpoint를 공유하는 일은 없어야 합니다.

Endpoint 중지 및 삭제 (Stop or delete the Endpoint)

서빙을 중지하되 Endpoint 구성을 보존하려면:

nebius ai endpoint stop "$ENDPOINT_ID"
nebius ai endpoint get "$ENDPOINT_ID"

동기식 stop 명령이 완료될 때까지 기다리고, 다시 시작하기 전에 STOPPED를 확인하세요. 다시 시작하려면 nebius ai endpoint start "$ENDPOINT_ID"를 실행하고 현재 URL을 가져온 뒤 준비 상태 확인을 반복합니다. 다시 시작할 때는 새 용량과 새 이미지·모델 다운로드가 필요할 수 있으니, 컨테이너 디스크를 영속 스토리지로 의존하지 마세요.

작업이 끝나면 Endpoint를 삭제하고 같은 ID를 조회할 때 NotFound가 반환되는지 확인합니다:

nebius ai endpoint delete "$ENDPOINT_ID"
nebius ai endpoint get "$ENDPOINT_ID"
unset AUTH_TOKEN

Nebius는 Endpoint와 함께 관리형 VM 및 컨테이너 디스크를 삭제합니다. 별도로 마운트한 스토리지는 자체 생명주기와 과금을 갖습니다. 터미널을 닫거나 요청을 중단해도 Endpoint는 중지되지 않습니다. 삭제가 실패하면 ID를 보관하고 정리를 재시도하세요. 일반적인 연결·인증 오류는 삭제가 완료됐다는 증거가 아닙니다.

문제 해결 (Troubleshooting)

증상 확인 사항
PROVISIONING 또는 NotEnoughResources 쿼터, 리전, 플랫폼, 프리셋을 확인하세요. 용량 가용성은 쿼터와 다를 수 있습니다.
RUNNING 인데 HTTP 502/503 모델 다운로드·엔진 시작 로그, 서브넷 이그레스, 호스트 바인딩, 포트 8000을 확인하세요.
HTTP 401/403 Nebius 컨트롤 플레인 토큰이 아니라 Endpoint 토큰을 사용하세요.
CUDA 또는 메모리 부족 오류 이미지/드라이버 호환성, 모델의 메모리 요구량, 최대 컨텍스트 길이를 확인하세요.
Model not found 요청한 모델 ID와 고정 리비전을 확인하세요.
중단된 스트림 인그레스와 서버 로그를 검사하세요. 부분 응답을 새 세대로 자동 재생하지 않아야 합니다.

자세한 내용은 Nebius vLLM cookbook 예제Endpoint 관리 문서를 참고하세요.

더 알아보기 (Learn more)