Skip to content

ZeptoDB Docker Deployment Guide

Single Docker image for all roles: master, data node, flight server, CLI.

Image: zeptodb/zeptodb:0.1.8 Size: ~300MB (distroless runtime) Base: gcr.io/distroless/cc-debian12:nonroot Platforms: linux/amd64, linux/arm64


Terminal window
# Create one bootstrap admin key and its hash-only server key store.
mkdir -m 0700 -p auth
umask 077
export ZEPTO_ADMIN_KEY="zepto_$(openssl rand -hex 32)"
KEY_HASH="$(printf '%s' "$ZEPTO_ADMIN_KEY" | sha256sum | cut -d' ' -f1)"
printf '# zeptodb-keys-v1\nak_docker|docker-bootstrap-admin|%s|admin||1|0|||0\n' \
"$KEY_HASH" > auth/api_keys.txt
# The distroless container runs as UID 65532. The mounted file contains only a
# one-way hash; make it readable while the parent directory remains private.
chmod 0444 auth/api_keys.txt
# Bind to loopback and mount the key store read-only.
docker run --rm -p 127.0.0.1:8123:8123 \
-v "$PWD/auth/api_keys.txt:/run/secrets/zeptodb-auth/api_keys.txt:ro" \
zeptodb/zeptodb:0.1.8
# Query via curl
curl -H "Authorization: Bearer $ZEPTO_ADMIN_KEY" \
-X POST http://localhost:8123/ -d "SELECT 1+1 AS result"

The production image does not create development credentials. Without a mounted key store it remains fail-closed. --no-auth is available only as an explicit isolated development/benchmark override. HTTP is plaintext unless the server is configured with TLS or placed behind a TLS-terminating proxy; do not publish the default port directly to the internet.

The image explicitly permits plaintext only inside the container boundary and marks session cookies Secure. Put the Web UI behind HTTPS; Bearer-key curl requests over a loopback-only Docker port remain suitable for initial checks.

The mounted file is intentionally read-only. Rotate keys by replacing the file from a secrets manager and restarting the container. Deployments that need runtime /admin/keys mutations must use a writable/Vault-backed store.


BinaryRoleDefault Port
zepto_http_serverMaster node — HTTP API, SQL engine, Web UI8123
zepto_data_nodeData node — partition storage, RPC server9000+
zepto_flight_serverArrow Flight — gRPC streaming8815
zepto-cliInteractive SQL REPL
Terminal window
# Master node (default)
docker run --rm -p 127.0.0.1:8123:8123 \
-v "$PWD/auth/api_keys.txt:/run/secrets/zeptodb-auth/api_keys.txt:ro" \
zeptodb/zeptodb:0.1.8
# Data node (requires a cluster secret; see the Compose example below)
docker run --rm \
--entrypoint ./zepto_data_node \
-e ZEPTO_CLUSTER_SECRET_FILE=/run/secrets/cluster-secret \
-v "$PWD/auth/cluster-secret:/run/secrets/cluster-secret:ro" \
zeptodb/zeptodb:0.1.8 9000
# Arrow Flight server (production TLS + API-key authentication)
docker run --rm -p 8815:8815 \
--entrypoint ./zepto_flight_server \
-v "$PWD/tls:/run/zeptodb/tls:ro" \
-v "$PWD/auth/api_keys.txt:/run/zeptodb/api_keys.txt:ro" \
zeptodb/zeptodb:0.1.8 \
--flight-host 0.0.0.0 \
--flight-port 8815 \
--tls-cert /run/zeptodb/tls/server.crt \
--tls-key /run/zeptodb/tls/server.key \
--api-keys-file /run/zeptodb/api_keys.txt
# CLI (interactive)
docker run -it --entrypoint ./zepto-cli zeptodb/zeptodb:0.1.8

FeatureStatusNotes
Highway SIMDVectorized scan/aggregation
LLVM JITRuntime query compilation
OpenSSL / TLS / JWT--tls-cert, --jwt-issuer to activate
AWS S3AWS_ACCESS_KEY_ID env var to activate
Arrow FlightLoopback-safe default; TLS required for external bind
ParquetHDB flush to Parquet files
LZ4 compressionWAL and HDB compression
io_uringAsync I/O for HDB reads
HugePagesAuto-detect: uses if available, falls back to regular pages
Web UIServed at /ui/ on master node
FeatureReasonAlternative
UCX / RDMARequires InfiniBand hardware + kernel modulesUse bare-metal deployment
Python bindingRuntime dependency on Python + pybind11pip install zeptodb separately
tcmallocMarginal gain in containersDefault allocator is fine

