Configuration

Use this page for the common choices. The generated API Reference is the source for every field, default, validation, and status property.

Object storage

QuestDBObjectStore is namespaced configuration for an existing S3 bucket or Azure Blob container. It has no controller. The operator never creates, lists, reads, or deletes objects and needs no cloud permissions; QuestDB pods perform all object-store I/O.

apiVersion: questdb.io/v1alpha1
kind: QuestDBObjectStore
metadata:
name: questdb-store
spec:
provider: S3
s3:
bucket: my-questdb-bucket
region: eu-west-1
# Omit for pod ambient identity, such as EKS IRSA.
credentialsSecret:
name: s3-credentials
apiVersion: questdb.io/v1alpha1
kind: QuestDBObjectStore
metadata:
name: questdb-store
spec:
provider: Azure
azure:
accountName: mystorageaccount
container: questdb
credentialsSecret:
name: azure-credentials

Static credential Secrets use these keys:

ProviderKeys
S3AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, optional AWS_SESSION_TOKEN
AzureAZURE_STORAGE_KEY

The store, credentials Secret, and consuming cluster must be in the same namespace. Prefer one cloud identity and least-privilege policy per tenant or cluster. On EKS, IRSA is attached to the tenant namespace's default ServiceAccount; it is for QuestDB pod S3 access, not image pulls.

Prefix isolation

QuestDB has no instance-name key in object storage, so prefixes are its isolation boundary:

  • spec.backup.root defaults to backup/. Give each cluster a distinct backup root when clusters share a bucket or container.
  • spec.replication.root defaults to the identity-scoped db/<namespace>/<cluster>/. Leave it unset unless deliberately adopting an existing WAL stream.

A provider-level root on QuestDBObjectStore does not add a base prefix; the per-use backup or replication root overrides it. Scope cloud permissions to the effective per-use prefixes.

Backup and HA

Backups run inside QuestDB Enterprise on the primary. Enabling backup requires objectStoreRef and a schedule:

spec:
objectStoreRef:
name: questdb-store
backup:
enabled: true
schedule: "0 * * * *"
# timezone: UTC # default
# retention: 5 # default
# root: backup/ # default

spec.backup absent means no backup. Watch BackupHealthy and status.backup.lastBackup; configuration alone is not proof that an object was written.

For HA, set instances above 1 only after a successful seed backup. HA requires objectStoreRef, enabled scheduled backup, a completed backup, and instances > 1. spec.replication is optional: omit it for the identity-scoped WAL root, default WAL cleaner, no seed pin, and no lag gate. Add it only for tuning:

spec:
instances: 3
replication:
maxLagTxns: 1000

The operator creates <name>-rw for the current primary. For store-backed replication it also creates <name>-ro for read-eligible replicas; when none are eligible, <name>-ro falls back to the primary. Use the database operations and high-availability runbooks for routing and failover.

The WAL cleaner is enabled by default. Do not disable it unless another process owns replication-WAL retention; otherwise WAL grows without bound.

Storage

Each instance receives its own persistent volume:

spec:
storage:
storageClassName: gp3
size: 100Gi
pvcRetentionPolicy: Retain

Use a CSI StorageClass with ReadWriteOnce, fsGroup support, and allowVolumeExpansion: true. Do not use ReadWriteOncePod: supported cloud CSI drivers do not apply the required non-root ownership in that mode. Size may only increase. pvcRetentionPolicy defaults to Retain for removed replica PVCs; Delete reclaims them. The primary PVC is never deleted by scale-down.

Resources and private images

Set a firm memory budget with equal request and limit. A CPU limit is optional:

spec:
image: registry.distribution.questdb.io/questdb:3.3.4-enterprise
imagePullSecrets:
- name: questdb-registry
resources:
requests:
cpu: "1"
memory: 4Gi
limits:
memory: 4Gi

spec.imagePullSecrets names Secrets in the tenant namespace for database pods. It is separate from the Helm value controllerManager.imagePullSecrets, which applies only to the operator image in questdb-operator-system. On EKS, worker-node IAM can provide ambient ECR pull access; IRSA cannot.

