Qdrant 클러스터 관리
Qdrant 클러스터 관리 (private-cloud-qdrant-cluster-management)
가장 간단한 QdrantCluster 구성은 다음과 같아요.
apiVersion: qdrant.io/v1
kind: QdrantCluster
metadata:
name: qdrant-a7d8d973-0cc5-42de-8d7b-c29d14d24840
labels:
cluster-id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
customer-id: "acme-industries"
spec:
id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
version: "v1.11.3"
size: 1
resources:
cpu: 100m
memory: "1Gi"
storage: "2Gi"
id는 같은 네임스페이스 안의 모든 Qdrant 클러스터에서 고유해야 해요. name은 위 패턴을 따라야 하고, cluster-id와 customer-id 레이블은 필수예요.
스케줄링, 보안, 네트워킹 등 더 많은 구성 옵션이 있어요. 전체 세부 사항은 Qdrant Private Cloud API 레퍼런스를 참고하세요.
클러스터 스케일링 (Scaling a Cluster)
클러스터를 스케일링하려면 QdrantCluster spec에서 CPU, 메모리, 스토리지 리소스를 업데이트해요. Qdrant operator가 클러스터 구성을 자동으로 조정해요. 이 작업은 복제된 컬렉션을 가진 멀티 노드 클러스터에서 고가용성이에요.
수직 스케일링은 CSI 드라이버와 StorageClass가 볼륨 확장을 허용할 때만 가능해요. 디스크 스토리지는 축소할 수 없어요.
Qdrant 버전 업그레이드 (Upgrading the Qdrant version)
데이터베이스 클러스터의 Qdrant 버전을 업그레이드하려면 QdrantCluster spec의 version 필드를 업데이트해요. Qdrant operator가 자동으로 클러스터를 새 버전으로 업그레이드해요. 업그레이드 프로세스는 복제된 컬렉션을 가진 멀티 노드 클러스터에서 고가용성이에요.
참고로, 업그레이드 시 마이너 버전을 건너뛰지 않아야 해요. 예를 들어 v1.11.3을 실행 중이라면 v1.11.5나 v1.12.6으로는 업그레이드할 수 있지만, v1.13.0으로는 직접 업그레이드할 수 없어요.
클러스터 노출 (Exposing a Cluster)
기본적으로 QdrantCluster는 내부 ClusterIP 서비스를 통해 노출돼요. 클러스터를 외부에 노출하려면 NodePort 서비스, LoadBalancer 서비스, 또는 Ingress 리소스를 만들 수 있어요.
LoadBalancer 서비스로 QdrantCluster를 만드는 예시는 다음과 같아요.
apiVersion: qdrant.io/v1
kind: QdrantCluster
metadata:
name: qdrant-a7d8d973-0cc5-42de-8d7b-c29d14d24840
labels:
cluster-id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
customer-id: "acme-industries"
spec:
id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
version: "v1.11.3"
size: 1
resources:
cpu: 100m
memory: "1Gi"
storage: "2Gi"
service:
type: LoadBalancer
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
특히 LoadBalancer 서비스를 만들 때는 로드밸런서 구성에 대한 애너테이션(annotations) 을 제공해야 할 수 있어요. 자세한 내용은 클라우드 공급자의 문서를 참고하세요.
예시:
- AWS EKS LoadBalancer annotations
- Azure AKS Public LoadBalancer annotations
- Azure AKS Internal LoadBalancer annotations
- GCP GKE LoadBalancer annotations
내부 통신 채널은 API 키나 bearer 토큰으로 보호되지 않아요. 내부 gRPC는 포트 6335를 사용해요. 이 포트가 공개적으로 도달 가능하지 않고 노드 통신에만 사용될 수 있도록 보장해야 해요. 기본적으로 Qdrant Private Cloud는 Qdrant 클러스터 노드 간 포트 6335 통신만 허용하는 엄격한 NetworkPolicy를 배포해요.
인증과 권한 부여 (Authentication and Authorization)
기본적으로 Hybrid Cloud의 클러스터는 Kubernetes 네트워크 내부의 Kubernetes ClusterIP 서비스로만 노출되어 외부에서 접근할 수 없고, API 키도 구성되지 않아요. 데이터베이스를 내부 또는 외부로 노출하기로 선택하면 API 키를 구성해야 해요.
인증 정보는 Kubernetes 시크릿으로 제공돼요.
secret을 만드는 한 가지 방법은 kubectl을 사용하는 거예요.
kubectl create secret generic qdrant-api-key --from-literal=api-key=your-secret-api-key --from-literal=read-only-api-key=your-secret-read-only-api-key --namespace qdrant-private-cloud
결과물로 생성되는 secret은 다음과 같아요.
apiVersion: v1
data:
api-key: ***
read-only-api-key: ***
kind: Secret
metadata:
name: qdrant-api-key
namespace: qdrant-private-cloud
type: kubernetes.io/generic
QdrantCluster spec에서 secret을 참조할 수 있어요.
apiVersion: qdrant.io/v1
kind: QdrantCluster
metadata:
name: qdrant-a7d8d973-0cc5-42de-8d7b-c29d14d24840
labels:
cluster-id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
customer-id: "acme-industries"
spec:
id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
version: "v1.11.3"
size: 1
resources:
cpu: 100m
memory: "1Gi"
storage: "2Gi"
config:
service:
api_key:
secretKeyRef:
name: qdrant-api-key
key: api-key
read_only_api_key:
secretKeyRef:
name: qdrant-api-key
key: read-only-api-key
jwt_rbac: true
jwt_rbac 플래그를 설정하면 세분화된 역할 기반 접근 제어용 JWT 토큰도 만들 수 있어요.
데이터베이스 접근용 TLS 구성 (Configuring TLS for Database Access)
Qdrant 데이터베이스에 접근하기 위한 TLS를 구성하려면 두 가지 옵션이 있어요.
- ingress 또는 로드밸런서 수준에서 TLS를 오프로드할 수 있어요.
- Qdrant 데이터베이스에서 직접 TLS를 구성할 수 있어요.
Qdrant 데이터베이스에서 직접 TLS를 구성하려면 secret으로 제공할 수 있어요.
이런 secret을 만들려면 kubectl을 사용할 수 있어요.
kubectl create secret tls qdrant-tls --cert=mydomain.com.crt --key=mydomain.com.key --namespace the-qdrant-namespace
결과물로 생성되는 secret은 다음과 같아요.
apiVersion: v1
data:
tls.crt: ...
tls.key: ...
kind: Secret
metadata:
name: qdrant-tls
namespace: the-qdrant-namespace
type: kubernetes.io/tls
QdrantCluster spec에서 secret을 참조할 수 있어요.
apiVersion: qdrant.io/v1
kind: QdrantCluster
metadata:
name: test-cluster
spec:
id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
version: "v1.11.3"
size: 1
resources:
cpu: 100m
memory: "1Gi"
storage: "2Gi"
config:
service:
enable_tls: true
tls:
cert:
secretKeyRef:
name: qdrant-tls
key: tls.crt
key:
secretKeyRef:
name: qdrant-tls
key: tls.key
클러스터 간 통신용 TLS 구성 (Configuring TLS for Inter-cluster Communication)
Operator v2.2.0부터 사용 가능
이 기능은 클러스터 생성 시에만 활성화할 수 있어요. 이후 변경은 불가능해요.
Qdrant 노드 간 통신을 암호화하려면 인증서, 키, 그리고 이를 생성하는 데 사용되는 루트 CA 인증서를 제공해 TLS를 활성화해야 해요.
이전 섹션의 지침과 유사하게 secret을 만들어야 해요.
kubectl create secret generic qdrant-p2p-tls \
--from-file=tls.crt=qdrant-nodes.crt \
--from-file=tls.key=qdrant-nodes.key \
--from-file=ca.crt=root-ca.crt
--namespace the-qdrant-namespace
결과물로 생성되는 secret은 다음과 같아요.
apiVersion: v1
data:
tls.crt: ...
tls.key: ...
ca.crt: ...
kind: Secret
metadata:
name: qdrant-p2p-tls
namespace: the-qdrant-namespace
type: Opaque
QdrantCluster spec에서 secret을 참조할 수 있어요.
apiVersion: qdrant.io/v1
kind: QdrantCluster
metadata:
name: test-cluster
labels:
cluster-id: "my-cluster"
customer-id: "acme-industries"
spec:
id: "my-cluster"
version: "v1.13.3"
size: 2
resources:
cpu: 100m
memory: "1Gi"
storage: "2Gi"
config:
service:
enable_tls: true
tls:
caCert:
secretKeyRef:
name: qdrant-p2p-tls
key: ca.crt
cert:
secretKeyRef:
name: qdrant-p2p-tls
key: tls.crt
key:
secretKeyRef:
name: qdrant-p2p-tls
key: tls.key
operator는 다음 규칙에 따라 클러스터의 노드에 이름을 할당해요.
qdrant-{spec.id}-{node-index}.qdrant-headless-{spec.id}따라서 데이터베이스 접근에 사용되는 도메인에 더해, 제공된 인증서에는 예정된 모든 노드에 대한 Subject Alternative Names(SAN) 이 포함되어야 해요. 이는 원하는 도구로 생성할 수 있는데, 예를 들어 step CLI를 사용할 수 있어요. 예시
QdrantCluster에 따라 적절한 인증서는 다음과 같이 얻을 수 있어요.step certificate create mydomain.com qdrant-nodes.crt qdrant-nodes.key \ --profile leaf --not-after 43800h \ --ca root-ca.crt --ca-key root-ca.key \ --san qdrant-my-cluster-0.qdrant-headless-my-cluster \ --san qdrant-my-cluster-1.qdrant-headless-my-cluster
감사 로깅 (Audit Logging)
Qdrant v1.17.0부터 사용 가능
감사 로깅은 인증 또는 권한 부여가 필요한 API 작업을 데이터베이스 볼륨의 JSON 로그 파일에 기록해요. 기본적으로 비활성화돼 있어요. QdrantCluster에서 spec.config.audit 아래에 활성화하세요.
apiVersion: qdrant.io/v1
kind: QdrantCluster
metadata:
name: qdrant-a7d8d973-0cc5-42de-8d7b-c29d14d24840
labels:
cluster-id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
customer-id: "acme-industries"
spec:
id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
version: "v1.17.0"
size: 1
resources:
cpu: 100m
memory: "1Gi"
storage: "2Gi"
config:
service:
api_key:
secretKeyRef:
name: qdrant-api-key
key: api-key
audit:
enabled: true
rotation: daily
max_log_files: 7
trust_forwarded_headers: false
trust_forwarded_headers는 Qdrant가 TCP 연결 대신 X-Forwarded-For 헤더에서 클라이언트 주소를 가져오게 해요. 클러스터가 신뢰할 수 있는 리버스 프록시나 로드밸런서 뒤에 있을 때만 활성화하세요. 공개적으로 도달 가능한 인스턴스에서는 클라이언트가 감사 로그에서 자신의 IP 주소를 위조할 수 있어요.
감사 항목은 kubectl logs가 보여주는 컨테이너 stdout이 아니라 클러스터의 데이터베이스 볼륨(기본 ./storage/audit)의 파일에 기록돼요. 감사 로깅은 장황하고 파일이 빠르게 커질 수 있으므로, PersistentVolume에 충분한 여유 공간을 확보하세요. 애플리케이션 로그와 함께 수집하려면 Logging & Monitoring을 참고하세요.
Operator는 클러스터가 Qdrant v1.17.0 이상을 실행할 때만 이 구성을 작성해요. 이전 버전에서는 조용히 무시돼요. QdrantCluster는 여전히 enabled: true를 보여주지만, 감사 로그는 작성되지 않고 오류도 보고되지 않아요.
Qdrant v1.18.0부터 클라이언트는 추적 ID(예: x-request-id)를 보낼 수 있고, POST /audit/logs로 항목을 쿼리할 수 있어요. 로테이션 옵션과 쿼리 API를 포함한 세부 사항은 Audit Logging에 있어요. AuditConfig의 필드 수준 참조는 Qdrant Private Cloud API 레퍼런스에 있어요.
GPU 지원 (GPU support)
Qdrant 1.13과 private-cloud 버전 1.6.1부터 인덱싱을 가속화하는 GPU를 사용하는 클러스터를 만들 수 있어요.
전제 조건으로, GPU를 지원하는 Kubernetes 클러스터가 필요해요. GPU와 Kubernetes에 대한 일반 정보는 Kubernetes 문서를, 또는 특정 Kubernetes 배포판의 문서를 확인할 수 있어요.
예시:
GPU를 지원하는 Kubernetes 클러스터가 있으면 GPU 지원 QdrantCluster를 만들 수 있어요.
apiVersion: qdrant.io/v1
kind: QdrantCluster
metadata:
name: qdrant-a7d8d973-0cc5-42de-8d7b-c29d14d24840
labels:
cluster-id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
customer-id: "acme-industries"
spec:
id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
version: "v1.13.4"
size: 1
resources:
cpu: 2
memory: "8Gi"
storage: "40Gi"
gpu:
gpuType: "nvidia"
클러스터 Pod가 시작되면 로그에서 GPU가 감지되는지 확인할 수 있어요.
$ kubectl logs qdrant-a7d8d973-0cc5-42de-8d7b-c29d14d24840-0
Starting initializing for pod 0
_ _
__ _ __| |_ __ __ _ _ __ | |_
/ _` |/ _` | '__/ _` | '_ \| __|
| (_| | (_| | | | (_| | | | | |_
\__, |\__,_|_| \__,_|_| |_|\__|
|_|
Version: 1.13.4, build: 7abc6843
Access web UI at http://localhost:6333/dashboard
2025-03-14T10:25:30.509636Z INFO gpu::instance: Found GPU device: NVIDIA A16-2Q
2025-03-14T10:25:30.509679Z INFO gpu::instance: Found GPU device: llvmpipe (LLVM 15.0.7, 256 bits)
2025-03-14T10:25:30.509734Z INFO gpu::device: Create GPU device NVIDIA A16-2Q
...
더 많은 GPU 구성 옵션은 Qdrant Private Cloud API 레퍼런스를 참고하세요.
임시 스냅샷 볼륨 (Ephemeral Snapshot Volumes)
스냅샷을 만들지 않거나, 클러스터 재시작 후에도 스냅샷을 유지할 필요가 없다면, 스냅샷 스토리지 클래스 이름을 emptyDir로 설정할 수 있어요.
apiVersion: qdrant.io/v1
kind: QdrantCluster
metadata:
name: qdrant-a7d8d973-0cc5-42de-8d7b-c29d14d24840
labels:
cluster-id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
customer-id: "acme-industries"
spec:
id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
version: "v1.13.4"
size: 1
resources:
cpu: 2
memory: "8Gi"
storage: "40Gi"
storageClassNames:
snapshots: emptyDir
k8s 노드의 임시 스토리지가 어떻게 할당·사용되는지에 대한 자세한 내용은 Kubernetes의 emptyDir 볼륨 문서를 참고하세요.
자동 샤드 리밸런싱 (Automatic Shard Rebalancing)
Qdrant Private Cloud는 자동 샤드 리밸런싱을 지원해요. 샤드는 클러스터의 노드 수를 확장·축소할 때를 포함해 데이터가 고르게 분포되도록 사용 가능한 노드 전반에 지속적으로 재분배돼요. 자동 리밸런싱은 전체 클러스터에 적용돼요. 샤드가 활성 상태일 때 수동으로 이동했고, 그 이동으로 노드의 샤드 개수나 크기가 목표 밖으로 벗어나면, 수정을 위해 샤드가 다시 이동될 수 있어요. 샤드 배치를 수동으로 제어해야 한다면 먼저 자동 샤드 리밸런싱을 비활성화하세요.
자동 샤드 리밸런싱을 활성화하려면 QdrantCluster spec의 rebalancestrategy 필드를 설정할 수 있어요.
apiVersion: qdrant.io/v1
kind: QdrantCluster
metadata:
name: qdrant-a7d8d973-0cc5-42de-8d7b-c29d14d24840
labels:
cluster-id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
customer-id: "acme-industries"
spec:
id: "a7d8d973-0cc5-42de-8d7b-c29d14d24840"
version: "v1.15.1"
size: 3
rebalanceStrategy: by_count_and_size
resources:
cpu: 2
memory: "8Gi"
storage: "40Gi"
사용 가능한 모든 리밸런싱 전략 목록은 Qdrant Private Cloud API 레퍼런스를 참고하세요.
리샤딩 (Resharding)
Qdrant Cloud에서는 기존 컬렉션을 처음부터 다시 만들 필요 없이 샤드 수를 변경할 수 있어요. 이 기능을 리샤딩(resharding)이라고 하며, 필요에 따라 컬렉션을 확장·축소할 수 있게 해요. 자세한 내용은 Resharding을 참고하세요.