MetricBare Metal (tuned)DockerGapNotes
Tick-to-trade latency< 1μs3–8μs3–8xContainer syscall overhead + no CPU isolation
Ingest throughput50M+ msg/s20–35M msg/s~2xNo NUMA pinning, shared scheduler
Query (1M rows scan)~200μs~250μs~25%Minimal overhead for compute-bound
Query (aggregation)~50μs~60μs~20%SIMD/JIT identical
Tail latency (p99)< 5μs20–100μs10–20xKernel scheduler jitter
Network (RDMA)< 2μsN/ARDMA not available in containers
FeatureBare MetalDocker
CPU pinning (isolcpus, taskset)✅ Full control⚠️ --cpuset-cpus only
NUMA bindingnumactl --membind⚠️ --cpuset-mems only
HugePages (2MB/1GB)✅ Kernel-level config⚠️ Host must pre-allocate
RDMA / InfiniBand✅ Native❌ Not supported
io_uring✅ Native✅ Works (kernel 5.10+)
Kernel bypass (DPDK)
nohz_full (tickless)❌ Host-level only
TLS / JWT auth
Arrow Flight
S3 upload
Web UI✅ (separate process)✅ (embedded, /ui/)
Rolling upgradeManual✅ K8s native
Auto-scaling⚠️ K8s node capacity only; ZeptoDB HPA is currently blocked
Deployment speedHoursSeconds
Use CaseRecommendationReason
HFT / market makingBare metalEvery microsecond matters; need RDMA, CPU isolation
Market data feed handlerBare metalConsistent sub-millisecond latency required
Real-time risk / surveillanceBare metal or DockerDepends on latency SLA
Quant research / backtestingDockerCost-effective, easy to spin up/down
Analytics dashboardDockerQuery latency tolerance > 10ms
Development / CIDockerFast iteration, reproducible
Multi-tenant SaaSDocker + K8sIsolation, resource quotas, auto-scaling

The shortened commands below focus on resource flags. Add the read-only API key-store mount from Quick Start to every zepto_http_server container.

Terminal window
# Pin to cores 0-3
docker run --cpuset-cpus="0-3" -p 8123:8123 zeptodb/zeptodb:0.1.8
Terminal window
# Host: allocate HugePages
echo 1024 > /proc/sys/vm/nr_hugepages
# Container: mount hugetlbfs
docker run --shm-size=2g \
-v /dev/hugepages:/dev/hugepages \
-p 8123:8123 zeptodb/zeptodb:0.1.8
Terminal window
docker run --cpuset-cpus="0-15" --cpuset-mems="0" \
-p 8123:8123 zeptodb/zeptodb:0.1.8
Terminal window
docker run -p 127.0.0.1:8123:8123 \
-v "$PWD/auth/api_keys.txt:/run/secrets/zeptodb-auth/api_keys.txt:ro" \
-v /data/zeptodb:/opt/zeptodb/data \
zeptodb/zeptodb:0.1.8 \
--bind 0.0.0.0 --allow-plaintext-http --secure-cookie \
--port 8123 --ticks 0 \
--storage-mode tiered --hdb-dir /opt/zeptodb/data \
--api-keys-file /run/secrets/zeptodb-auth/api_keys.txt \
--no-bootstrap-dev-keys --web-dir /opt/zeptodb/web

Mounting a directory alone does not enable persistence. The --storage-mode tiered --hdb-dir ... arguments connect the process to that mount. Run the host directory with ownership/permissions compatible with the distroless nonroot UID (65532).

This is a tiered-storage evaluation path, not a production durability claim. Hot-partition WAL/recovery and merging HDB rows into general SQL reads remain release blockers; an end-to-end restart query must be proven before relying on the directory as a recoverable database.

Terminal window
docker run -p 8123:8123 \
-e AWS_ACCESS_KEY_ID=<key> \
-e AWS_SECRET_ACCESS_KEY=<secret> \
-e AWS_DEFAULT_REGION=us-east-1 \
zeptodb/zeptodb:0.1.8

Create the API key store as in Quick Start, then create a separate peer secret:

