본문으로 건너뛰기
페이지 목차
이 페이지에서 검색

로컬 LLM

이 페이지에 묻기

로컬 LLM · 현재 차시와 목차 본문에서만 찾아 답합니다. 답을 지어내지 않고 해당하는 대목을 그대로 보여 주며, 여기에 없으면 없다고 알려 드립니다.

생성형 AI가 아니라 이 페이지 본문을 찾아 그대로 보여 주는 방식입니다. 외부로 나가는 요청이 없습니다.

LOCAL · LLM

로컬 LLM

생성 수정

로컬 모델 실행과 GPU·메모리 이해부터 서빙·RAG·도구 호출·업무형 앱 구현까지 차례로 살펴봅니다.

42개 문서 · 3일차 · 20 / 42

19차시 · vLLM 서버 구축

지도 위치 : 3일차 · ③추론 엔진을 ④API로 여는 자리 · 모델 서버 띄우기 | 이전: 18차시 vLLM 환경 구축 | 다음: 20차시 OpenAI 호환 API 활용 키워드 : vLLM Server 실행, 모델 · GPU 설정, Context Length, 서버 구성

이 차시를 다 읽으면

  1. vllm serve 한 줄로 서버를 띄우고, 주요 옵션 여섯 개가 각각 무엇을 정하는지 말할 수 있다.
  2. 기동 로그에서 가중치 메모리 · KV 캐시 · "Maximum concurrency" 줄을 찾아 뜻을 말할 수 있다.
  3. 요청이 하나도 없는데 nvidia-smi가 꽉 차 보이는 것이 왜 정상인지 설명할 수 있다.
  4. 컨텍스트 길이를 크게 잡으면 기동 에러 가 나는 이유를 VRAM 예산식으로 계산할 수 있다.
  5. /health · /v1/models로 서버를 확인하고, --api-key와 0.0.0.0의 위험을 말할 수 있다.
  6. 서버를 systemd 또는 Docker 로 상시 실행하는 두 길을 구별할 수 있다.

0. 이 차시의 판별 축

#축왼쪽 (0)오른쪽 (1)이 축으로 갈리는 것큰 축 (README 5장)
1메모리를 언제 잡는가필요할 때 (Ollama 방식)기동 시 미리 확보 (vLLM 방식)nvidia-smi 수치의 뜻① 디스크 ↔ 메모리
2어디까지 열어 두는가127.0.0.1 (이 기계만)0.0.0.0 (모든 네트워크 인터페이스)누가 접근할 수 있는가④ 로컬 ↔ 원격
3누가 프로세스를 지키는가내 터미널 (닫으면 죽음)systemd · Docker (재부팅해도 다시 뜸)상시 실행① 디스크 ↔ 메모리 (꺼지면 사라지는 실행 중 프로세스를 누가 다시 올리는가)

앞에서 이어집니다 — 17차시 구조도의 모델 서버 칸 을 실제로 세우는 차시입니다. 그리고 9차시의 예산식 필요한 VRAM ≈ 가중치 + KV 캐시 + 여유분이 처음으로 기동 로그 숫자 가 되어 눈앞에 나옵니다.


1. vllm serve — 한 줄로 서버 띄우기

1.1 명령

source ~/vllm-lab/.venv-vllm/bin/activate
export VLLM_API_KEY='여기에_긴_비밀값'

vllm serve Qwen/Qwen3-8B \
  --host 127.0.0.1 --port 8000 \
  --served-model-name munuibot \
  --max-model-len 8192 \
  --gpu-memory-utilization 0.90 \
  --dtype auto \
  --api-key "$VLLM_API_KEY"

🔍 읽는 포인트

  • 첫 인자 Qwen/Qwen3-8B — 18차시와 같은 Hugging Face 모델 이름 . 캐시에 있으면 다시 받지 않습니다.
  • --served-model-name munuibot — 클라이언트가 요청에 적을 모델 이름 . 앱 코드에는 munuibot만 남고, 뒤의 모델을 바꿔도 앱은 그대로입니다(20차시).
  • --max-model-len · --gpu-memory-utilization — 이 두 줄이 VRAM 예산 을 정합니다(2~4절).

