ติดตั้ง Qdrant Vector Database บน VPS สำหรับงาน AI และ RAG
Qdrant คือ vector database โอเพ่นซอร์สที่เขียนด้วย Rust ออกแบบมาเพื่อจัดเก็บและค้นหา vector embeddings ด้วยความเร็วสูง เหมาะสำหรับงาน semantic search, recommendation engine และโดยเฉพาะ RAG (Retrieval-Augmented Generation) ที่ต้องการนำ LLM มาใช้ร่วมกับข้อมูลของตัวเอง
บทความนี้ครอบคลุมการติดตั้ง Qdrant บน VPS Linux ผ่าน Docker, การสร้าง collection, การ insert และค้นหา vector ผ่าน REST API รวมถึงการตั้งค่า authentication, TLS และ backup สำหรับ production
ทำไมต้องใช้ Qdrant บน VPS ของตัวเอง?
- ควบคุม data ได้ 100% — ข้อมูล embedding ไม่ออกไปยัง cloud provider
- ประหยัดค่าใช้จ่ายเมื่อเทียบกับ managed services (Pinecone, Weaviate Cloud)
- Latency ต่ำเมื่อ LLM กับ vector DB อยู่ VPS เดียวกัน
- ปรับแต่ง index parameter ได้ตามข้อมูลจริง
1 ความต้องการของระบบ
| ทรัพยากร | ขั้นต่ำ | แนะนำ |
|---|---|---|
| RAM | 2 GB | 8 GB ขึ้นไป |
| CPU | 2 vCPU | 4+ vCPU |
| Disk | 20 GB SSD | 50+ GB NVMe |
| OS | Ubuntu 22.04+ | Ubuntu 24.04 / Debian 12 |
2 ติดตั้ง Docker (ถ้ายังไม่มี)
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker
docker --version
3 ติดตั้ง Qdrant ด้วย Docker Compose
สร้างไดเรกทอรีและไฟล์ config:
mkdir -p ~/qdrant/{config,storage,snapshots}
cd ~/qdrant
สร้างไฟล์ docker-compose.yml:
version: "3.8"
services:
qdrant:
image: qdrant/qdrant:latest
container_name: qdrant
restart: unless-stopped
ports:
- "127.0.0.1:6333:6333" # REST API (bind localhost เท่านั้น)
- "127.0.0.1:6334:6334" # gRPC
volumes:
- ./storage:/qdrant/storage
- ./snapshots:/qdrant/snapshots
- ./config/production.yaml:/qdrant/config/production.yaml:ro
environment:
- QDRANT__SERVICE__API_KEY=YOUR_SECRET_API_KEY_HERE
สร้างไฟล์ config/production.yaml สำหรับ tune performance:
storage:
# จำนวน segment ต่อ collection
optimizers_config:
default_segment_number: 2
service:
max_request_size_mb: 32
max_workers: 0 # 0 = ใช้ CPU ทั้งหมด
# เปิด telemetry ปิดเพื่อ privacy
telemetry_disabled: true
เปลี่ยน YOUR_SECRET_API_KEY_HERE แล้วรัน:
docker compose up -d
docker compose logs -f qdrant
4 ทดสอบ API เบื้องต้น
# ดู version
curl http://localhost:6333/
# สร้าง collection ชื่อ "my_docs" — 1536 dimensions (OpenAI ada-002)
curl -X PUT http://localhost:6333/collections/my_docs \
-H "Content-Type: application/json" \
-H "api-key: YOUR_SECRET_API_KEY_HERE" \
-d '{
"vectors": {
"size": 1536,
"distance": "Cosine"
}
}'
Cosine เหมาะกับ text embeddings, Dot เหมาะกับ normalized vectors, Euclid สำหรับ image/sensor data5 Insert และ Search Vector
Insert ตัวอย่าง (ใช้ dummy vector ความยาว 4 เพื่อสาธิต):
# สร้าง collection ขนาดเล็กสำหรับทดสอบ
curl -X PUT http://localhost:6333/collections/test \
-H "Content-Type: application/json" \
-H "api-key: YOUR_SECRET_API_KEY_HERE" \
-d '{"vectors": {"size": 4, "distance": "Dot"}}'
# Insert points
curl -X PUT http://localhost:6333/collections/test/points \
-H "Content-Type: application/json" \
-H "api-key: YOUR_SECRET_API_KEY_HERE" \
-d '{
"points": [
{
"id": 1,
"vector": [0.05, 0.61, 0.76, 0.74],
"payload": {"city": "Bangkok", "country": "Thailand"}
},
{
"id": 2,
"vector": [0.19, 0.81, 0.75, 0.11],
"payload": {"city": "Tokyo", "country": "Japan"}
}
]
}'
# Search nearest vector
curl -X POST http://localhost:6333/collections/test/points/search \
-H "Content-Type: application/json" \
-H "api-key: YOUR_SECRET_API_KEY_HERE" \
-d '{
"vector": [0.2, 0.1, 0.9, 0.7],
"limit": 2,
"with_payload": true
}'
6 ใช้ Qdrant กับ Python SDK
pip install qdrant-client openai
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
client = QdrantClient(
url="http://localhost:6333",
api_key="YOUR_SECRET_API_KEY_HERE"
)
# สร้าง collection
client.create_collection(
collection_name="knowledge_base",
vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
)
# Insert vector จาก OpenAI embedding
import openai
openai.api_key = "sk-..."
text = "วิธีติดตั้ง Nginx บน Ubuntu"
response = openai.embeddings.create(model="text-embedding-ada-002", input=text)
vector = response.data[0].embedding
client.upsert(
collection_name="knowledge_base",
points=[PointStruct(id=1, vector=vector, payload={"text": text, "url": "/vps-nginx.html"})]
)
# Semantic search
query = "ตั้งค่า web server"
q_vec = openai.embeddings.create(model="text-embedding-ada-002", input=query).data[0].embedding
results = client.search(collection_name="knowledge_base", query_vector=q_vec, limit=5)
for r in results:
print(r.score, r.payload)
7 ตั้งค่า Nginx Reverse Proxy + TLS
เปิด port ผ่าน Nginx พร้อม Let's Encrypt เพื่อให้ client ภายนอกเชื่อมต่อได้อย่างปลอดภัย:
server {
listen 443 ssl http2;
server_name qdrant.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/qdrant.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/qdrant.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:6333;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# จำกัดเฉพาะ IP ที่อนุญาต
allow 203.0.113.10; # IP ของ app server
deny all;
}
}
8 Backup Collection ด้วย Snapshot
# สร้าง snapshot
curl -X POST http://localhost:6333/collections/my_docs/snapshots \
-H "api-key: YOUR_SECRET_API_KEY_HERE"
# ดูรายการ snapshot
curl http://localhost:6333/collections/my_docs/snapshots \
-H "api-key: YOUR_SECRET_API_KEY_HERE"
# Download snapshot
curl -o my_docs_backup.snapshot \
http://localhost:6333/collections/my_docs/snapshots/SNAPSHOT_NAME \
-H "api-key: YOUR_SECRET_API_KEY_HERE"
สร้าง cron job backup ทุกคืน:
#!/bin/bash
# /usr/local/bin/qdrant-backup.sh
DATE=$(date +%Y%m%d)
API_KEY="YOUR_SECRET_API_KEY_HERE"
BACKUP_DIR="/var/backups/qdrant"
mkdir -p "$BACKUP_DIR"
# Snapshot collection ทั้งหมด
for col in $(curl -s http://localhost:6333/collections -H "api-key: $API_KEY" | jq -r '.result.collections[].name'); do
curl -s -X POST "http://localhost:6333/collections/$col/snapshots" \
-H "api-key: $API_KEY" > /dev/null
echo "Snapshotted: $col"
done
# Sync ไฟล์ snapshot ออก
rsync -a ~/qdrant/snapshots/ "$BACKUP_DIR/$DATE/"
find "$BACKUP_DIR" -maxdepth 1 -type d -mtime +7 -exec rm -rf {} +
ตรวจสอบว่า Qdrant ทำงานถูกต้อง
# ดูสถานะ container
docker compose ps
# ดู health
curl http://localhost:6333/healthz
# ดู metrics (Prometheus-compatible)
curl http://localhost:6333/metrics | grep qdrant
# ดูรายการ collection ทั้งหมด
curl http://localhost:6333/collections -H "api-key: YOUR_SECRET_API_KEY_HERE"
# ดูจำนวน point ใน collection
curl http://localhost:6333/collections/my_docs \
-H "api-key: YOUR_SECRET_API_KEY_HERE" | jq '.result.points_count'
http://localhost:6333/dashboard ใช้ดูและจัดการ collection แบบ visual ได้สะดวกมากระหว่าง developmentแก้ปัญหาที่พบบ่อย
Error: "Wrong input: Not existing collection"
Collection ยังไม่ถูกสร้าง หรือชื่อสะกดผิด ให้ตรวจสอบด้วย:
curl http://localhost:6333/collections -H "api-key: KEY"
# ถ้า collection ที่ต้องการไม่อยู่ในรายการ ให้สร้างใหม่ด้วย PUT /collections/{name}
Error: "Unauthorized" หรือ 403
API key ไม่ถูกต้อง หรือลืมส่ง header ตรวจสอบ environment variable:
docker compose exec qdrant env | grep API_KEY
# ถ้าไม่มีให้แก้ docker-compose.yml แล้ว restart
docker compose down && docker compose up -d
Error: "Out of memory" หรือ container crash
RAM ไม่พอสำหรับ index ที่โหลดอยู่ ให้ดู memory usage:
docker stats qdrant --no-stream
# ลดขนาด collection หรือเพิ่ม swap
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
Error: "Vector dimension mismatch"
Vector ที่ insert มีขนาดไม่ตรงกับที่ตั้งค่าใน collection ตรวจสอบ:
# ดู config ของ collection
curl http://localhost:6333/collections/my_docs \
-H "api-key: KEY" | jq '.result.config.params'
# size ต้องตรงกับ vector ที่จะ insert เสมอ
Container ช้าตอน startup เพราะ index ใหญ่
Qdrant โหลด index เข้า RAM ตอนเริ่มต้น collection ใหญ่ใช้เวลานาน ดู log:
docker compose logs -f qdrant | grep -i "loading\|loaded\|segment"
# ปกติสำหรับ 1M vectors อาจใช้เวลา 30–60 วินาที
คำถามที่พบบ่อย
Qdrant ต่างจาก Elasticsearch อย่างไร?
Elasticsearch เป็น full-text search engine ที่ทำ vector search ได้ (เพิ่มมาใหม่) แต่ Qdrant ถูกออกแบบมาเพื่อ vector search โดยเฉพาะ ทำให้ Qdrant เร็วกว่าและใช้ RAM น้อยกว่าสำหรับ workload ที่เป็น vector ล้วนๆ และมี filtering ที่ซับซ้อนกว่า
ต้องใช้ GPU ไหม?
ไม่จำเป็น Qdrant ทำงานบน CPU ได้ดีมาก GPU ต้องการเฉพาะตอน generate embedding (เช่น ใช้ model ของตัวเอง) ถ้าใช้ OpenAI API หรือ Ollama แยก การ search/insert บน Qdrant ใช้ CPU อย่างเดียวก็เพียงพอ
รองรับ multi-tenancy ได้ไหม?
ได้ โดย filter ด้วย payload เช่น เก็บ tenant_id ใน payload แล้ว filter ตอน search จะได้ผลลัพธ์เฉพาะของ tenant นั้น หรือสร้างแยก collection ต่อ tenant ถ้าข้อมูลแต่ละ tenant ใหญ่มาก