<Home>
DocumentationSELF-HOSTED / DEVELOPMENT RELEASEView source ↗
GUIDE 22 / Databases

Database architecture

Follow a database request through the Go API, durable operations, controllers and resource accounting.

Self-hosted alpha.56 adds Managed MyDuck and Oracle Database Free. Cloud alpha.35 packages the same support, but packaging does not guarantee shared Cloud capacity: the current shared Cloud service cannot provision Oracle Free or Vitess, and MyDuck availability depends on eligible worker capacity and runtime setup. Neon and Supabase are deferred. The alpha.56 acceptance record covers the new MyDuck and Oracle Free qualification. Vitess keeps its alpha.55 native and shared HTTP evidence; alpha.56 carries its unchanged runtime, operator, images, build and installer after an exact source-delta review and shared CI regressions. Check the managed database guide for each engine's boundary. Development-cluster acceptance does not establish production availability or physical multi-zone resilience.

Follow one create request#

Save a database specification in orders.toml:

schema_version = 1
name = "orders"
engine = "postgresql"
version = "17"
mode = "cluster"
replicas = 1
shards = 1
cpu = "500m"
memory = "1Gi"
storage_gib = 10

[tls]
mode = "required"

[placement]
spread = "nodes"

This requests a primary and one replica on different eligible nodes. It needs two data volumes and capacity for operation overhead. Two nodes on one VM do not provide two independent failure domains.

hakopod database create --project demo --environment development --file orders.toml
hakopod database list --project demo --environment development
hakopod database show DATABASE_ID

The dashboard, CLI and API share the same Go handlers. The server validates the strict versioned specification, project/environment permissions, runtime prerequisites and capacity. An accepted request records the database revision, allocation and operation durably in PostgreSQL. A queued operation is not a ready database.

The request flows from the dashboard or CLI to the Go API, then to the durable PostgreSQL operation queue. Workers reconcile owned Kubernetes resources and save native observations back to PostgreSQL.

The API and reconciliation workers run in one process by default. Database lifecycle work uses a separate lane from native health probes. The current source starts one lifecycle loop, four observation loops and a bounded maintenance loop. PostgreSQL operation claims use short leases and row locks; expired claims return to the queue. Before runtime writes, the worker rechecks the lease, current revision and authority. It records progress and schedules another bounded step instead of holding an HTTP request open until a cluster starts.

See API and workers, durable operation claims, allocation accounting and the specification.

Who owns each part#

Hakopod owns the resource identity, desired revision, scoped access, credentials, operation history, allocation and application connection grants. An engine-specific Kubernetes controller manages its native database objects. Kubernetes schedules the resulting pods and attaches their owned volumes. The engine's replication protocol determines which members can accept writes.

Ownership checks matter during retries and deletion. A matching name is insufficient: namespace and resource identities must belong to this database. Cleanup must not adopt a pre-existing Secret or delete another workload's volume. A failed or interrupted deletion retains its allocation until the owned persistent data has actually gone.

Database Processes and controller Routing responsibility
PostgreSQL 17/18 CloudNativePG, PostgreSQL members, optional PgBouncer Separate primary and replica services; optional pooled versions of each route.
Redis 8 Credential-safe Opstree Redis operator and Redis members A cluster-aware client follows slot ownership and redirections.
MySQL 8.4 Oracle MySQL Operator, InnoDB Cluster members with sidecars, MySQL Router Router has explicit primary and secondary ports. Voting members determine write availability.
MongoDB 8.0 MongoDB Kubernetes Controller, replica-set members and agents The driver discovers members and selects according to read preference and write concern.
ClickHouse 26.3 Altinity operator, data members, three Keeper members for clusters Local tables remain local to a shard. Distributed tables or explicit queries combine shards.
Oracle Database Free 26ai Namespace-scoped Oracle Database Operator, an owned SingleInstanceDatabase resource, TCPS listener and two equal-size volumes One APP schema in FREEPDB1 over private TCPS port 2484. Free does not implement a Data Guard cluster.
Oracle Enterprise, under development Hardened Oracle Database Operator, primary/standby members and one bounded Data Guard broker helper Native roles determine the write route. Graceful switchover is reviewed; forced failover remains disabled. Licensed-image acceptance is pending.
MyDuck One hardened Linux amd64 MyDuck process and one persistent DuckDB volume MySQL on 3306 and PostgreSQL on 5432 reach the same database. There is no replica, election or automatic failover.
Vitess 23 Namespace-scoped operator, MySQL/vttablet, vtgate, vtctld, vtorc, backup storage controller and three etcd members vtgate uses the keyspace, fixed shard map and explicit VSchema. Included since self-hosted alpha.55 and carried in alpha.56 and Cloud alpha.35. The current shared Cloud service cannot provision Vitess.