1.2 주요 옵션

옵션정하는 것예시값VRAM 예산식의 어느 항주의
--max-model-len요청 하나의 최대 토큰 (입력 + 출력)8192KV 캐시 (요청 하나당 상한)모델 최대치 이하. 너무 크면 기동 에러 (4절)
--gpu-memory-utilizationvLLM이 쓸 GPU 메모리 비율0.90전체 예산기동 시 미리 확보 (3절)
--api-keyAuthorization: Bearer 키환경변수로—키는 하나 뿐 (5.2)
--served-model-nameAPI에서 부를 모델 이름munuibot—클라이언트의 model 값과 정확히 일치해야 함
--host / --port바인딩 주소 · 네트워크 포트127.0.0.1 / 8000—0.0.0.0 주의 (5.2)
--dtype가중치 · 계산 정밀도auto가중치auto는 모델 설정(config.json)을 따름. Qwen3는 보통 BF16

동시 처리 · 양자화 · KV 캐시 정밀도 · 프리픽스 캐싱 같은 손잡이(--max-num-seqs, --quantization, --kv-cache-dtype, --enable-prefix-caching)는 23차시 에서 다룹니다.

⚠️ 옵션 이름과 기본값은 버전에 따라 바뀝니다. 내 버전의 진실은 vllm serve --help입니다.

1.3 ⚠️ 번역어 — 여기의 "포트"는 네트워크 포트

--port 8000의 포트는 네트워크 포트 입니다. [통신 창구 번호]인데, [ 한 컴퓨터(IP 주소 하나) 안에서 요청이 어느 프로그램에게 가는지 가르는 번호 ]라는 점에서 컴퓨터 자체를 가리키는 IP 주소와 구별됩니다. IP 주소가 건물이라면 포트는 "건물 안의 몇 번 창구"입니다. 5차시에서 본 Ollama의 11434가 같은 것입니다. 20차시의 아키텍처 포트 (계약)와는 같은 철자, 다른 개념입니다(README 6장).

⚠️ 8000번은 관례상 개발용 백엔드 가 많이 쓰는 번호이고, FastAPI(uvicorn)의 기본값도 8000입니다. 같은 기계에서 문의봇 API 서버와 vLLM을 함께 띄우면 포트가 겹칩니다. 하나를 옮기세요(예: FastAPI 8080).


2. ⭐ 기동 로그 읽기

2.1 찾아야 할 줄 세 개

vllm serve를 실행하면 로그가 길게 흐릅니다. 다 읽을 필요 없습니다. 이 세 줄만 찾습니다. (아래는 형태만 보인 것입니다. 문구는 버전마다 조금씩 다르고, 숫자 자리는 일부러 비웠습니다.)

... Model loading took XX.X GiB ...                         ← ① 가중치가 차지한 메모리
... GPU KV cache size: NN,NNN tokens                         ← ② KV 캐시 풀의 크기(토큰 수)
... Maximum concurrency for 8192 tokens per request: X.XXx   ← ③ 최대 길이 기준 동시 수용량
... Starting vLLM API server ... on http://127.0.0.1:8000
줄9차시 예산식의 어느 항이걸로 아는 것
① 가중치가중치9차시에 계산한 값(8B × 2바이트 ≈ 16GB)과 맞는가
② KV 캐시 풀KV 캐시예산에서 가중치와 오버헤드를 빼고 남은 자리 전부
③ Maximum concurrencyKV 캐시 ÷ (컨텍스트 × 동시 수)이 설정으로 최대 길이 요청을 동시에 몇 개 품는가

2.2 ⭐ "Maximum concurrency for N tokens per request: X" 의 뜻

X = KV 캐시 풀의 토큰 수 ÷ --max-model-len

