在 GKE 上部署 Qdrant 向量数据库

本指南介绍如何在 Google Kubernetes Engine (GKE) 上部署 Qdrant 向量数据库集群。

向量数据库是专门用于管理和搜索大型高维向量集合的数据存储区。这些矢量表示文本、图片、音频、视频等数据或可进行数字编码的任何数据。与依赖于完全匹配的传统数据库不同,向量数据库专注于在大量数据集中查找相似项或识别模式。这些特性使得 Qdrant 非常适合各种应用,包括神经网络或基于语义的匹配、分面搜索等。Qdrant 不仅可用作向量数据库,还可用作向量相似度搜索引擎。

本教程适用于想要在 GKE 上部署 Qdrant 数据库集群的云平台管理员和架构师机器学习工程师以及 MLOps (DevOps) 专业人员。

优势

Qdrant 具有以下优势:

  • 包含适用于各种编程语言的大量库,并提供可与其他服务集成的开放式 API。
  • 可横向扩缩,支持分片和复制,可简化扩缩和高可用性。
  • 支持容器和 Kubernetes 模式,可让您在现代化云原生环境中轻松开展部署和管理工作。
  • 提供灵活的载荷模式,可通过高级过滤功能精确定制搜索条件。
  • 不同的量化选项和其他优化,以降低基础设施费用并提高性能。

目标

在本教程中,您将学习如何:

  • 为 Qdrant 规划和部署 GKE 基础设施。
  • 部署 StatefulHA 运算符以确保 Qdrant 高可用性。
  • 部署并配置 Qdrant 集群。
  • 上传演示数据集并运行简单的搜索查询。
  • 收集指标并运行信息中心。

部署架构

此架构可跨多个可用区为 Qdrant 设置一个具有容错能力且可扩缩的 GKE 集群,通过滚动更新确保正常运行时间和可用性,并最大限度地减少中断。它包括使用 StatefulHA Operator 进行高效的故障切换管理。如需了解详情,请参阅区域级集群

架构图

下图显示了在 GKE 集群中的多个节点和可用区上运行的 Qdrant 集群:

Qdrant 部署架构

在此架构中,Qdrant StatefulSet 部署在三个不同可用区的三个节点上。

  • 您可以在 Helm 图表值文件中配置必要的 Pod 亲和性规则拓扑分布限制,从而控制 GKE 在各个节点之间分发 Pod 的方式。
  • 如果一个可用区发生故障,GKE 会根据推荐的配置在新节点上重新调度 Pod。

为了实现数据持久性,本教程中的架构具有以下特征:

  • 使用区域性 SSD 磁盘(自定义 regional-pd StorageClass)来保留数据。我们建议将区域 SSD 磁盘用于数据库,因为其延迟时间短、IOPS 高。
  • 所有磁盘数据都会在区域内的主要可用区和次要可用区之间进行复制,以更好地应对可能发生的可用区故障。

设置环境

如需使用 Cloud Shell 设置您的环境,请按照以下步骤操作:

  1. 为您的项目、区域和 Kubernetes 集群资源前缀设置环境变量:

    在本教程中,请使用 us-central1 区域创建部署资源。

    export PROJECT_ID=PROJECT_ID
    export KUBERNETES_CLUSTER_PREFIX=qdrant
    export REGION=us-central1
    
    • PROJECT_ID 替换为您的 Google Cloud项目 ID。
  2. 检查 Helm 的版本:

    helm version
    

    更新版本(如果低于 3.13):

    curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
    
  3. 从 GitHub 克隆示例代码库:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  4. 转到 qdrant 目录以开始创建部署资源:

    cd kubernetes-engine-samples/databases/qdrant
    

创建集群基础架构

本部分涉及运行 Terraform 脚本来创建可用性高的专用区域级 GKE 集群,以部署 Qdrant 数据库。

您可以选择使用标准集群或 Autopilot 集群部署 Qdrant。每种类型都有自己的优势和不同的价格模式。

