Skip to main content

Kubernetes deployment

When to use

Use the Kubernetes backend when you need multi-node, production-grade deployments. In this mode the manager process runs as a single pod inside your cluster and spawns Quack node pods on demand via the Kubernetes API. Each pool's nodes are independent pods, so they scale and fail independently of the manager.

For single-machine development and testing, use the local backend (runtimeType=local) instead.

Configure the backend

Set quack-on-demand.runtimeType=kubernetes (or QOD_RUNTIME_TYPE=kubernetes) to activate the Kubernetes backend. All k8s.* keys are overridable via environment variables.

KeyEnv varDefaultDescription
k8s.namespaceQOD_K8S_NAMESPACEdefaultKubernetes namespace where node pods and services are created.
k8s.imageQOD_K8S_IMAGEstarlakeai/quack-on-demand-node:latest-snapshotContainer image used for Quack node pods.
k8s.serviceAccountQOD_K8S_SERVICE_ACCOUNT(unset)Service account name injected into node pods. Omit to use the namespace default.
k8s.serviceTypeQOD_K8S_SERVICE_TYPEClusterIPKubernetes Service type for per-node Services.
k8s.quackPortQOD_K8S_QUACK_PORT8080Port the Quack HTTP server listens on inside each node pod.
k8s.startupTimeoutSecQOD_K8S_STARTUP_TIMEOUT_SEC120Seconds the manager waits for a new node pod to reach Running phase before aborting.
k8s.podLabelQOD_K8S_POD_LABELmanaged-by=quack-on-demandLabel (key=value) applied to every manager-owned pod and Service, used for discovery.

See /reference/configuration for the full list of configuration keys.

How nodes run

The manager creates one Pod and one Service per node. The Service selector pins to a single pod by quack-node-id so traffic never fans out across multiple pods.

Every pod receives the following labels:

LabelPurpose
managed-byMatches the podLabel value (default quack-on-demand); scopes discovery to manager-owned pods.
quack-tenantTenant identifier for the pool this node belongs to.
quack-tenant-dbTenant-database identifier.
quack-poolPool name.
quack-roleNode role: WriteOnly, ReadOnly, or Dual.
quack-node-idUnique node identifier; used as the pod name and the Service name.
quack-max-concurrentMaximum concurrent queries this node accepts.

On manager restart, the discoverExisting pass lists all pods matching the podLabel and reconstructs the in-memory node registry from these labels. Note that the per-node auth token is held only in memory, so rediscovered pods come back with an empty token until the manager reconnects. A follow-up will persist tokens in Kubernetes Secrets.

Object-store credentials

The manager forwards object-store credentials from its own environment into every spawned node pod. This mirrors what the local backend receives for free through process environment inheritance.

The following variables are forwarded when present on the manager pod:

S3-compatible (AWS S3, MinIO, SeaweedFS, R2, etc.)

VariablePurpose
QOD_S3_ENDPOINTS3 endpoint URL.
QOD_S3_ACCESS_KEY_IDAccess key.
QOD_S3_SECRET_ACCESS_KEYSecret key.
QOD_S3_REGIONRegion name.
QOD_S3_URL_STYLEpath or vhost.
QOD_S3_USE_SSLtrue or false.

Azure Blob Storage

VariablePurpose
QOD_AZURE_CONNECTION_STRINGAzure Storage connection string.

Google Cloud Storage

VariablePurpose
QOD_GCS_KEY_IDGCS HMAC key ID.
QOD_GCS_SECRETGCS HMAC secret.

Variables that are already set explicitly in defaultMetastore (via pool or global configuration) are not overridden by forwarding.

Helm chart

A Helm chart is provided at charts/quack-on-demand/. It deploys the manager pod, the two Services (REST/UI on port 20900 and FlightSQL on port 31338), and the RBAC Role + RoleBinding that lets the manager call the Kubernetes API to create, watch, and delete node pods and services within its own namespace.

Top-level keys in values.yaml:

KeyDescription
imageManager container image repository, tag, and pull policy.
replicaCountNumber of manager replicas. Keep at 1 until leader election is supported.
nameOverride / fullnameOverrideOverride rendered resource names.
serviceAccountService account creation and annotations for the manager pod.
rbacControls creation of the Role and RoleBinding for Kubernetes API access.
podAnnotations / podLabelsExtra annotations and labels on the manager pod.
podSecurityContext / securityContextPod- and container-level security contexts.
resourcesCPU and memory requests/limits for the manager container.
nodeSelector / tolerations / affinityManager pod scheduling constraints.
priorityClassNamePriority class for the manager pod.
terminationGracePeriodSecondsGrace period (default 60 s) to allow in-flight FlightSQL statements to finish.
serviceServices for the REST/UI listener (rest) and the FlightSQL edge (flightsql), each with type, port, and annotations.
ingressIngress for the REST/UI; FlightSQL (gRPC) is not covered here.
probesLiveness and readiness probe tuning.
serviceMonitorPrometheus Operator ServiceMonitor toggle.
pdbPodDisruptionBudget (only useful when replicaCount > 1).
postgresExternal Postgres connection details and secret references.
quackNodeImage for the Quack node pods the manager spawns, and TLS toggle for node-to-manager traffic.
storagedataPath for the DuckLake catalog parquet files.
s3S3-compatible object-store credentials forwarded to node pods, with inline or existing-Secret options.
adminInitial admin credentials seeded at startup.
apiKeyOptional static API key for the /api/* admin endpoints.
flightsqlFlightSQL TLS configuration (auto-generated cert by default).
authOIDC provider configuration (Keycloak off by default).
metricsMetrics sink selection (prometheus, aws, azure, gcp, or none).
bootstrapIdempotent startup bootstrap for a starter tenant and pool.
envArbitrary extra environment variables passed to the manager pod.
extraVolumes / extraVolumeMountsAdditional volumes and mounts (for cert secrets, custom config, etc.).
imagePullSecretsImage pull secrets for private registries.

Node placement

Per-pool node placement using cohorts (nodeSelector and tolerations) is supported on the Kubernetes backend and is documented in the Pools guide.