모든 요청이 최대 길이(8192 토큰)를 꽉 채운다고 가정할 때, 동시에 몇 개까지 KV 캐시에 들어가는가 입니다.

⚠️ 두 가지로 잘못 읽힙니다.

오해바로잡기
"X가 최대 동시 접속자 수다"❌ 실제 요청은 대개 최대 길이보다 짧습니다. vLLM은 쓴 만큼만 KV 블록을 잡으므로(21차시) 실제로는 더 많이 들어갑니다. 넘치는 요청은 거절이 아니라 대기열 로 갑니다
"X가 작아도 일단 뜨면 괜찮다"⚠️ X가 작다는 것은 긴 요청이 몰릴 때 여유가 적다 는 신호입니다. 1보다 작으면 아예 뜨지 않습니다 (4절)

2.3 계산으로 미리 짐작하기 — 이론값, 실측 아님

문의봇 조건(RTX 4090 24GB, Qwen3-8B BF16, --max-model-len 8192)으로 9차시 예산식을 돌려 봅니다. 층 수 · KV 헤드 수 · head_dim은 모델의 config.json에서 확인 합니다.

GPU 24GB × 0.90                           ≈ 21.6 GB   ← vLLM이 확보하는 예산
− 가중치 (약 8.2B × 2바이트)              ≈ 16.4 GB
− 활성값 · CUDA 등 오버헤드                ≈ 1~2 GB
= KV 캐시 풀                              ≈ 3.2 ~ 4.2 GB
÷ KV 캐시/토큰 (2 × 36층 × 8헤드 × 128 × 2바이트) ≈ 144 KB
= 풀에 들어가는 토큰                       ≈ 2.2만 ~ 2.8만 토큰
÷ 8192                                    ≈ 동시 2.7 ~ 3.5개 (최대 길이 기준)

⭐ 상담원 10명 을 생각하면 여유가 넉넉하지 않습니다. 실제 문의는 짧아서 더 들어가겠지만, 이 계산이 23차시의 출발점입니다. 그때 손잡이는 넷입니다. 컨텍스트를 줄이거나, 가중치를 가볍게 하거나(양자화 모델), KV 캐시를 가볍게 하거나(FP8), 예산 비율을 올리거나. 로그의 실제 숫자와 이 계산을 나란히 놓는 것 이 이 차시 실습의 핵심입니다.


3. ⭐ nvidia-smi가 꽉 차 보이는 것은 정상입니다

--gpu-memory-utilization 0.90은 "GPU 메모리의 90%까지 쓸 수 있다"가 아니라 "기동할 때 90%를 미리 확보한다" 입니다. 가중치를 올리고, 남은 자리를 전부 KV 캐시 풀로 예약 해 둡니다. 그래서 요청이 0개여도 nvidia-smi의 memory.used가 거의 꽉 차 보입니다.

Ollama (5차시)vLLM
언제 잡나모델을 처음 부를 때 (가중치 + num_ctx 만큼의 KV)기동할 때 한 번에
언제 놓나마지막 요청 후 기본 5분 뒤 언로드서버가 떠 있는 동안 놓지 않음
nvidia-smi 모양요청에 따라 오르내림평평하게 높음

앞에서 배운 축 ① 디스크 ↔ 메모리 에서, vLLM은 "필요할 때 빌리기"가 아니라 "자리를 먼저 통째로 잡아 두기" 를 고른 것입니다. 요청이 올 때마다 메모리를 구하러 다니지 않으니 빠르고 예측 가능합니다. 대신 남과 나눠 쓰기 어렵습니다.

⚠️ 여기서 세 가지가 따라옵니다.

  1. nvidia-smi로는 "실제로 얼마나 쓰고 있는가"를 알 수 없습니다. KV 캐시 실사용률은 /metrics에서 봅니다(22차시).
  2. 같은 GPU에 다른 프로세스를 두기 어렵습니다 (18차시 5.1). 꼭 함께 써야 하면 비율을 낮추고, 그만큼 KV 풀이 줄어드는 것을 받아들입니다.
  3. 24차시에서 Ollama와 메모리를 비교할 때 nvidia-smi 숫자를 그대로 비교하면 틀립니다.

