The two deployments¶
There are two deployments, and they share nothing — no network, no volume, no secret.
| Semantic deployment | Sandbox | |
|---|---|---|
| Compose project | praxis-semantic |
praxis-sandbox |
| Services | modelstore, cube-api, cubestore |
sandbox |
| Published port | 127.0.0.1:8000 (model store) |
127.0.0.1:8600 |
| Volumes | model (every data model you have — back it up), cubestore |
workspaces |
| Needed for | everything: the model, every query | running Python: chat scripts, file uploads, Flows. Required by onboarding |
| Holds | the warehouse credentials, CUBEJS_API_SECRET |
no credential at all |
Connecting is two steps¶
The portal cannot start a container, so connecting has a step in the middle that you do.
sequenceDiagram
actor You
participant P as Portal
participant D as Docker
You->>P: 1. POST /connection — warehouse type and settings
P->>P: store credentials, mint 3 secrets (no addresses yet)
You->>P: download semantic + sandbox compose files
P-->>You: two docker-compose.yml files, secrets inlined
You->>D: 2. docker compose up -d (each file)
You->>P: 3. PUT /deployment — store_url, sandbox_url
P->>D: check each address answers as the right service, with the right token
P->>P: store only the addresses that passed
- Setup step 1 (or Data → … → Edit connection later). Pick the warehouse type and fill in the form. The portal stores the settings and mints three secrets: Cube's API secret, the model store token and the sandbox token.
- Download both compose files, put each in its own folder, and run
docker compose up -dnext to each. The files are generated each time you download them; nothing is written to disk by the portal. - Paste the two addresses —
http://127.0.0.1:8000andhttp://127.0.0.1:8600by default. Each is checked before it is stored, and a wrong one is refused with a reason (see Troubleshooting).
The same address step is used again if a deployment moves.
Four conditions, not one¶
| Condition | Meaning | Costs a request? |
|---|---|---|
| deployed | a model store address is stored | no |
| onboarded | both addresses are stored, and there is a model | no |
| reachable | something answers at the address, and it is the right service | yes |
| serving | Cube is compiling a model | yes |
None of the checks proves the warehouse password is right. The first thing that connects to the warehouse is the Read tables step.
Warehouses¶
| Type | Required settings |
|---|---|
| Postgres, MySQL, SQL Server, Redshift | CUBEJS_DB_HOST, CUBEJS_DB_NAME, CUBEJS_DB_USER |
| ClickHouse | CUBEJS_DB_HOST |
| Snowflake | CUBEJS_DB_SNOWFLAKE_ACCOUNT, CUBEJS_DB_SNOWFLAKE_WAREHOUSE, CUBEJS_DB_NAME, CUBEJS_DB_USER |
| BigQuery | CUBEJS_DB_BQ_PROJECT_ID, CUBEJS_DB_BQ_CREDENTIALS (a service account key) |
| Databricks (JDBC) | CUBEJS_DB_DATABRICKS_URL, CUBEJS_DB_DATABRICKS_ACCEPT_POLICY (the form ticks it) |
| Athena | CUBEJS_AWS_KEY, CUBEJS_AWS_SECRET, CUBEJS_AWS_REGION, CUBEJS_AWS_S3_OUTPUT_LOCATION |
| Trino | CUBEJS_DB_HOST, CUBEJS_DB_USER, CUBEJS_DB_PRESTO_CATALOG |
| DuckDB | nothing — no path means an in-memory database |
A password is never required (some warehouses authenticate otherwise), and a type not in this
table is accepted with whatever CUBEJS_DB_* / CUBEJS_AWS_* settings you type. Settings with any
other prefix are refused.
A database on your own machine
From inside a container, your machine is host.docker.internal, not localhost.
Databricks needs Cube's JDK image: change the cube-api image to cubejs/cube:<version>-jdk
with platform: linux/amd64. The rendered file's comment says so.
Inside the semantic deployment¶
modelstoreowns the data model's files and their history, and is the only door to Cube. It serves queries at/refs/{ref}/query,/refs/{ref}/sqland/refs/{ref}/meta, minting a short-lived JWT for Cube that names the ref and its revision. Health check:GET /healthz.cube-apiruns the stockcubejs/cubeimage with acube.pysupplied through composeconfigs. Its port is not published.CUBEJS_DEV_MODEisfalse, because dev mode turns off JWT verification. Each ref and revision compiles separately, so a model change is live within seconds with no restart.cubestoreis required: production-mode Cube answers/metawithout it but refuses every query.
Apple Silicon and Cube Store
Cube Store publishes one architecture per tag, with no multi-arch manifest. The wrong one
fails at docker compose up with no matching manifest. The portal picks the tag from the
architecture of the machine rendering the file (-arm64v8 suffix on arm64). If you run the
file on a different machine, change that one line; the file's comment marks it.
Inside the sandbox¶
One service, hardened: 2 GB memory, 2 CPUs, 512 processes, all capabilities dropped,
no-new-privileges. It holds no warehouse credential and cannot sign a Cube token, which is what
keeps the query gate load-bearing even though the agent's Python runs here. It can reach the
network, so its port is bound to loopback and its token is mandatory.
Each chat and each Flow run gets its own workspace directory in the workspaces volume. Timeouts
are written into the file: SANDBOX_EXEC_TIMEOUT_S=120 and SANDBOX_PROFILE_TIMEOUT_S=60.