Autopilot

下图展示了部署在三个不同可用区中的 Autopilot 区域级 GKE 集群。

GKE Autopilot 集群

若要部署集群基础设施,请在 Cloud Shell 中运行以下命令:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-autopilot init
terraform -chdir=terraform/gke-autopilot apply \
-var project_id=${PROJECT_ID} \
-var region=${REGION} \
-var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

以下变量会在运行时被替换:

  • GOOGLE_OAUTH_ACCESS_TOKEN:替换为通过 gcloud auth print-access-token 命令检索到的访问令牌,用于对与各种 Google Cloud API 之间的互动操作进行身份验证
  • PROJECT_IDREGIONKUBERNETES_CLUSTER_PREFIX 是在设置环境部分中定义的环境变量,分配给您要创建的 Autopilot 集群的新相关变量。

出现提示时,请输入 yes

输出类似于以下内容:

...
Apply complete! Resources: 9 added, 0 changed, 0 destroyed.

Outputs:

kubectl_connection_command = "gcloud container clusters get-credentials qdrant-cluster --region us-central1"

Terraform 会创建以下资源:

  • Kubernetes 节点的自定义 VPC 网络和专用子网。
  • 用于通过网络地址转换 (NAT) 访问互联网的 Cloud Router 路由器。
  • 专用 GKE 集群(在 us-central1 区域中)。
  • 具有集群的日志记录和监控权限的 ServiceAccount
  • 用于集群监控和提醒的 Google Cloud Managed Service for Prometheus 配置。

标准

下图展示了部署在三个不同可用区中的专用区域级 Standard GKE 集群。

GKE Standard 集群

若要部署集群基础设施,请在 Cloud Shell 中运行以下命令:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-standard init
terraform -chdir=terraform/gke-standard apply \
-var project_id=${PROJECT_ID} \
-var region=${REGION} \
-var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

以下变量会在运行时被替换:

  • GOOGLE_OAUTH_ACCESS_TOKEN 会被替换为通过 gcloud auth print-access-token 命令检索到的访问令牌,用于对与各种 Google Cloud API 之间的互动操作进行身份验证
  • PROJECT_IDREGIONKUBERNETES_CLUSTER_PREFIX 是在设置环境部分中定义的环境变量,分配给您要创建的标准集群的新相关变量。

出现提示时,请输入 yes。完成这些命令并使集群显示就绪状态可能需要几分钟时间。

输出类似于以下内容:

...
Apply complete! Resources: 10 added, 0 changed, 0 destroyed.

Outputs:

kubectl_connection_command = "gcloud container clusters get-credentials qdrant-cluster --region us-central1"

Terraform 会创建以下资源:

  • Kubernetes 节点的自定义 VPC 网络和专用子网。
  • 用于通过网络地址转换 (NAT) 访问互联网的 Cloud Router 路由器。
  • 位于 us-central1 区域并且启用了自动扩缩功能的专用 GKE 集群(每个可用区一个到两个节点)。
  • 具有集群的日志记录和监控权限的 ServiceAccount
  • 用于集群监控和提醒的 Google Cloud Managed Service for Prometheus 配置。

连接到集群

配置 kubectl 以提取凭据并与新的 GKE 集群通信:

gcloud container clusters get-credentials \
    ${KUBERNETES_CLUSTER_PREFIX}-cluster --location ${REGION}

将 Qdrant 数据库部署到您的集群

在本教程中,您会使用 Helm 图表将 Qdrant 数据库(分布式模式)和有状态 HA 运算符部署到 GKE 集群。

部署会创建具有以下配置的 GKE 集群:

  • Qdrant 节点的三个副本。
  • 配置了容忍、节点亲和性和拓扑分布限制,以确保在各个 Kubernetes 节点之间正确分发资源。这会利用节点池和不同的可用区。
  • 预配了具有 SSD 磁盘类型的 RePD 卷来存储数据。
  • 有状态 HA 运算符用于管理故障切换过程并确保高可用性。StatefulSet 是一种 Kubernetes 控制器,可为其每个 Pod 保留一个永久的唯一身份。
  • 数据库会创建一个包含 API 密钥的 Kubernetes Secret,用于进行身份验证。

如需使用 Helm 图表部署 Qdrant 数据库,请按照以下步骤操作:

  1. 启用 StatefulHA 插件

    Autopilot

    GKE 会在创建集群时自动启用 StatefulHA 插件。

    标准

    运行以下命令:

    gcloud container clusters update ${KUBERNETES_CLUSTER_PREFIX}-cluster \
        --project=${PROJECT_ID} \
        --location=${REGION} \
        --update-addons=StatefulHA=ENABLED
    

    完成此命令并使集群显示就绪状态可能需要 15 分钟。

  2. 先添加 Qdrant 数据库 Helm 图表代码库,然后才能将其部署到您的 GKE 集群:

    helm repo add qdrant https://qdrant.github.io/qdrant-helm
    
  3. 为数据库创建命名空间 qdrant

    kubectl create ns qdrant
    
  4. 应用此清单以创建区域级永久性 SSD 磁盘 StorageClass

    kubectl apply -n qdrant -f manifests/01-regional-pd/regional-pd.yaml
    

    regional-pd.yaml 清单描述了永久性 SSD 磁盘 StorageClass

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    allowVolumeExpansion: true
    metadata:
      name: ha-regional
    parameters:
      replication-type: regional-pd
      type: pd-ssd
      availability-class: regional-hard-failover
    provisioner: pd.csi.storage.gke.io
    reclaimPolicy: Retain
    volumeBindingMode: WaitForFirstConsumer
  5. 使用 Helm 部署具有 metrics Sidecar 配置和 Qdrant 集群的 Kubernetes configmap:

    kubectl apply -n qdrant -f manifests/03-prometheus-metrics/metrics-cm.yaml
    helm install qdrant-database qdrant/qdrant -n qdrant \
    -f manifests/02-values-file/values.yaml
    

    metrics-cm.yaml 清单描述了 metrics sidecar ConfigMap

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: nginx-conf
    data:
      default.conf.template: |
        server {
          listen 80;
          location / {
            proxy_pass http://localhost:6333/metrics;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header api-key ${QDRANT_APIKEY};
            proxy_set_header X-Forwarded-For $remote_addr;
          }
        }

    values.yaml 清单描述了 Qdrant 集群配置:

    replicaCount: 3
    
    config:
      service:
        enable_tls: false
      cluster:
        enabled: true
      storage:
        optimizers:
          deleted_threshold: 0.5
          vacuum_min_vector_number: 1500
          default_segment_number: 2
          max_segment_size_kb: null
          memmap_threshold_kb: null
          indexing_threshold_kb: 25000
          flush_interval_sec: 5
          max_optimization_threads: 1
    
    livenessProbe:
      enabled: true
      initialDelaySeconds: 60
    
    resources:
      limits:
        cpu: "2"
        memory: 4Gi
      requests:
        cpu: "1"
        memory: 4Gi
    
    tolerations:
      - key: "app.stateful/component"
        operator: "Equal"
        value: "qdrant"
        effect: NoSchedule
    
    affinity:
      nodeAffinity:
        preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 1
          preference:
            matchExpressions:
            - key: "app.stateful/component"
              operator: In
              values:
              - "qdrant"
    
    topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: "topology.kubernetes.io/zone"
        whenUnsatisfiable: ScheduleAnyway
        labelSelector:
          matchLabels:
            app.kubernetes.io/name: qdrant
            app.kubernetes.io/instance: qdrant
    
    podDisruptionBudget:
      enabled: true
      maxUnavailable: 1
    
    persistence:
      accessModes: ["ReadWriteOnce"]
      size: 10Gi
      storageClassName: ha-regional
    
    apiKey: true
    
    sidecarContainers:
      - name: metrics
        image: nginx:1.29
        resources:
          requests:
            memory: "128Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 80
        env:
        - name: QDRANT_APIKEY 
          valueFrom:
            secretKeyRef:
              name: qdrant-database-apikey          
              key: api-key
        volumeMounts:
            - name: nginx-conf
              mountPath: /etc/nginx/templates/default.conf.template
              subPath: default.conf.template
              readOnly: true
    additionalVolumes:
      - name: nginx-conf
        configMap:
          name: nginx-conf
          items:
            - key: default.conf.template
              path: default.conf.template 

    此配置会启用集群模式,允许您设置高可用性和分布式 Qdrant 集群。

  6. 为 Qdrant statefulset 添加标签:

    kubectl label statefulset qdrant-database examples.ai.gke.io/source=qdrant-guide -n qdrant
    
  7. 部署内部负载均衡器以访问与 GKE 集群位于同一 VPC 中的 Qdrant 数据库:

    kubectl apply -n qdrant -f manifests/02-values-file/ilb.yaml
    

    ilb.yaml 清单描述了 LoadBalancer Service:

    apiVersion: v1
    kind: Service
    metadata:
      annotations:
        #cloud.google.com/neg: '{"ingress": true}'
        networking.gke.io/load-balancer-type: "Internal"
      labels:
        app.kubernetes.io/name: qdrant
      name: qdrant-ilb
    spec:
      ports:
      - name: http
        port: 6333
        protocol: TCP
        targetPort: 6333
      - name: grpc
        port: 6334
        protocol: TCP
        targetPort: 6334
      selector:
        app: qdrant
        app.kubernetes.io/instance: qdrant-database
      type: LoadBalancer
  8. 检查部署状态:

    helm ls -n qdrant
    

    如果 qdrant 数据库成功部署,则输出类似于以下内容:

    NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
    qdrant-database  qdrant          1               2024-02-06 20:21:15.737307567 +0000 UTC deployed        qdrant-0.7.6    v1.7.4
    
  9. 等待 GKE 启动所需工作负载:

    kubectl wait pods -l app.kubernetes.io/instance=qdrant-database --for condition=Ready --timeout=300s -n qdrant
    

    此命令可能需要几分钟时间才能成功完成。

  10. GKE 启动工作负载后,验证 GKE 是否已创建 Qdrant 工作负载:

    kubectl get pod,svc,statefulset,pdb,secret -n qdrant
    
  11. 启动 Qdrant 的 HighAvailabilityApplication (HAA) 资源:

    kubectl apply -n qdrant -f manifests/01-regional-pd/ha-app.yaml
    

    ha-app.yaml 清单描述了 HighAvailabilityApplication 资源:

    kind: HighAvailabilityApplication
    apiVersion: ha.gke.io/v1
    metadata:
      name: qdrant-database
      namespace: qdrant
    spec:
      resourceSelection:
        resourceKind: StatefulSet
      policy:
        storageSettings:
          requireRegionalStorage: true
        failoverSettings:
          forceDeleteStrategy: AfterNodeUnreachable
          afterNodeUnreachable:
            afterNodeUnreachableSeconds: 20 # 60 seconds total

    系统会为 Qdrant 集群创建以下 GKE 资源:

    • 控制三个 Pod 副本的 Qdrant StatefulSet
    • A PodDisruptionBudget,确保最多只有一个不可用的副本。
    • qdrant-database Service,公开节点之间的入站连接和复制的 Qdrant 端口。
    • qdrant-database-headless Service,提供正在运行的 Qdrant Pod 的列表。
    • qdrant-database-apikey Secret,帮助实现安全的数据库连接。
    • 有状态 HA 运算符 Pod 和 HighlyAvailableApplication 资源,主动监控 Qdrant 应用。HighlyAvailableApplication 资源定义了要应用于 Qdrant 的故障切换规则。
  12. 如需检查故障切换规则是否已应用,请描述资源并确认 Status: Message: Application is protected

    kubectl describe highavailabilityapplication qdrant-database -n qdrant
    

    输出类似于以下内容:

    Status:
    Conditions:
        Last Transition Time:  2023-11-30T09:54:52Z
        Message:               Application is protected
        Observed Generation:   1
        Reason:                ApplicationProtected
        Status:                True
        Type:                  Protected
    

