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

Database architecture

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

Self-hosted alpha.47 includes PostgreSQL, Redis and MongoDB. MySQL, ClickHouse, Oracle Database, Vitess, Neon and Supabase remain unavailable while native qualification is incomplete. Check the managed database guide for availability; these guides describe source behavior, not a production deployment.

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 Hakopod-owned standalone StatefulSet, TCPS listener and volumes One PDB service. 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.
Vitess 23, under construction Namespace-scoped operator, MySQL/vttablet, vtgate, vtctld, vtorc and three etcd members vtgate uses keyspace, shard map and explicit VSchema. Native acceptance is pending.

Read the PostgreSQL, Redis, MySQL, MongoDB, ClickHouse, Oracle and Vitess guides before choosing an engine. Oracle Free is proprietary free-to-use software with upstream limits. Enterprise/Data Guard has a separate source implementation; deployment stays disabled until the hardened controller and a licensed image pass native acceptance.

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. 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.