Docs/Deploy & operatev0.0.1-preview

Deployment

Where TulaDB runs — Linux servers with tuladb-installer, plus the Docker, Compose, Helm and Amazon EKS evaluation stacks — and what exists today on AWS and Google Cloud.

On this page
  1. Linux servers: tuladb-installer
  2. Single node with Docker
  3. 3-node cluster with Docker Compose
  4. Native binary
  5. Kubernetes
  6. Amazon EKS (AWS)
  7. On AWS and Google Cloud
  8. Cloud test fleets (AWS and GCP)
  9. Port reference
  10. Verifying an installer by hand
  11. Distribution in this release

Linux servers: tuladb-installer

The way to run TulaDB on a server is tuladb-installer, downloaded from Downloads. It installs a single node or prepares the nodes of a three-voter cluster as a systemd service, on Ubuntu 22.04/24.04, Debian 12 and RHEL 9, x86_64 and arm64. It verifies itself, validates the configuration and generates credentials. Installing the packages by hand is not supported. Install TulaDB covers it end to end.

The stacks below (Docker, Compose, Kubernetes, EKS) package the engine with the dashboard, the SDK REST gateway and monitoring, for evaluation. They are published as the eval bundle on Downloads (installers, the Helm chart, the TulaDB container images as docker load tarballs and a Postman collection), signed and verified like every other download. For the shortest path, see Quick eval with Docker and Postman. The commands below run from that bundle. Every installer in it verifies its own SHA-256 checksum before doing anything, and refuses to run piped from stdin: download-then-run is intentional.

Single node with Docker

The fastest way to a full local stack — engine, dashboard, and SDK REST server. In the evaluation bundle:

sh install.sh

Then open the dashboard at http://localhost:3000; the SDK REST API is on http://localhost:8080, and the engine listens on localhost:7700 (write) and localhost:7800 (query).

The engine runs mTLS even here, so the installer needs openssl on the host. It generates a local CA, the engine’s certificate, and one client certificate each for the REST server and the dashboard (keys 0600 in a 0700 directory under ~/.tuladb/certs); each service gets only its own key, and the CA key is mounted nowhere.

If you only want the engine — to point an SDK or tulactl at — run the image directly. It bundles a single-node demo config as its default command. Load it from the eval release first, docker load -i tuladb-core-x86_64.tar.gz (or -arm64), and set TULADB_IMAGE to the image name it prints (Loaded image: …/tuladb-core:0.0.1-preview):

docker run -d --name tuladb --no-healthcheck --network host \
  -v tuladb_data:/app/data \
  "$TULADB_IMAGE"

The demo config is tuned for a laptop: single node, small WAL footprint, run-tier dedup, and no TLS — which is why it binds 127.0.0.1 inside the container. An engine reachable beyond loopback must run mTLS, so a published port (-p) cannot reach this config; use --network host (Linux, or a recent Docker Desktop with host networking) or docker exec, or use the installer above, which runs the engine with mTLS. To run your own configuration, mount it and pass its path as the container command — an exposed bind then needs the TLS settings from Configuration.

The bare image is read-only to an SDK. The bundled demo config grants no roles, so an anonymous client gets the default unauthenticated_role, read-only: reads work, and every write — creating an account, a transfer — answers ERR_PERMISSION (35). The image carries tulactl beside the engine (docker exec tuladb tulactl …), with the same tools the installer puts in /opt/tuladb. To write from a local SDK, copy the demo config out, add a writable anonymous role (allowed because the demo binds loopback only), and run with it:

docker run --rm --entrypoint cat "$TULADB_IMAGE" /app/docker/tuladb-demo.toml > tuladb-local.toml
echo 'unauthenticated_role = "ledger-operator"' >> tuladb-local.toml

docker run -d --name tuladb --no-healthcheck --network host \
  -v tuladb_data:/app/data -v "$PWD/tuladb-local.toml:/app/config/local.toml:ro" \
  "$TULADB_IMAGE" /app/config/local.toml

For tulactl, use the native binary install, which includes it. Or use the installer stack above, where the gateway and dashboard already hold write-capable client certificates.