Read the PostgreSQL, Redis, MySQL, MongoDB, ClickHouse, Oracle, MyDuck and Vitess guides before choosing an engine. Oracle Free is proprietary, no-cost software limited to 2 CPUs, 2 GB of database memory and 12 GB of user data. Enterprise, Data Guard and public Oracle endpoints remain unavailable.

Capacity includes the supporting processes#

The CPU and memory entered in a database form apply to data members. The total reservation also includes sidecars, gateways, coordinators, sandbox overhead and working capacity for replacement and recovery.

For example, three MySQL members at 500m CPU and 1Gi each, three sidecars at 100m/256Mi, and two Routers at 100m/128Mi request 2 CPU cores and 4Gi before replacement and sandbox headroom. Three 10Gi data volumes add 30Gi of requested storage. This is configured capacity, not observed consumption.

ClickHouse reserves a backup staging volume equal to each data member's data volume, plus three 1Gi Keeper volumes in cluster mode. MongoDB includes agent resources and separate log volumes. Oracle Free includes a backup staging volume and its own schema quota; increasing the pod reservation does not remove Oracle's license limits. MyDuck reserves memory for its protocol servers and process overhead around DuckDB. Vitess includes tablet, gateway, control and topology processes; its source contract accounts for the namespace-scoped operator too.

Cloud serializes database and application reservations against the same workspace allocation. Shrinking members must not refund storage that remains retained. A plan that fits steady-state pods can still fail admission because it cannot fit a replacement. See CPU reservations, database model and allocation transactions.

For a hosted multi-node allocation, the operator approves an exact set of node names and UIDs. A UID identifies the node object, so replacing a node with the same name does not preserve its approval. The full database CPU and memory envelope must fit on every approved worker. A 4-core, 8Gi allocation on two workers therefore reserves that amount on both workers; it is not divided in half. Other workloads and host headroom also count. Storage has a separate operator-declared pool budget.

Cloud can also connect to a separately operated Hakopod cluster. The operator approves the HTTPS endpoint, project, environment and node inventory. The workspace owner then reviews those values and supplies a machine key scoped to that project and environment. Cloud rechecks the approved inventory before forwarding requests. This path connects an existing installation; it does not build its network or storage for you.

What placement and monitoring can prove#

Inspect the available nodes before choosing placement:

hakopod database nodes --project demo --environment development

The same inventory appears in the dashboard's Topology step and through hako.databasePlacementNodes() in the TypeScript SDK. It reports current availability, architecture and any reported zone, region or provider. MySQL, MongoDB and Vitess require amd64 nodes for their pinned images. The form keeps an incompatible or removed selection visible so you can correct it; it does not silently switch to a different node.

spread = "nodes" requires distinct eligible nodes; spread = "zones" requires distinct reported zones. Node and zone labels are scheduler inputs, not evidence of physical independence. Admission checks the eligible domains, but storage, taints, capacity and subsequent failures can still prevent scheduling.

All members belong to one connected Kubernetes cluster. Nodes from different providers need private connectivity, appropriate network encryption, reliable control-plane access and a storage design that tolerates the intended failure. Hakopod does not merge independent Kubernetes clusters into one managed database. Node-local disks cannot be moved by changing a placement label.

The cockpit reads native observations and bounded metrics requests. Revision and observation age determine whether data is current. A configured member count is not a ready count; reserved disk capacity is not disk usage; a replication line is not measured traffic. Keep unavailable measurements unavailable.

Before publishing availability for a new engine, record the exact source, controller/images, architecture, runtime, real-cluster lifecycle, failure, TLS, backup/recovery and application tests. Two nodes on one physical VM can verify scheduler and process behavior. They cannot prove multi-zone or multi-provider resilience.

Continue with routing, credentials and TLS and recovery.