使用 Vertex AI Colab Enterprise 笔记本运行查询

Qdrant 以集合的形式组织向量和载荷。向量嵌入是一种将字词或实体表示为数值向量并同时保留其语义关系的方法。该方法对于相似性搜索非常重要,因为它可以根据含义而非完全匹配项来查找相似项,这使得搜索和推荐系统等任务更有效、更精细。

本部分介绍了如何将矢量上传到新的 Qdrant集合,以及如何运行搜索查询。

在此示例中,您将使用包含不同类型图书列表的 CSV 文件中的数据集。您创建一个 Colab Enterprise 笔记本,以对 Qdrant 数据库执行搜索查询。

如需详细了解 Vertex AI Colab Enterprise,请参阅 Colab Enterprise 文档

创建运行时模板

如需创建 Colab Enterprise 运行时模板,请执行以下操作:

  1. 在 Google Cloud 控制台中,前往 Colab Enterprise 运行时模板页面,并确保您的项目已被选中:

    进入运行时模板

  2. 点击 新建模板。系统会显示创建新的运行时模板页面。

  3. 运行时基本信息部分中:

    • 显示名称字段中,输入 qdrant-connect
    • 区域下拉列表中,选择 us-central1。该区域与 GKE 集群所在的区域相同。
  4. 配置计算部分中:

    • 机器类型下拉列表中,选择 e2-standard-2
    • 磁盘大小字段中,输入 30
  5. 网络和安全部分中:

    • 网络下拉列表中,选择 GKE 集群所在的网络。
    • 子网下拉列表中,选择相应的子网。
    • 清除启用公共互联网访问权限复选框。
  6. 点击创建以完成运行时模板的创建过程。您的运行时模板会显示在运行时模板标签页上的列表中。

创建运行时

如需创建 Colab Enterprise 运行时,请执行以下操作:

  1. 在运行时模板列表中,对于您刚刚创建的模板,点击操作列中的 ,然后点击创建运行时。此时会显示创建 Vertex AI 运行时窗格。

  2. 如需根据模板创建运行时,请点击创建

  3. 在打开的运行时标签页中,等待状态转换为健康

导入笔记本

如需在 Colab Enterprise 中导入笔记本,请执行以下操作:

  1. 前往我的笔记本标签页,然后点击导入。系统会显示导入笔记本窗格。

  2. 导入来源中,选择网址

  3. 笔记本网址下方,输入以下链接:

    https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/databases/qdrant/manifests/04-notebook/vector-database.ipynb
    
  4. 点击导入

连接到运行时并运行查询

如需连接到运行时并运行查询,请执行以下操作:

  1. 在笔记本中,点击连接按钮旁边的 其他连接选项。此时会显示连接到 Vertex AI Runtime 窗格。

  2. 选择连接到运行时,然后选择连接到现有运行时

  3. 选择您启动的运行时,然后点击连接

  4. 如需运行笔记本单元,请点击每个代码单元旁边的 运行单元按钮。

该笔记本包含代码单元和用于描述每个代码块的文本。运行代码单元会执行其命令并显示输出。您可以按顺序运行单元,也可以根据需要运行单个单元。

查看集群的 Prometheus 指标

GKE 集群配置了 Google Cloud Managed Service for Prometheus,可启用 Prometheus 格式的指标收集。该服务提供了监控和提醒的全托管式解决方案,允许收集、存储和分析来自集群及其应用的指标。

