TessariDBDocs
  • 0.34.2-betalatest
  • 0.34.1-beta
  • 0.34.0-beta
  • 0.33.4-beta
  • 0.33.3-beta
  • 0.33.2-beta
  • 0.33.1-beta
  • 0.33.0-beta
  • 0.32.0-beta

In a container

The published image, the two ports it opens, every variable it reads, and the one setting that decides whether your store is open to the network.

docker run -d --name tessaridb \
  -p 9080:9080 -p 8000:8000 \
  -v tessaridb-data:/var/lib/tessaridb \
  -e TESSARIDB_INITIAL_USER=owner \
  -e TESSARIDB_INITIAL_PASSWORD='choose-a-real-one' \
  tessaridb/tessaridb

That is a node. It needs no repository access, no toolchain and no C++ compiler, which is what makes it the shortest path to a running store while the engine's repository is still private — see Install for the build from source and what it requires.

The image is tessaridb/tessaridb on Docker Hub.

The one thing to get right

A store with no users is open. It runs anything for anybody who reaches the port, because the first user is what closes it — and nothing types a DEFINE USER into a node that came up unattended. Users explains why the rule is that way round.

So set TESSARIDB_INITIAL_USER and TESSARIDB_INITIAL_PASSWORD on the first start. The node declares that user as a store-wide owner, once, when the store has no users at all, and says so in its log:

INFO  tessaridb::bootstrap declared owner as the store's first user, from TESSARIDB_INITIAL_USER

Every start after that leaves an existing store alone and says that instead — which is the line that distinguishes this did nothing because it was already done from this did nothing and nobody noticed:

INFO  tessaridb::bootstrap this store already has users, so TESSARIDB_INITIAL_USER was not applied

So the pair can stay in a compose file forever. They are not a way to reset a password: once the store is closed the variables do nothing, and a lost owner password is a restore from backup rather than a recovery.

Set only one of the two and the node refuses to start. That is deliberate. The alternative failure is a node that came up open because a variable was misspelled, which looks exactly like a node that came up correctly.

The image ships no default credential on purpose. One would close every store that pulls it with a password the whole internet knows, which is worse than the open store it appears to fix.

The two ports

PortSurfaceWhat speaks it
9080the wire protocolthe tessaridb prompt, the Rust client
8000HTTPanything that speaks JSON, and the web console at /

One process serves both over one store. Either can be turned off by setting its address to the empty string, and both empty is refused rather than started — a node asked to serve nothing would read from standard input, reach end of file and exit, which is indistinguishable from a crash.

Give the node a certificate and both surfaces speak TLS 1.3. Mount the certificate chain and its key — a secret mount, not the store's volume — and point TESSARIDB_TLS_CERT and TESSARIDB_TLS_KEY at them. The node runs as uid 10001 and refuses a key anybody else may read: own the key file by 10001 with mode 600, or leave it root's with mode 440 and the node's group able to read it, which is how a Kubernetes secret with fsGroup arrives. Without them the node — single or in a cluster — serves in the clear and says so when it starts; TESSARIDB_REQUIRE_CLIENT_TLS=1 makes it refuse to start instead. The nodes of a cluster speak mutual TLS to each other either way. Encryption in transit says the rest.

The console is already in there

Open http://localhost:8000 and the web console is there. It is served by the binary — the page, its stylesheet, its two scripts and its icon are all inside the executable, so there is no second image to run beside this one and nothing to keep at the same version as the node. Sign in with the user you declared above; the store is closed, so an anonymous session is refused.

Every variable it reads