💡 비유는 기억 보조로만 — 손님이 올 때마다 의자를 가져오는 식당(Ollama)과, 개점 전에 홀 전체를 세팅해 두는 식당(vLLM).


4. 컨텍스트 길이가 너무 크면 — 기동 에러

--max-model-len을 생략하면 vLLM은 모델이 지원하는 최대치 (config.json의 값, Qwen3-8B는 수만 토큰 — 직접 확인)를 씁니다. 2.3의 계산에서 KV 풀이 2.2만 ~ 2.8만 토큰이었습니다. 최대치가 그보다 크면 최대 길이 요청 하나조차 KV 캐시에 못 담습니다. vLLM은 이 상태로 뜨지 않고 기동 단계에서 멈춥니다.

에러 문구는 버전마다 다르지만 취지는 이렇습니다. "최대 시퀀스 길이가 KV 캐시에 저장할 수 있는 토큰 수보다 크다. gpu_memory_utilization을 올리거나 max_model_len을 줄여라."

손잡이효과대가자세히
--max-model-len 줄이기요청 하나당 상한↓ → X↑긴 메일은 거절되거나 앞에서 잘라야 함23차시
--gpu-memory-utilization 올리기 (예: 0.95)예산↑여유분이 줄어 다른 메모리 사용과 부딪힐 수 있음23차시
양자화 모델 (AWQ · FP8 등)가중치↓ → KV 풀↑품질 확인 필요 (15차시)23차시
--kv-cache-dtype fp8토큰당 KV↓품질 확인 필요23차시

⚠️ 2차시 3절의 구분을 다시 봅니다. 모델이 지원하는 최대치 ≠ 내가 설정해서 쓰는 값. 문의봇은 "모델이 몇까지 되나"가 아니라 "우리 메일이 얼마나 긴가" 로 정합니다(23차시 3절).


5. 서버 확인과 보안

5.1 살아 있는지, 무엇이 떠 있는지

curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/health
curl -s http://127.0.0.1:8000/v1/models -H "Authorization: Bearer $VLLM_API_KEY"
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/v1/models   # 키 없이
curl -s http://127.0.0.1:8000/v1/chat/completions \
  -H "Content-Type: application/json" -H "Authorization: Bearer $VLLM_API_KEY" \
  -d '{"model":"munuibot","messages":[{"role":"user","content":"주문한 지 일주일째 안 와요. 한 줄로 요약해줘."}],"max_tokens":100}'

🔍 읽는 포인트

  • /health → 200 이면 살아 있음. 17차시 2.4에서 말한 허브의 헬스 체크 가 이것입니다.
  • /v1/models → 응답의 "id"가 munuibot 이어야 합니다.
  • 키 없이 부르면 401 이 나와야 정상입니다. HTTP 상태 코드 401 = 인증 실패 (Unauthorized, "누구인지 확인할 수 없다", 17차시 2.3).
  • 마지막 요청의 응답 구조(choices, usage, finish_reason)는 20차시에서 해부합니다.

5.2 ⚠️ --api-key와 0.0.0.0

--host는 서버의 바인딩 주소 , 즉 "어느 주소로 들어오는 요청을 받을 것인가"를 정합니다. 앞에서 배운 대로(5차시 4.2) 두 값이 갈립니다.

바인딩 주소뜻접근할 수 있는 곳
127.0.0.1루프백 — 이 컴퓨터가 자기 자신을 가리키는 주소같은 기계 안의 프로그램만
0.0.0.0이 기계가 가진 모든 네트워크 인터페이스 (유선 · 무선 · 사설망 주소 전부)같은 네트워크의 다른 PC도 서버IP:8000으로