3-node cluster with Docker Compose

Three engine nodes under Raft replication, plus Prometheus, Grafana, dashboard, and the SDK REST server. In the evaluation bundle:

sh install-cluster.sh

Dashboard on :3000, Grafana on :3001, Prometheus on :9090, SDK REST on :8080; engine nodes on 127.0.0.1:7701–7703 (write) and 7801–7803 (query). The bundled Grafana credentials are for this local stack only — never reuse them on anything reachable.

Every engine port — client, query, fabric and heartbeat — runs mTLS, with a certificate per node: a node accepts a peer’s fabric connection or heartbeat only from the certificate that names that peer. Anonymous clients are denied; the REST server and dashboard present their own client certificates, granted ledger-operator and nothing more. Reaching the engine ports from the host likewise needs a client certificate signed by the stack’s CA and a matching grant.

Native binary

Use tuladb-installer above. It installs the native engine on Linux as a production service, and on macOS (Apple silicon) as a development install under ~/.tuladb with no service and no root.

Kubernetes

TulaDB runs as a StatefulSet with one persistent volume per pod. The engine chart, charts/tuladb, is available to design partners on request and is not published to a Helm repository, so the path below is relative to your copy of it. (The evaluation bundle carries a different chart, helm/tuladb-platform, which the EKS installer applies: engine cluster plus gateway, dashboard and monitoring.) The engine chart is the source of truth:

helm install tuladb ./charts/tuladb -n tuladb --create-namespace \
  --set replicaCount=3 \
  --set image.tag=0.0.1-preview \
  --set persistence.size=50Gi \
  --set persistence.storageClassName=fast-ssd \
  --set serviceMonitor.enabled=true

The chart encodes the operational rules a Raft cluster needs, so you don’t have to remember them:

  • Odd replica counts (3 or 5). The chart warns on an even count rather than refusing it, so this one is on you. Peers are derived per pod ordinal; node_id is the ordinal plus one.
  • Pods spread across hosts by soft anti-affinity on the hostname. The chart sets no zone spread: to survive a zone loss, add a zone topology spread constraint yourself.
  • podManagementPolicy: Parallel is mandatory. A forming Raft cluster can’t mark any node Ready until a quorum exists, so OrderedReady would deadlock genesis.
  • Readiness gates on the engine’s node_ready signal — “has a leader and is caught up” — not merely “port open”. A PodDisruptionBudget with maxUnavailable: 1 protects quorum during node drains.
  • mTLS is required, at any replica count. The chart fails to render with TLS off, and unless you provide certificates — either your own TLS Secret, or cert-manager integration. There is no insecure fallback: the engine itself refuses to start a pod reachable beyond loopback without mTLS. See Security.
  • Grow by adding learners, then promoting them. A new node becomes promotable only once it holds a verified full copy of the cluster’s data — see Joining a node. Shrinking is a controlled membership reconfiguration — never just lower the replica count.
  • The engine is supervised. A node that detects it applied writes the cluster later truncated stops rather than continue on balances no log backs, and expects to be restarted; the StatefulSet does that. Outside Kubernetes, run tuladbd under systemd or another supervisor.

Amazon EKS (AWS)

A full platform install — 3-node engine cluster, SDK gateway replicas, dashboard, Prometheus, and Grafana. In the evaluation bundle:

bash install-eks.sh

The installer reuses your current kubectl context if it already points at an EKS cluster, or provisions one with eksctl (3 × m5.large by default). It sets up the EBS CSI driver, checks the platform chart’s files against an embedded digest, applies it, and prints the service URLs when everything is Ready. Engine mTLS is mandatory in the platform chart, and the REST server and dashboard each need their own engine client certificate — the chart fails to render without them. The platform chart mounts one certificate into every engine pod, which proves cluster membership but not which node a peer is; per-node peer identity needs a certificate per pod. Load balancers default to internal scheme; an internet-facing endpoint requires an ACM certificate — the chart refuses to expose plaintext to the world.

