Infrastructure Setup
This is the entry point for the production data/messaging/upload layer. Each service below is its own document — this page just explains what each one does and in what order to set them up. All four assume the 3-node HA k3s cluster (and Longhorn, and APISIX) from the cluster Prerequisite doc already exist.
Services
1. PostgreSQL — CloudNativePG
The primary relational database. Runs as 1 primary + 2 replicas via
CloudNativePG, with a PgBouncer pooler in front so apps never connect to
Postgres directly. Uses local-path-retain storage, not Longhorn — CNPG
already replicates the data itself.
Start here first — most other services either store their own state independently or don't depend on Postgres being up, but it's the most foundational piece if your apps need a database on day one.
2. SeaweedFS — Internal S3 storage
Distributed, S3-compatible object storage (master/volume/filer/S3-gateway),
internal-only — no external route, no -externalUrl. Apps reach it purely
via in-cluster DNS over plain HTTP. The playtelly bucket lives here.
Set up before tusd — tusd streams uploads directly into this, so the bucket needs to exist first.
3. VerneMQ — Shared MQTT broker
One 3-pod HA MQTT broker shared by both production and staging apps
(separated by username + topic prefix, not separate clusters). Also covers
the public APISIX WebSocket route for external MQTT-over-WebSocket clients.
Independent of the other three — can be set up any time after the cluster Prerequisite doc is done.
4. tusd — Resumable file uploads
Handles resumable/chunked uploads (tus protocol) and streams them straight
into SeaweedFS, notifying coreapi via webhook on completion.
Set up last — it depends on SeaweedFS (Section 2 above) already having
the playtelly bucket created.
5. Zitadel — Identity/auth (IAM)
Identity provider — organizations, users, machine service accounts. Runs 2+ replicas for HA, backed by Postgres. Covers both an externally-routed deployment and an internal-only one.
Depends on PostgreSQL — needs the CNPG cluster (and optionally its PgBouncer pooler) already running before its first-instance bootstrap can succeed.
6. NATS JetStream — Messaging/streaming
3-node Raft cluster for pub/sub and persistent streams, across a
mixed-architecture cluster (amd64 + arm64). Requires a custom multi-platform
image since the base image lacks the nats CLI.
Independent of the other five — no shared dependencies, can be set up any time.
Suggested order
1. PostgreSQL ← foundational, no dependencies on the others
2. SeaweedFS ← needed before tusd
3. VerneMQ ← independent, any time
4. tusd ← depends on SeaweedFS's bucket existing
5. Zitadel ← depends on PostgreSQL
6. NATS JetStream ← independent, any time