Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Running a cluster

A QdrantCluster describes one Helm release of the qdrant chart. This chapter walks the spec top to bottom; the reference has every field with its default, and Helm values the operator renders shows what each field becomes.

Version and image

spec:
  version: v1.16.3
  image:
    repository: docker.io/qdrant/qdrant
    pullPolicy: IfNotPresent

version is required and pins both the Qdrant image tag and the chart version: the operator passes it, without the leading v, as --version to Helm and lets the chart's appVersion pick the image tag. The chart and Qdrant release in lockstep, so every Qdrant release has a chart of the same number. image.repository points at a mirror; the tag always follows version.

Replicas and distributed mode

spec:
  replicas: 3
  cluster:
    enabled: true
    p2p:
      port: 6335
      enableTls: false

cluster.enabled defaults to true, and the API server rejects replicas > 1 with cluster.enabled: false, because a multi-pod StatefulSet of stand-alone nodes would not form a cluster. Scaling up adds pods that join through the p2p port. Scaling down is the chart's business; Qdrant does not move shards off a node by itself, so drain a node's shards before you lower replicas.

Persistence

spec:
  persistence:
    size: 50Gi
    storageClassName: fast-ssd
    accessModes: [ReadWriteOnce]
  snapshotPersistence:
    enabled: true
    size: 50Gi

Each pod gets a PersistentVolumeClaim from the StatefulSet's claim template. persistence.size and storageClassName are immutable after creation and the API server rejects the update naming the field. To grow a volume, expand the PVCs directly if the storage class allows it.

snapshotPersistence gives each pod a second volume for the snapshots Qdrant writes before the operator streams them out. Without it, snapshots are written to the data volume, so leave headroom equal to your largest collection's shards on a node, or turn this on. Like persistence, it becomes a volume claim template and cannot be changed on an existing cluster; the API server does not reject the change, Helm does.

Resources and scheduling

spec:
  resources:
    requests: {cpu: "2", memory: 8Gi}
    limits: {cpu: "4", memory: 8Gi}
  nodeSelector:
    workload: vector-search
  tolerations:
    - {key: dedicated, operator: Equal, value: qdrant, effect: NoSchedule}
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - topologyKey: kubernetes.io/hostname
          labelSelector:
            matchLabels: {app.kubernetes.io/name: qdrant}

resources, nodeSelector, tolerations and affinity pass straight through to the chart. Qdrant holds its HNSW graphs in memory, so memory requests should track the indexed vectors; the chart sets no default requests.

Service

spec:
  service:
    type: LoadBalancer
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-type: nlb

The chart creates a Service named qdrant-<name> with the HTTP port 6333, the gRPC port 6334 and, in distributed mode, the p2p port. A headless Service qdrant-<name>-headless gives each pod a stable DNS name; the operator uses it to reach individual nodes for snapshots. status.endpoint holds the in-cluster HTTP URL of the client Service.

Metrics

spec:
  metrics:
    enabled: true
    serviceMonitor:
      enabled: true
      interval: 15s
      labels: {release: kube-prometheus-stack}

Qdrant always serves /metrics. What metrics controls is the ServiceMonitor the chart renders for the Prometheus operator: it is created only when both metrics.enabled and serviceMonitor.enabled are true, and the monitoring.coreos.com CRDs must exist on the cluster or the Helm release fails.

Extra chart configuration

spec:
  config:
    storage:
      performance:
        optimizer_cpu_budget: 2
    log_level: INFO

config is merged into the chart's config value, which becomes Qdrant's config/production.yaml. The operator writes cluster.enabled, the p2p settings, service.enable_tls and the TLS certificate paths into the same map first, and your config wins on conflicts. Anything Qdrant's configuration file accepts goes here.

Status and phases

PhaseMeaning
PendingFirst Helm install applied, StatefulSet not yet fully ready
UpgradingSpec changed on an existing release, rollout in progress
RunningreadyReplicas equals replicas

The Progressing condition turns True with reason HelmReleaseApplied whenever the operator applies the release and False with RolloutComplete once the StatefulSet is ready. The Ready condition reports AllReplicasReady or ReplicasNotReady with the ready count in its message. The operator re-reads the StatefulSet every thirty seconds.

Deleting

Deleting a QdrantCluster runs helm uninstall --wait on its release. The chart's PersistentVolumeClaims stay behind, as StatefulSet claims do; delete them yourself once you are sure. Backups referencing the cluster keep their data in the bucket.