여기에 인증 (누구인지 확인, 17차시 2.3)이 있느냐가 겹치면 아래 표가 됩니다.

구성접근할 수 있는 사람판정
127.0.0.1 + 키같은 기계의 프로세스 (API 서버가 같은 기계일 때)⭐ 기본값으로
0.0.0.0 + 키같은 네트워크의 키를 아는 누구나API 서버가 다른 기계일 때만, 사설망 · 방화벽과 함께
0.0.0.0 + 키 없음같은 네트워크의 누구나❌ GPU와 모델을 통째로 공개
  • 0.0.0.0으로 여는 순간 같은 네트워크 전체가 손님 이 됩니다. 테스트하려고 잠깐 연 한 줄이 그대로 보안 구멍이 되는 흔한 경로입니다. 6.2의 Docker 포트 연결도 같은 함정을 품고 있습니다.
  • 5차시의 OLLAMA_HOST=0.0.0.0은 인증 없이 열렸습니다. vLLM은 키를 걸 수 있지만, 키 하나 = 서비스 간 인증 일 뿐 상담원별 권한은 없습니다(17차시 2.3).
  • 키를 명령줄에 직접 쓰면 셸 기록과 프로세스 목록에 남습니다. 환경변수나 파일 로 넘깁니다. vLLM은 VLLM_API_KEY 환경변수도 읽습니다(버전 확인).

6. 상시 실행 — systemd 또는 Docker

터미널에서 띄운 서버는 터미널을 닫으면 같이 죽습니다. 서버가 죽거나 기계가 재부팅되면 누군가 다시 띄워야 합니다. 운영에서는 그 "누군가"를 사람이 아니라 OS나 컨테이너 엔진에게 맡깁니다.

6.1 systemd 서비스로

systemd — [리눅스의 서비스 관리자]인데, [ 프로그램을 서비스로 등록해 두면 부팅 때 자동으로 띄우고, 죽으면 다시 띄우고, 로그를 모아 준다 ]는 점에서 내 터미널에서 직접 띄운 프로세스와 구별된다. 서비스 하나의 실행 방법을 적은 설정 파일이 유닛 파일 (.service)이고, systemctl이 그 서비스를 켜고 끄는 명령, journalctl이 로그를 보는 명령입니다.

Ollama는 설치할 때 이미 systemd 서비스로 등록되었고, 그 설정을 systemctl edit로 바꿨습니다(5차시 1.2 · 4.1). vLLM은 유닛 파일을 직접 만듭니다.

# /etc/systemd/system/vllm.service
[Unit]
Description=vLLM server (munuibot)
After=network-online.target

[Service]
User=llm
EnvironmentFile=/etc/vllm/vllm.env
ExecStart=/home/llm/vllm-lab/.venv-vllm/bin/vllm serve Qwen/Qwen3-8B \
  --host 127.0.0.1 --port 8000 --served-model-name munuibot \
  --max-model-len 8192 --gpu-memory-utilization 0.90
Restart=on-failure

[Install]
WantedBy=multi-user.target
# /etc/vllm/vllm.env 에는 VLLM_API_KEY=..., HF_HOME=... 처럼 값만 둔다
sudo systemctl daemon-reload
sudo systemctl enable --now vllm
journalctl -u vllm -f          # 2절의 기동 로그를 여기서 읽는다

🔍 읽는 포인트

  • ExecStart — 가상환경 안의 vllm 실행 파일을 절대 경로로 부릅니다. activate 없이도 그 환경이 쓰입니다.
  • EnvironmentFile — 키를 유닛 파일 밖의 환경 파일 에 둡니다. 이것이 흔히 .env라고 부르는 방식입니다. .env 파일 은 [설정 파일]인데, [ 비밀값과 환경마다 달라지는 값을 이름=값 줄로 적어 코드 · 설정 본문 밖에 둔다 ]는 점에서 코드에 값을 직접 쓰는 방식과 구별됩니다. 규칙은 셋입니다. ① 비밀값은 코드에 쓰지 않는다 ② 값이 든 파일은 Git에 올리지 않는다 ③ 대신 키 이름만 적은 .env.example을 올린다(20차시 3.3).
  • Restart=on-failure — 죽으면 다시 띄웁니다. enable은 재부팅 후 자동 시작.