The installer doesn’t generate any of that key material: the engine certificates, the two client certificates and the storage-encryption key (the chart encrypts the store by default and fails to render without a key). Put them in a values file and pass it as TULADB_VALUES; EKS_REGION, EKS_NODE_COUNT and EKS_NODE_TYPE override the provisioned cluster, and SKIP_INSTALL=1 stops after provisioning. Where no default StorageClass exists, it marks gp2 as the default. The platform chart’s load-balancer settings are AWS-specific (Network Load Balancer, ACM).

On AWS and Google Cloud

What exists for each cloud today — the supported install paths, and where the lake can live:

AWS Google Cloud
Supported install The EKS installer above None yet. There is no GKE installer and no GCP-specific chart setting. The Helm chart is cloud-neutral Kubernetes, but we haven’t documented or tested it on GKE
Iceberg export target S3 Tables, credentials from an IAM role BigLake over GCS, credentials from the service account (ADC)
Dashboard lake query s3tables rest, against BigLake
Installs the exporter or the lake? No No

On both clouds the exporter and the dashboard’s lake connection are yours to deploy and configure: no installer or chart deploys the exporter, creates a bucket or catalog, or sets the dashboard’s lake variables.

Cloud test fleets (AWS and GCP)

Our chaos and soak harness provisions full test fleets on both clouds. It is a test harness, not a deployment path — it uses throwaway networks, short-lived certificates and instances that delete themselves — but it shows what we run TulaDB on:

  • AWS: three Graviton instances with local NVMe (default m8gd.xlarge), one per availability zone of us-east-1, in the default VPC; the WAL and data on XFS partitions of the instance store; a security group open only within the fleet and to the operator’s address. A monitor instance runs Prometheus and Grafana over HTTPS. No exporter runs on the AWS path.
  • Google Cloud: three machines with local SSD (default c4a-standard-4-lssd, Arm; z3 x86 shapes too), one per zone of us-east4, or one per region across three regions; Hyperdisk Balanced boot disks on the newer families; firewall rules open only within the fleet and to the operator. With history retention on, it also creates a GCS bucket, a BigLake catalog over it, a service account with BigLake and object-storage roles, and an exporter VM that writes the lake as that service account.

Both use mutual TLS on every hop, from a certificate authority generated per run, and a load generator on every node. What the runs found is on Chaos and soak testing. The harness ships with source access.

Port reference

Port Role
7700 Write / client protocol (node_addr)
7800 Query — read-only, also serves the analytics export cursor
8700 Raft fabric (node-to-node replication)
9700 Heartbeat
9145 Prometheus metrics exporter — a separate sidecar process that reads the engine’s metrics snapshot; binds 127.0.0.1 unless given --listen

Verifying an installer by hand

Each evaluation-stack installer sits next to its .sha256 sidecar. Check it before running it:

sha256sum -c install.sh.sha256      # Linux
shasum -a 256 -c install.sh.sha256  # macOS

A sidecar from the same place as its script only proves the two match. Once the eval bundle is on Downloads, verify the bundle itself first, against its signed SHA256SUMS, as that page shows. Each installer additionally pins the SHA-256 of the asset manifest it downloads, so a tampered artifact fails closed even if the distribution endpoint itself were compromised. Piping an installer straight from the network (curl … | sh) is refused, because running from stdin would skip the self-check.

Distribution in this release

  • TulaDB server: tuladb-installer, one static binary per platform (Linux x86_64, Linux arm64, macOS arm64), served from downloads.tuladb.com/core/0.0.1-preview/ and listed on Downloads. Each release publishes the installers with SHA256SUMS, a keyless cosign signature from the release workflow at the release tag, and the trusted_root.json to verify it offline. The packages inside are not published separately.
  • Evaluation stacks (Docker and Compose installers, the Helm chart, the EKS installer, the TulaDB container images, the Postman collection): the eval bundle on Downloads. The images are docker load tarballs per architecture, covered by the bundle’s signed SHA256SUMS; they are not pushed to a public registry.
  • SDKs: the sdk download on Downloads, one file per language; not on public package registries in this release.
  • Grafana dashboards: the grafana-dashboards download on Downloads.