diff --git a/apps/docs/content/guides/choose-cache.mdx b/apps/docs/content/guides/choose-cache.mdx index b40d5eea..4c8fdafa 100644 --- a/apps/docs/content/guides/choose-cache.mdx +++ b/apps/docs/content/guides/choose-cache.mdx @@ -14,6 +14,7 @@ description: "**Use Valkey.** KeyDB development has stalled and is effectively d ## Valkey (Default Choice) - Redis-compatible drop-in replacement -- Type: `valkey:single@7.2` (single) or `valkey:ha@7.2` (HA) — only v7.2 is supported (the platform rejects `valkey@8` at import, `serviceStackTypeNotFound`) -- Profile (scaling tier): `hobby` for dev, `staging` for production; escalate to `production` only on a clear load signal -- Connection: `redis://${hostname}:6379` — Valkey runs **unauthenticated** on Zerops; there are NO `user`/`password` env vars. Do **not** template `${cache_user}`/`${cache_password}` — they don't exist and produce a broken DSN +- **HA vs single → the `type` variant:** `valkey:single@7.2` (default) / `valkey:ha@7.2`. Only `7.2` exists — the platform rejects `valkey@8` (`serviceStackTypeNotFound`). +- **Scaling tier → the `profile` field:** `hobby` / `staging` *(default)* / `production`. Recommend `hobby` for dev (cheapest), `staging` for production; escalate to `production` only on a clear load signal. Omitting `profile` applies `staging`. +- **Legacy form** (older YAML / existing services): `type: valkey@7.2` + `mode:` — `mode: NON_HA` ≡ `:single`, `mode: HA` ≡ `:ha`. Still accepted (remaps to the variant) but `mode` is deprecated; author new YAML as the variant + profile. +- Connection: Valkey **requires auth** on Zerops — use `${cache_connectionString}` (full auth'd URL) or supply `${cache_password}` (e.g. `REDIS_PASSWORD: ${cache_password}`). There is no separate `${cache_user}` (default user + password); an unauthenticated `redis://${hostname}:6379` fails with `NOAUTH Authentication required`. diff --git a/apps/docs/content/guides/choose-database.mdx b/apps/docs/content/guides/choose-database.mdx index b8b63077..21bec425 100644 --- a/apps/docs/content/guides/choose-database.mdx +++ b/apps/docs/content/guides/choose-database.mdx @@ -3,7 +3,7 @@ title: "Choosing a Database on Zerops" description: "**Use PostgreSQL** for everything unless you have a specific reason not to. It's the best-supported database on Zerops with full HA, read replicas, and pgBouncer." --- -**Use PostgreSQL** for everything unless you have a specific reason not to — the best-supported database on Zerops, with optional HA, read replicas, and pgBouncer. HA vs single node is set in the type (`postgresql:single@` / `postgresql:ha@`) and is immutable; legacy `mode: NON_HA`/`HA` is deprecated (`NON_HA` ≡ `:single`, `HA` ≡ `:ha`). +**Use PostgreSQL** for everything unless you have a specific reason not to — the best-supported database on Zerops, with optional HA, read replicas, and pgBouncer. ## Decision Matrix @@ -11,17 +11,51 @@ description: "**Use PostgreSQL** for everything unless you have a specific reaso |------|--------|-----| | **General-purpose** | **PostgreSQL** (default) | Optional HA, read replicas, pgBouncer, best Zerops support | | MySQL compatibility | MariaDB | MaxScale routing, async replication | -| Analytics / OLAP | ClickHouse | Columnar storage, ReplicatedMergeTree, 4 protocol ports | +| Analytics / OLAP | ClickHouse | Columnar storage, ReplicatedMergeTree | -## PostgreSQL (Default Choice) +## PostgreSQL — two import-YAML choices, both fixed for the service's life -- Type + scaling: `postgresql:single@` (single node, dev) or `postgresql:ha@` (HA cluster). Add a `profile` (scaling tier) — set it explicitly and escalate only on a clear signal: `oltp-hobby` for dev, `oltp-staging` for production, moving up to `oltp-production` / `oltp-enterprise` only when load clearly needs it. Omitting it applies the default (single → `oltp-staging`, HA → `oltp-production` = dedicated CPU). See [PostgreSQL scaling](/postgresql/how-to/scale) -- Connection: the generated `${connectionString}` is `postgresql://${user}:${password}@${hostname}:5432` (no database path). Append `/${dbName}` yourself if your driver needs one — the db-name var is `dbName` (default `db`) +**1. HA vs single node → the `type` variant** (NOT a `mode:` field): + +- `postgresql:single@` — one node. Default for dev and most apps. +- `postgresql:ha@` — 3-node cluster + proxies. Production-grade; resources start at the production tier. + +**2. Scaling tier → the `profile` field** (autoscaling envelope + PostgreSQL tuning preset): + +| Workload | `:single` profile | `:ha` profile | +|---|---|---| +| dev / prototype / learning — cheapest | **`oltp-hobby`** | — (HA has no hobby) | +| staging / early-stage app | `oltp-staging` *(single default)* | `oltp-staging` | +| business-critical transactional | `oltp-production` | `oltp-production` *(HA default)* | +| high-throughput OLTP at scale | — | `oltp-enterprise` | +| analytics / warehouse | `olap-production` | `olap-production` | +| ingestion / write-heavy | `writeheavy-production` | `writeheavy-production` | + +**Recommended defaults — set `profile` explicitly; escalate only on a clear signal:** dev → `postgresql:single@` + `profile: oltp-hobby` (lowest cost); production → `profile: oltp-staging` (move to `oltp-production` / `oltp-enterprise` only when load clearly warrants it). Omitting `profile` applies the default — single → `oltp-staging`, **HA → `oltp-production` (dedicated CPU + high minima)** — which over-provisions HA. + +```yaml +services: + - hostname: db # dev — cheapest + type: postgresql:single@18 + profile: oltp-hobby + - hostname: db # production HA — default tier (profile optional) + type: postgresql:ha@18 + profile: oltp-production +``` + +- `profileOverrides` (individual params: `work_mem`, `max_wal_size`, `autovacuum_*`, …) is valid **only** with `profile: custom`. +- `verticalAutoscaling` (CPU mode, min/max CPU/RAM/disk) tightens the envelope on top of any profile — no need for `custom` just to resize. + +**Legacy form — you may still meet it** in older YAML, recipes, or existing services: `type: postgresql@` + a separate `mode:` field. The mapping is `mode: NON_HA` ≡ `:single`, `mode: HA` ≡ `:ha`. The platform still accepts the legacy form (it remaps to the variant) but `mode` is **deprecated and ignored by validation**. Author new YAML as `:single`/`:ha` + `profile`; treat a discovered `mode:` as its equivalent variant. + +- Connection: the generated `${connectionString}` is `postgresql://${user}:${password}@${hostname}:5432` (no database path). Append `/${dbName}` yourself if your driver needs one — the db-name var is `dbName` (default `db`). ## MariaDB -- Connection: the generated `${connectionString}` is `mysql://${user}:${password}@${hostname}:3306` (no database path); append `/${dbName}` if your driver needs one +- Type variant: `mariadb:single@` / `mariadb:ha@`. No `profile` — scale with `verticalAutoscaling`. +- Connection: the generated `${connectionString}` is `mysql://${user}:${password}@${hostname}:3306` (no database path); append `/${dbName}` if your driver needs one. ## ClickHouse -- HA: replicated databases use a `Replicated(...)` engine `ON CLUSTER`; tables use a `Replicated*MergeTree` engine (without `ON CLUSTER`) +- Type variant: `clickhouse:single@` / `clickhouse:ha@`. No `profile` — scale with `verticalAutoscaling`. +- HA: replicated databases use a `Replicated(...)` engine `ON CLUSTER`; tables use a `Replicated*MergeTree` engine (without `ON CLUSTER`). diff --git a/apps/docs/content/guides/production-checklist.mdx b/apps/docs/content/guides/production-checklist.mdx index db5ad198..9f4faf55 100644 --- a/apps/docs/content/guides/production-checklist.mdx +++ b/apps/docs/content/guides/production-checklist.mdx @@ -3,17 +3,20 @@ title: "Production Checklist for Zerops" description: "Before going to production: (1) databases to HA mode, (2) minContainers: 2 on app services, (3) replace Mailpit with real SMTP, (4) remove Adminer, (5) use Object Storage for uploads, (6) use Redis/Valkey for sessions." --- -Before going to production: (1) databases to HA mode, (2) minContainers: 2 on app services, (3) replace Mailpit with real SMTP, (4) remove Adminer, (5) use Object Storage for uploads, (6) use Valkey for sessions. +Before going to production: (1) databases to HA (the `:ha` type variant), (2) minContainers: 2 on app services, (3) replace Mailpit with real SMTP, (4) remove Adminer, (5) use Object Storage for uploads, (6) use Valkey for sessions. ## Database | Item | Dev | Production | |------|-----|------------| -| Deployment variant | `:single` | `:ha` (must recreate) | +| Deployment variant | `:single` (e.g. `postgresql:single@18`) | `:ha` (e.g. `postgresql:ha@18`) — must recreate | +| Scaling profile | `oltp-hobby` | `oltp-staging` (escalate to `oltp-production` only on clear load) | | Backups | Optional | Enabled | | Connection | Single primary | Primary + read replicas | -**The deployment variant is immutable** — cannot switch after creation. Delete and recreate with the `:ha` type variant (e.g. `postgresql:ha@16`). +**HA is immutable** — cannot switch after creation. Delete and recreate with the `:ha` variant. + +**Legacy form** you may still see in older YAML or existing services: `type: postgresql@18` + a separate `mode:` field — `mode: NON_HA` ≡ `:single`, `mode: HA` ≡ `:ha`. Still accepted (remapped to the variant) but `mode` is deprecated and ignored by validation; author new YAML in the variant form. ## Application Services @@ -90,7 +93,7 @@ Remove entirely or disable `enableSubdomainAccess`. Use VPN + pgAdmin/DBeaver lo ```yaml - hostname: cache - type: valkey:single@7.2 # use valkey:ha@7.2 for production + type: valkey:single@7.2 # valkey:ha@7.2 for production ``` ## Framework-Specific Production Settings @@ -135,7 +138,7 @@ Remove entirely or disable `enableSubdomainAccess`. Use VPN + pgAdmin/DBeaver lo | CPU mode | `cpuMode: DEDICATED` for consistent performance under load | | Environment separation | Separate projects for dev/staging/prod | | Stateless design | Sessions in Valkey, uploads in Object Storage — no local state | -| Database variant | `:ha@` for all managed services (immutable — plan before creation) | +| Database HA | the `:ha` type variant for all HA-capable managed services (immutable — plan before creation) | | Min containers | `minContainers: 2+` on app services for throughput + crash-tolerance (rolling deploys are already zero-downtime at any count via the default `temporaryShutdown: false` — don't conflate the two) | ## Health Check Pattern diff --git a/apps/docs/content/guides/scaling.mdx b/apps/docs/content/guides/scaling.mdx index e785a6be..01fb52fe 100644 --- a/apps/docs/content/guides/scaling.mdx +++ b/apps/docs/content/guides/scaling.mdx @@ -3,7 +3,7 @@ title: "Scaling and Autoscaling" description: "Zerops autoscales vertically (CPU/RAM/disk) and horizontally (container count). Runtimes support both. Managed services (DB, cache, shared-storage) support vertical only with fixed container count (`:single`=1, `:ha`=3). Object-storage and Docker have no autoscaling. Extends grammar.md section 9 with mechanics, thresholds, YAML syntax, and common mistakes." --- -Zerops autoscales vertically (CPU/RAM/disk) and horizontally (container count). Runtimes support both. Managed services (DB, cache, shared-storage) support vertical only with fixed container count (`:single`=1, `:ha`=3). Object-storage and Docker have no autoscaling. Extends grammar.md section 9 with mechanics, thresholds, YAML syntax, and common mistakes. +Zerops autoscales vertically (CPU/RAM/disk) and horizontally (container count). Runtimes support both. Managed services (DB, cache, shared-storage) support vertical only with fixed container count (the `:single` type variant = 1 node, `:ha` = 3). Object-storage and Docker have no autoscaling. Extends grammar.md section 9 with mechanics, thresholds, YAML syntax, and common mistakes. ## When to Scale Which Way @@ -111,12 +111,14 @@ Applies to **runtimes and Linux containers only**. New containers are added when ### Managed Services (DB, Cache, Shared Storage) -Container count is **fixed by the deployment variant** (`:single` / `:ha` in the type), set at creation, **immutable**: +Container count is **fixed by the deployment variant in the type** (`postgresql:single@18` / `postgresql:ha@18`), set at creation, **immutable**: | Variant | Containers | Use case | |---|---|---| -| `:single` | 1 | Development, non-critical | -| `:ha` | 3 (on separate physical machines) | Production, automatic failover | +| `:single` | 1 | Development, non-critical | +| `:ha` | 3 (on separate physical machines) | Production, automatic failover | + +**Legacy form** you may still see in older YAML: a separate `mode:` field — `mode: NON_HA` ≡ `:single`, `mode: HA` ≡ `:ha`. Still accepted (remapped to the variant) but deprecated and ignored by validation. HA recovery: failed container is disconnected, new one created on different hardware, data synchronized from healthy copies, failed container removed. @@ -155,7 +157,6 @@ services: # Managed DB (vertical only, no container settings) - hostname: db type: postgresql:ha@16 - profile: oltp-production verticalAutoscaling: cpuMode: DEDICATED minCpu: 1