6.2 Docker 컨테이너로

용어정의
Docker 이미지[실행 환경 꾸러미]인데, [ 앱과 그 앱이 쓰는 OS 라이브러리까지 한 묶음으로 굳혀 버전 태그를 붙인다 ]는 점에서 파이썬 패키지만 격리하는 가상환경과 구별된다
컨테이너[격리된 프로세스]인데, [ 이미지를 실행한 것 ]이라는 점에서 디스크에 저장된 이미지와 구별된다. 이미지 : 컨테이너 = 프로그램 파일 : 실행 중인 프로그램 (축 ①)
docker run --gpus all --ipc=host \
  -p 127.0.0.1:8000:8000 \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  --env-file ./vllm.env \
  vllm/vllm-openai:<버전태그> \
  --model Qwen/Qwen3-8B --served-model-name munuibot --max-model-len 8192

🔍 읽는 포인트

  • --gpus all — 컨테이너는 기본적으로 GPU를 보지 못합니다. 호스트(컨테이너를 돌리는 실제 기계)에 NVIDIA Container Toolkit (컨테이너에 GPU를 연결해 주는 NVIDIA 도구)이 설치되어 있어야 이 옵션이 동작합니다.
  • --ipc=host — 컨테이너가 호스트의 공유 메모리를 쓰게 합니다. vLLM(PyTorch)이 프로세스 사이에 공유 메모리를 쓰기 때문에 공식 문서가 이 옵션(또는 넉넉한 --shm-size)을 권합니다.
  • -p 127.0.0.1:8000:8000 — 호스트 주소:호스트 포트:컨테이너 포트로 바깥 창구와 컨테이너 안 창구를 잇습니다. 앞에 127.0.0.1을 붙이지 않으면 0.0.0.0에 열립니다(5.2).
  • -v ...huggingface... — 모델 캐시를 볼륨 (컨테이너 밖의 디스크 폴더를 컨테이너 안에 붙이는 것)으로 연결해, 컨테이너를 지워도 모델을 다시 받지 않게 합니다.
  • <버전태그> — latest 대신 버전을 고정 합니다. 이미지 이름과 인자 형식은 공식 문서의 Docker 배포 페이지에서 확인합니다.
systemd + 가상환경Docker
격리 강도파이썬 패키지만앱 + OS 라이브러리
버전 고정가상환경 재현이 손에 달림이미지 태그 하나로 고정
재시작 · 부팅Restart=, enable--restart, 또는 Podman(Docker와 같은 컨테이너 표준을 따르는 다른 엔진) + systemd
어울리는 곳장비 한 대, 빠른 실험여러 장비에 같은 환경 배포, 5일차 프로젝트

7. 실습 — 맡기고 검수하기

지시

18차시에 만든 .venv-vllm 환경으로 vLLM 서버를 띄우고 확인해줘.
맥락: vllm serve --help 출력과 공식 문서(docs.vllm.ai)의 OpenAI-compatible server 페이지를 근거로 할 것.
제약:
- --host 127.0.0.1, --port 8000, --served-model-name munuibot, API 키는 환경변수 VLLM_API_KEY로.
- 0.0.0.0으로 열지 마. systemd 등록은 유닛 파일 내용을 먼저 보여주고 내 승인 후에.
할 일:
1. --max-model-len 8192로 기동. 기동 로그에서 가중치 메모리 / KV 캐시 크기 / Maximum concurrency 줄을 원문 그대로 뽑아줘.
2. config.json에서 max_position_embeddings 값을 확인하고, --max-model-len을 그 값으로 바꿔 다시 기동. 실패하면 에러 원문을.
3. 요청이 0개일 때 nvidia-smi --query-gpu=memory.used,memory.total --format=csv 출력.
4. /health, /v1/models(키 있음/없음), /v1/chat/completions 한 건의 HTTP 코드와 응답 원문.
5. ss -ltnp | grep 8000 출력.
보고 형식: [항목 | 실행한 명령 | 출력 원문 | 한 줄 해석] 표.
추측하지 말고 실행 출력 원문을 붙여.