Terminal window
openssl rand -base64 48 > auth/cluster-secret
# The direct-bind example runs as UID 65532; the private parent directory keeps
# this raw peer secret out of other users' path traversal.
chmod 0444 auth/cluster-secret
services:
master:
image: zeptodb/zeptodb:0.1.8
ports:
- "127.0.0.1:8123:8123"
environment:
ZEPTO_CLUSTER_SECRET_FILE: /run/secrets/cluster_secret
secrets:
- api_keys
- cluster_secret
command: >
--bind 0.0.0.0
--allow-plaintext-http
--secure-cookie
--port 8123
--ticks 0
--api-keys-file /run/secrets/api_keys
--no-bootstrap-dev-keys
--web-dir /opt/zeptodb/web
--add-node 1:data1:9000
--add-node 2:data2:9001
data1:
image: zeptodb/zeptodb:0.1.8
entrypoint: ["./zepto_data_node"]
command: ["9000", "--node-id", "1"]
environment:
ZEPTO_CLUSTER_SECRET_FILE: /run/secrets/cluster_secret
secrets:
- cluster_secret
data2:
image: zeptodb/zeptodb:0.1.8
entrypoint: ["./zepto_data_node"]
command: ["9001", "--node-id", "2"]
environment:
ZEPTO_CLUSTER_SECRET_FILE: /run/secrets/cluster_secret
secrets:
- cluster_secret
secrets:
api_keys:
file: ./auth/api_keys.txt
cluster_secret:
file: ./auth/cluster-secret
Terminal window
docker compose up -d
curl -H "Authorization: Bearer $ZEPTO_ADMIN_KEY" \
http://localhost:8123/admin/nodes

The shared secret provides mutual peer authentication and replay resistance; it does not encrypt RPC payloads. Keep the Compose network private. Use an encrypted overlay or a private/VPC network for traffic that crosses hosts.


zepto_flight_server [OPTIONS]
--flight-host HOST Flight bind host (default: 127.0.0.1)
--flight-port PORT Flight port (default: 8815)
--port PORT Alias for --flight-port
--http-port PORT Bundled HTTP/HTTPS port (default: 8123)
--tls-cert PATH PEM certificate for Flight and bundled HTTP
--tls-key PATH PEM private key for Flight and bundled HTTP
--api-keys-file PATH API key store (default: dev_keys.txt)
--no-auth Disable authentication (development only)
--allow-insecure-flight Allow plaintext non-loopback bind (development only)
--ticks N Seed demo rows

The certificate and key must be supplied together. Without TLS, Flight accepts only a loopback bind unless --allow-insecure-flight is explicitly set. Do not use --no-auth or the insecure override in production.

zepto_http_server [OPTIONS]
Server:
--bind HOST HTTP bind host (default: 127.0.0.1)
--allow-plaintext-http Permit non-loopback HTTP behind a trusted TLS proxy
--secure-cookie Mark session cookies Secure for HTTPS clients
--port PORT HTTP API port (default: 8123)
--ticks N Seed synthetic demo rows (production: 0)
--storage-mode MODE pure (memory) or tiered (persistent HDB)
--hdb-dir PATH Persistent HDB directory (implies tiered mode)
--web-dir PATH Web UI static files directory
--api-keys-file PATH API key store
--no-bootstrap-dev-keys Compatibility no-op; production is already fail-closed
--bootstrap-dev-keys Create/print development credentials (development only)
--no-auth Disable authentication (development only)
--log-level LEVEL info|debug|warn|error
Cluster:
--node-id ID Node identifier
--add-node ID:HOST:PORT Add remote data node
--rpc-port PORT RPC port for HA communication
--allow-insecure-cluster Allow unauthenticated RPC (development only)
Cluster RPC authentication is configured with exactly one of
`ZEPTO_CLUSTER_SECRET_FILE` (recommended) or `ZEPTO_CLUSTER_SECRET`. The secret
must contain at least 32 bytes.
HA:
--ha active|standby Enable HA mode
--peer HOST:PORT HA peer address
TLS:
--tls-cert PATH TLS certificate file
--tls-key PATH TLS private key file
JWT / SSO:
--jwt-issuer URL Expected JWT issuer
--jwt-audience AUD Expected JWT audience
--jwt-secret SECRET HS256 shared secret
--jwt-public-key PATH RS256 PEM public key
--jwks-url URL JWKS endpoint (auto-fetch)

IssueCauseFix
File logging bootstrap warningLog directory is read-only or not writableThe server continues with stdout logging; mount a writable log volume only when local rotating files are required
mmap failed, falling backHugePages not available on hostNormal — auto-fallback to regular pages
Port already in useAnother container on same portChange -p mapping
Web UI blank pageBrowser cacheHard refresh (Ctrl+Shift+R)
No Authorization headerAuth enabled by defaultMount the API-key store and send Authorization: Bearer ...; use --no-auth only in isolated development

See also: