Fleet

Docker

One command to try it: a server, a node, the console and a sample plugin in one container. And a compose file for a small team: PostgreSQL, a server and a node.

For: cluster operators.

Use the supplied Compose layout to start the deployment. Preserve its keys and data volumes when replacing containers.

Two ways to run Orchestrator Zero with Docker, both from images you build locally (no official images are published yet):

  • The quickstart, one container with a dev server, the console, a node and a sample plugin, to try it.
  • Compose, for a small team on one machine: PostgreSQL, one server in cluster mode and one node, each in its own container with its own volume. More nodes join from other machines.

Try it in one command

Building the image currently requires access to the private repository. Public source downloads and official images are coming soon. Build the image once, from your checkout:

Terminal
make image-quickstart        # orchestrator-zero:quickstart, built locally and never pushed

and run it:

Terminal
docker run --rm -p 8443:8443 orchestrator-zero:quickstart

It starts a dev server, joins a node to it, installs the sample plugin from examples/greeter, runs a first job, and prints where to sign in:

  Orchestrator Zero is running.

    Web UI    https://localhost:8443
    User      admin
    Password  lZDqnGomjNqVdXWNxiW6sZVr

  The certificate comes from the cluster's own CA, so the browser asks you to accept it once.
  A first job ran on the node: "Hello, quickstart! (from 1f0c2a7e9b3d)"

Everything the node needs is in the image: uv, Python, the runtime and the sample plugin's packages. The container starts in about 15 seconds and needs no network. The CLI is in the container too:

Terminal
docker exec -it <container> oz0 node list
docker exec -it <container> oz0 job run --task-queue oz0.default --workflow HelloWorkflow --input '"you"'

The container's data, the dev cluster with its keys, lives in /var/lib/oz0. To keep it when the container goes, give it a named volume, which Docker fills with what the image holds there the first time:

Terminal
docker run -d --name oz0 -p 8443:8443 -v oz0-quickstart:/var/lib/oz0 orchestrator-zero:quickstart

The quickstart is a dev server on SQLite with its node in the same container: for trying, demos and plugin development on one machine, not for a team's work or nodes on other machines. For those, use compose.

Compose for a small team

deploy/compose/compose.yaml runs a cluster with one server:

ServiceWhat
postgresPostgreSQL 16, its data in the volume postgres; healthy when it takes connections over TCP, so not during the first start's temporary server
initruns once per up: makes the master key and the admin's password in the volume secrets the first time, then server init --exist-ok, which creates the cluster once and afterwards checks that the key still unseals it
serverserver start in cluster mode: management, the edge and Temporal; healthy when its edge is ready (oz0 server healthcheck). Its erasure ledger is in the volume ledger, apart from the database
tokenruns once per up: a join token for one use, while the node has not joined
nodejoins once with that token, then keeps its identity, uv, Python and runtime in the volume node

Build the images and set a password for PostgreSQL:

Terminal
make images IMAGE_TAG=local
cp deploy/compose/.env.example deploy/compose/.env
sed -i "s/^OZ0_POSTGRES_PASSWORD=.*/OZ0_POSTGRES_PASSWORD=$(openssl rand -hex 24)/" deploy/compose/.env

Start it, and read the admin's password:

Terminal
docker compose -f deploy/compose/compose.yaml up -d --wait
docker compose -f deploy/compose/compose.yaml exec server cat /oz0/secrets/admin-password

Sign in at https://<this machine>:8443 as admin. The CLI works from the server's container with the operator credentials init made:

Terminal
docker compose -f deploy/compose/compose.yaml exec -e OZ0_CONTEXT=/oz0/secrets/operator/context.json server oz0 node list

Back up the master key now and keep it somewhere else: without it the cluster's CAs and secrets cannot be unsealed. Backups of the database need it too.

Terminal
docker compose -f deploy/compose/compose.yaml cp server:/oz0/secrets/master.key ./oz0-master.key

.env holds the settings: OZ0_TAG (the images' tag), OZ0_POSTGRES_PASSWORD, OZ0_CLUSTER_NAME, OZ0_HISTORY_SHARDS (64; it can never change), OZ0_PUBLIC_HOST (the name other machines reach this one at, for the server's certificate), OZ0_PUBLISH_IP and the three ports, and OZ0_NODE_NAME.

docker compose down and up again keep everything: init finds the cluster, and the node comes back as itself without joining again. down -v removes the volumes, and with them the cluster. Back up the volume ledger apart from the database: a restore of an older backup applies again the erasures it records.

More nodes

Nodes on other machines join the edge on ports 7443 and 7233 with the console's Add nodes command, and run there as services. Set OZ0_PUBLIC_HOST to the name they reach this machine at, and restart the server (docker compose up -d), so that its certificate names it.

The command in the console names the server's address inside Docker's network (such as https://172.18.0.3:7443), which other machines cannot reach: replace it, both times it appears, with https://<OZ0_PUBLIC_HOST>:<OZ0_EDGE_API_PORT>. The node keeps using the address it joined through, and reaches Temporal at the same host on port 7233, the port the edge reports: for nodes on other machines, keep OZ0_EDGE_TEMPORAL_PORT at 7233.

When the team grows

Compose runs one server on one machine. For two or more servers, an external PostgreSQL and backups on a schedule, use the Helm chart or run the servers yourself.

Copyright © 2026