下图展示了 Prometheus 如何收集集群的指标:

Prometheus 指标收集

图中的 GKE 专用集群包含以下组件:

  • 公开路径 / 和端口 80 上指标的 Qdrant Pod。这些指标由名为 metrics 的边车容器提供。
  • 基于 Prometheus 的收集器,用于处理来自 Qdrant Pod 的指标。
  • 将指标发送到 Cloud Monitoring 的 PodMonitoring 资源。

如需导出和查看指标,请按照以下步骤操作:

  1. 创建 PodMonitoring 资源,以按 labelSelector 爬取指标:

    kubectl apply -n qdrant -f manifests/03-prometheus-metrics/pod-monitoring.yaml
    

    pod-monitoring.yaml 清单描述了 PodMonitoring 资源:

    apiVersion: monitoring.googleapis.com/v1
    kind: PodMonitoring
    metadata:
      name: qdrant
    spec:
      selector:
        matchLabels:
          app: qdrant
          app.kubernetes.io/instance: qdrant-database
      endpoints:
      - port: 80
        interval: 30s
        path: / 
  2. 使用 dashboard.json 中定义的配置创建 Cloud Monitoring 信息中心

    gcloud --project "${PROJECT_ID}" monitoring dashboards create --config-from-file monitoring/dashboard.json
    
  3. 命令成功运行后,前往 Cloud Monitoring 信息中心

    前往信息中心概览

  4. 从信息中心列表中,打开 Qdrant Overview 信息中心。收集和显示指标可能需要 1-2 分钟时间。

    信息中心会显示关键指标的计数:

    • 集合
    • 嵌入式向量
    • 待处理的操作
    • 正在运行的节点

备份集群配置

借助 Backup for GKE 功能,您可以定期备份整个 GKE 集群的配置,包括已部署的工作负载及其数据。

在本教程中,您将为 GKE 集群配置备份方案,以在每天凌晨 3 点对所有工作负载(包括 Secret 和卷)执行备份。为确保高效存储管理,三天前的备份会被自动删除。

如需配置备份方案,请按照以下步骤操作:

  1. 为集群启用 Backup for GKE 功能:

    gcloud container clusters update ${KUBERNETES_CLUSTER_PREFIX}-cluster \
    --project=${PROJECT_ID} \
    --location=${REGION} \
    --update-addons=BackupRestore=ENABLED
    
  2. 为集群中的所有命名空间创建具有每日时间表的备份方案:

    gcloud beta container backup-restore backup-plans create ${KUBERNETES_CLUSTER_PREFIX}-cluster-backup \
    --project=${PROJECT_ID} \
    --location=${REGION} \
    --cluster="projects/${PROJECT_ID}/locations/${REGION}/clusters/${KUBERNETES_CLUSTER_PREFIX}-cluster" \
    --all-namespaces \
    --include-secrets \
    --include-volume-data \
    --cron-schedule="0 3 * * *" \
    --backup-retain-days=3
    

    该命令在运行时会使用相关的环境变量。

    集群名称的格式取决于您的项目和区域,如下所示:

    projects/PROJECT_ID/locations/REGION/clusters/CLUSTER_NAME
    

    出现提示时,请输入 y.。输出类似于以下内容:

    Create request issued for: [qdrant-cluster-backup]
    Waiting for operation [projects/PROJECT_ID/locations/us-central1/operations/operation-1706528750815-610142ffdc9ac-71be4a05-f61c99fc] to complete...⠹
    

    此操作可能需要几分钟才能成功完成。执行完成后,输出类似于以下内容:

    Created backup plan [qdrant-cluster-backup].
    
  3. 您可以看到 Backup for GKE 控制台中列出新创建的备份方案 qdrant-cluster-backup

    前往 Backup for GKE

如果您要恢复已保存的备份配置,请参阅恢复备份