VariableDefaultWhat it does
TESSARIDB_STORE/var/lib/tessaridb/storewhere the store lives. Empty is a store held in memory and lost when the container stops
TESSARIDB_ADDRESS0.0.0.0:9080the wire protocol's address. Empty turns it off
TESSARIDB_HTTP_ADDRESS0.0.0.0:8000the HTTP surface's address. Empty turns it off
TESSARIDB_LOGinfoerror, warn, info, debug or trace, or directives such as info,tessari_wire=debug
TESSARIDB_LOG_FORMATunset — textjson writes one object per event for a log collector
TESSARIDB_BACKUP_DIR/var/lib/tessaridb/backupswhere BACKUP … TO '<name>' and the console's Backup tab write, inside the volume so a backup outlives the container. Empty refuses every TO
TESSARIDB_RETAIN_RECORDSunset — the node keeps 100 000how many records of each log a serving node keeps before it prunes the rest; none keeps the whole log. A DEFINE NODE RETAIN stored on the node wins over it (Bounding the log)
TESSARIDB_UNSEAL_FOR10mhow long an unseal lasts before the store seals itself (90s, 1h). Read by the node, so it works outside a container too
TESSARIDB_TLS_CERTunsetthe certificate chain clients are served under, PEM; with the key, every client surface speaks TLS 1.3 (Encryption in transit)
TESSARIDB_TLS_KEYunsetits private key, PEM
TESSARIDB_REQUIRE_CLIENT_TLSunset1 refuses to start without TESSARIDB_TLS_CERT and TESSARIDB_TLS_KEY, for a deployment that forbids the clear; off by default
TESSARIDB_CLIENT_PLAINTEXTunsetretired: the clear is already the default without a certificate; 1 is refused from 0.24.0-beta — drop it
TESSARIDB_ENCRYPTION_KEY_FILEunset32 bytes, mode 600, on a secret mount: the store and every backup it writes are encrypted under it (Encryption at rest)
TESSARIDB_JOIN_TOKENunseta token from CREATE JOIN TOKEN, offered to the seeds by a node joining a cluster
TESSARIDB_INITIAL_USERunsetthe first user, declared once on a store that has none
TESSARIDB_INITIAL_PASSWORDunsetthat user's password. Both or neither
TESSARIDB_PASSWORDunsetthe password for --user, when the image is run as a client
TESSARIDB_TLS_AUTHORITYunsetas a client: speak TLS and trust the node by these certificates, PEM

0.0.0.0 rather than a loopback address, because a container's loopback is reachable from nothing outside it — a node bound there answers no published port, which again looks like a node that failed to start.

The same image is the client

There is one binary, so the image that serves is the image that connects. A prompt against a running node needs nothing installed:

docker run --rm -it --network host \
  -e TESSARIDB_PASSWORD='choose-a-real-one' \
  tessaridb/tessaridb --at 127.0.0.1:9080 --user owner

Anything that is not the word serve is passed straight to the binary, so --version, --help, -e '…', --backup and --verify all work the way the command line describes them.

The store's directory

/var/lib/tessaridb is declared as a volume. The container runs as uid 10001, so a bind mount has to be owned by it:

mkdir -p ./data && sudo chown 10001:10001 ./data
docker run -d -v "$PWD/data:/var/lib/tessaridb" … tessaridb/tessaridb

A named volume needs none of that. A bind mount presents the host's ownership and shadows whatever the image set, so the wrong uid there is a store the node cannot open — reported as a database fault rather than as a permissions one.

Health, and stopping

The image's health check asks the node's own GET /health, which needs no credential precisely so that a supervisor does not have to hold one. When the HTTP surface is turned off it falls back to a connect on the wire port and says so, rather than reporting healthy because nothing was checked. The three probes are described in Serving.

There is no init process in the image. The node installs its own SIGTERM and SIGINT handlers before any surface serves and forks nothing, so it is correct as PID 1 and docker stop reaches it directly: it reports not ready for five seconds, stops accepting, gives in-flight work twenty seconds, and closes the store. A second signal exits at once.

With compose

services:
  tessaridb:
    image: tessaridb/tessaridb:0.34.2-beta
    restart: unless-stopped
    ports:
      - "9080:9080"
      - "8000:8000"
    volumes:
      - tessaridb-data:/var/lib/tessaridb
    environment:
      TESSARIDB_INITIAL_USER: owner
      TESSARIDB_INITIAL_PASSWORD: ${TESSARIDB_OWNER_PASSWORD:?set it}
      TESSARIDB_LOG: info

volumes:
  tessaridb-data:

An environment variable is readable by anything that can inspect the container or the process, which is a smaller circle than a command line but is not a secret store. That is worth knowing rather than discovering.

What is in the image, and what is not

The build is two stages and only the binary crosses between them, so the published image carries no source, no toolchain and no repository:

/usr/local/bin/tessaridbthe node, the client and the shell — about 11 MB
/usr/local/bin/tessaridb-entrypointturns the variables above into the command line
/usr/local/bin/tessaridb-healthcheckthe probe
/usr/share/doc/tessaridb/LICENSEBUSL-1.1, the same text as the repository's
everything elsea debian:bookworm-slim base — about 108 MB in total

No cargo, no rustc, no .rs file and no Cargo.toml reach the finished image.

Tags

TagWhat it is
latestthe most recent build
0.34.2-betathat version, pinned

latest moves. Pin the version tag for anything you would mind losing, and read Backup and restore before you rely on a store surviving a version change — the on-disk format is still moving, and a store written by one pre-release build is not promised to open under the next.

Next

  • Your first store — a table, a record, and a read.
  • Connecting — reaching a node from somewhere else.
  • Serving — the probes, draining, and what a node does on the way down.
  • Users — why the first user is the one that closes the store.