# tidalDB standalone server as a StatefulSet. # # WHY A STATEFULSET (not a Deployment): tidalDB is single-node-first and # embeddable — the server wraps ONE engine instance whose state (WAL + # checkpoints + indexes) lives on a durable data dir. It scales VERTICALLY # (bigger node), not by adding replicas. `replicas: 1` is intentional and load- # bearing: there is no shared-storage multi-writer mode. The experimental # multi-region `cluster` subcommand runs every region in ONE process (no host # isolation — NOT production HA, tracked as m8p10), so it does not change this. # See docs/runbooks/kubernetes.md and docs/runbooks/cluster.md. apiVersion: apps/v1 kind: StatefulSet metadata: name: tidaldb namespace: tidaldb labels: app.kubernetes.io/name: tidaldb app.kubernetes.io/component: server spec: serviceName: tidaldb # the headless Service in service.yaml — stable network id replicas: 1 # single-node-first: scale up, not out (see header) selector: matchLabels: app.kubernetes.io/name: tidaldb template: metadata: labels: app.kubernetes.io/name: tidaldb app.kubernetes.io/component: server annotations: # Plain-Prometheus scrape hints (the PodMonitor/ServiceMonitor in # servicemonitor.yaml is the Operator-native alternative). Metrics are # unauthenticated — keep :9091 cluster-internal (see ops/monitoring.md). prometheus.io/scrape: "true" prometheus.io/port: "9091" prometheus.io/path: "/metrics" spec: # SIGTERM flips readiness to 503 (pod leaves Endpoints), drains in-flight # requests, then checkpoints + fsyncs the WAL before exit. Give that room. terminationGracePeriodSeconds: 60 securityContext: runAsNonRoot: true runAsUser: 10001 # the `tidal` user baked into docker/deploy/Dockerfile runAsGroup: 10001 fsGroup: 10001 # makes the mounted PVC group-writable by the runtime user seccompProfile: type: RuntimeDefault containers: - name: tidaldb # For a real cluster, replace with your registry image pinned by digest # (e.g. registry.example.com/tidaldb@sha256:...) and set # imagePullPolicy: IfNotPresent. `tidaldb:deploy` is the local image # built from docker/deploy/Dockerfile and loaded via `kind load`. image: tidaldb:deploy imagePullPolicy: IfNotPresent # ENTRYPOINT is the bare binary; these args override the image CMD so # the schema comes from the mounted ConfigMap, not the baked default. args: - standalone - --listen - 0.0.0.0:9400 - --schema - /etc/tidaldb/schema/schema.yaml - --data-dir - /data - --metrics - 0.0.0.0:9091 env: - name: TIDAL_API_KEY valueFrom: secretKeyRef: name: tidaldb-api-key key: api-key - name: TIDAL_SERVER_LOG value: info ports: - name: http containerPort: 9400 - name: metrics containerPort: 9091 # Three distinct probes map to the three health endpoints: # - /health/startup : always 200 once the HTTP listener is up # - /health/live : always 200 while the process is alive # - /health : 200 ready / 503 while draining on SIGTERM # All are unauthenticated by design, so the probes need no token. startupProbe: httpGet: path: /health/startup port: http periodSeconds: 5 failureThreshold: 60 # up to ~5 min for large-DB WAL replay / index load (capacity-planning.md) livenessProbe: httpGet: path: /health/live port: http periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 readinessProbe: httpGet: path: /health # 503 during drain -> removed from Service Endpoints port: http periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 resources: requests: cpu: "250m" memory: 256Mi limits: cpu: "2" memory: 2Gi # size from docs/ops/capacity-planning.md for your item/embedding count securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true # the server only writes /data (PVC) and /tmp (emptyDir) capabilities: drop: ["ALL"] volumeMounts: - name: data mountPath: /data - name: schema mountPath: /etc/tidaldb/schema readOnly: true - name: tmp mountPath: /tmp volumes: - name: schema configMap: name: tidaldb-schema - name: tmp emptyDir: {} volumeClaimTemplates: - metadata: name: data labels: app.kubernetes.io/name: tidaldb spec: accessModes: ["ReadWriteOnce"] # storageClassName: "" # uncomment + set to pin a class; omitted = cluster default resources: requests: storage: 10Gi