Scheduling and disruption budgets

spec.scheduling supports node selectors, affinity, tolerations, topology spread, priority class, and an operator-managed PodDisruptionBudget (PDB). Without an override, pods get soft hostname anti-affinity, soft zone spread, and a PDB with minAvailable: 1 for one instance or instances-1 for HA.

The single-instance default intentionally blocks voluntary eviction. Before a node drain, scale out, lower spec.scheduling.podDisruptionBudget.minAvailable, or disable the PDB after accepting the availability risk. Follow the node maintenance runbook. Custom affinity or topology spread replaces the corresponding default rather than merging with it.

Wire protocols

spec.protocols opts a cluster into the wire protocols that are not served by default. Omit it and the defaults apply.

spec:
protocols:
qwp:
udp:
enabled: true
FieldDefaultEffect
spec.protocols.qwp.udp.enabledfalseServes the QWP UDP receiver on 9007/UDP.

Enabling it opens 9007/UDP on the pod and publishes it on <name> and <name>-rw. It is deliberately not published on <name>-ro: QWP UDP is ingest-only, so a datagram aimed at a replica is discarded, and because the transport is fire-and-forget nothing is returned to say so.

Two properties are worth knowing before you enable it:

  • The receiver is unauthenticated. QWP authenticates on the WebSocket upgrade request, and UDP has no upgrade, so anything that can reach 9007 can write. Restrict it with a NetworkPolicy.
  • Delivery is fire-and-forget. It neither acknowledges writes nor applies backpressure, and is intended for metrics workloads where occasional message loss is acceptable. Use the WebSocket transport for reliable ingestion.

It requires an engine that ships the QWP UDP receiver; QuestDB Enterprise 3.3.4 and later do. The operator writes the qwp.udp.* keys only while the receiver is enabled, so a cluster that leaves it off carries no trace of it.

There is no setting for QWP over WebSocket. Ingestion (/write/v4) and streaming query results (/read/v1) are served by the HTTP server on port 9000 and share its network settings, so they are available on every cluster.

Changing spec.protocols rolls the affected pods.

Extra engine options

spec.config passes server.conf key/value strings to QuestDB. Operator-owned authentication, role, snapshot identity, health-auth, and TLS keys are rejected. Object-store keys are not rejected, but operator-provided primary backup.object.store and replication.object.store settings use the engine's _FILE mechanism and take precedence.

Never put access keys, passwords, or credential-bearing connection strings in spec.config: the custom resource and rendered ConfigMap are plaintext. Additional backup destinations (backup.object.store.1 through .9) and cold.storage.object.store are suitable only for credential-free, ambient-identity settings until a Secret-backed mechanism is available.

The qwp.udp.* receiver keys are also operator-owned: qwp.udp.enabled and qwp.udp.bind.to are set through spec.protocols.qwp.udp, and qwp.udp.unicast and qwp.udp.join are rejected because multicast cannot be reached through the unicast ClusterIP the operator publishes. The remaining qwp.udp.* tuning keys — commit interval, buffer sizes, thread affinity — stay available.

Use spec.replication.config for supported replication tuning. Values cannot contain line separators. It rejects the same operator-owned QWP keys as spec.config: both maps are merged into one server.conf, so a key owned in only one of them would not be owned at all.

Changes and immutable fields

Changes to the image, resources, engine configuration, wire protocols, image pull Secrets, or pod scheduling roll affected pods. A primary roll remains single-writer-safe but briefly interrupts writes. Plan these as disruptive changes; do not combine an unrelated credential rotation with routine reconciliation.

Important immutable choices include:

  • spec.objectStoreRef once set;
  • spec.storage.storageClassName;
  • spec.bootstrap in presence and value;
  • spec.replication.root in presence and value; and
  • QuestDBObjectStore.spec.provider.

Storage size is expand-only. For exact transition rules and less common fields, use the generated API Reference rather than copying the full schema from this guide.