받을 증거

  • 기동 로그 세 줄 원문 (8192일 때, 최대치일 때 각각)
  • nvidia-smi 메모리 한 줄, curl 결과 네 개, ss 한 줄

내가 직접 볼 것

볼 것이걸로 아는 것
Maximum concurrency 값2.3 계산(2.7 ~ 3.5개 근처)과 비슷한가. 크게 다르면 조건(정밀도 · 오버헤드)이 다른 것
최대치로 띄웠을 때의 결과4절의 기동 에러가 실제로 나는가, 에러가 무엇을 하라고 하는가
요청 0개일 때 memory.used전체의 90% 근처면 정상 (3절)
키 없는 /v1/models401 이어야 함
/v1/models의 idmunuibot
ss 출력의 주소127.0.0.1:8000 (❌ 0.0.0.0:8000)

부록 A. 스스로 확인하기

#질문답이 있는 곳
1--max-model-len과 --gpu-memory-utilization은 VRAM 예산식의 어느 항을 정하는가?1.2
2--served-model-name을 쓰면 앱 쪽에 어떤 이득이 있는가?1.1
3기동 로그에서 찾을 세 줄과 각각의 뜻은?2.1
4"Maximum concurrency: X"는 최대 동시 접속자 수인가?2.2
524GB에서 Qwen3-8B BF16, 8192 토큰이면 X는 대략 얼마로 짐작되는가?2.3
6요청이 없는데 nvidia-smi가 꽉 찬 이유는?3
7--max-model-len을 생략하면 왜 기동 에러가 날 수 있는가?4
80.0.0.0 + 키 없음이 위험한 이유를 바인딩 주소와 인증으로 설명하면?5.2
9systemd를 유와 종차로 정의하면? 유닛 파일에서 ExecStart가 가상환경의 절대 경로를 쓰는 이유는?6.1
10Docker 이미지와 컨테이너는 무엇으로 갈리는가? systemd + 가상환경과 비교하면 무엇을 더 격리하는가?6.2

부록 B. 자주 하는 실수

실수바로잡기
"요청도 없는데 메모리를 90% 쓴다 → 메모리 누수"❌ 기동 시 미리 확보 . 정상
"Maximum concurrency가 3이니 동시 접속 3명까지"❌ 최대 길이 가정의 값. 실제 요청이 짧으면 더 들어가고, 넘치면 대기열로
--max-model-len 생략⚠️ 모델 최대치가 적용되어 기동 실패하거나 동시 수용량이 크게 줄 수 있음
테스트하려고 --host 0.0.0.0⚠️ 같은 네트워크 전체에 열림. 127.0.0.1이 기본
API 키를 명령줄에 직접⚠️ 셸 기록 · 프로세스 목록에 남음. 환경변수 · 파일로
FastAPI와 vLLM을 둘 다 8000에❌ 네트워크 포트 충돌. 하나를 옮김
Docker 이미지를 latest로⚠️ 다음 실행 때 다른 버전이 뜰 수 있음. 태그 고정

부록 C. NotebookLM 복습 프롬프트

이 19차시 노트만 근거로 6문제를 내줘. 비전공자 기준으로.
"Maximum concurrency 줄의 뜻", "nvidia-smi가 꽉 차 보이는 것이 정상인 이유", "컨텍스트 길이가 크면 기동 에러가 나는 이유", "0.0.0.0의 위험"은 반드시 포함해줘.
답은 내가 답한 다음에 채점하고, 틀린 이유를 노트의 절 번호를 근거로 설명해줘.