Finish RAILIANCE-WP-0016 apps-pg resource evidence
Publish capacity, recovery, labor, and allocation-driver evidence for resource:railiance:apps-pg so resource-control can forecast and allocate without reading application data or inventing booked cost.
This commit is contained in:
parent
b5fb44b53e
commit
6033ae1aef
6 changed files with 566 additions and 6 deletions
|
|
@ -105,3 +105,10 @@ are follow-up platform work items.
|
|||
Until backup coverage is explicitly added, consumer onboarding should
|
||||
record whether app data is disposable, externally reproducible, or
|
||||
requires an immediate backup follow-up before production use.
|
||||
|
||||
Resource evidence for `resource:railiance:apps-pg` (capacity, recovery,
|
||||
labor, allocation drivers) is published under
|
||||
`docs/evidence/RAILIANCE-WP-0016-apps-pg-resource-evidence.md`. The
|
||||
2026-08-14 observation: no ScheduledBackup, railiance01 `apps-pg` is
|
||||
not an Option A target, RPO is unbounded, RTO is undefined. That is
|
||||
unresolved local-storage risk, not verified recovery.
|
||||
|
|
|
|||
139
docs/evidence/RAILIANCE-WP-0016-apps-pg-observation.json
Normal file
139
docs/evidence/RAILIANCE-WP-0016-apps-pg-observation.json
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
{
|
||||
"schema_version": "0.1",
|
||||
"record_type": "usage_observation",
|
||||
"resource_id": "resource:railiance:apps-pg",
|
||||
"source": "railiance-platform",
|
||||
"workplan_id": "RAILIANCE-WP-0016",
|
||||
"reef": "reef-railiance",
|
||||
"captured_at": "2026-08-14T00:04:19Z",
|
||||
"identity": {
|
||||
"cluster": "apps-pg",
|
||||
"namespace": "databases",
|
||||
"pod": "apps-pg-1",
|
||||
"image": "ghcr.io/cloudnative-pg/postgresql:16",
|
||||
"postgres_version": "PostgreSQL 16.13 (Debian 16.13-1.pgdg11+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit",
|
||||
"created_at": "2026-08-09T00:15:53Z",
|
||||
"phase": "Cluster in healthy state"
|
||||
},
|
||||
"capacity": {
|
||||
"instances_provisioned": 1,
|
||||
"instances_ready": 1,
|
||||
"cpu_request": null,
|
||||
"memory_request": null,
|
||||
"cpu_limit": null,
|
||||
"memory_limit": null,
|
||||
"storage_provisioned": "10Gi",
|
||||
"storage_class": "local-path",
|
||||
"max_connections": 100
|
||||
},
|
||||
"utilization": {
|
||||
"cpu_observed": "9m",
|
||||
"memory_observed": "102Mi",
|
||||
"pgdata_bytes": 619083120,
|
||||
"wal_bytes_since_init": 587202560,
|
||||
"sessions": 7,
|
||||
"databases": [
|
||||
{
|
||||
"name": "apps_meta",
|
||||
"bytes": 7830551,
|
||||
"backends": 0,
|
||||
"xact_commit": 14374,
|
||||
"xact_rollback": 0,
|
||||
"blks_read": 126,
|
||||
"blks_hit": 525989,
|
||||
"tup_inserted": 0,
|
||||
"tup_updated": 0,
|
||||
"tup_deleted": 0
|
||||
},
|
||||
{
|
||||
"name": "coulomb_social_db",
|
||||
"bytes": 8952855,
|
||||
"backends": 0,
|
||||
"xact_commit": 14754,
|
||||
"xact_rollback": 0,
|
||||
"blks_read": 41,
|
||||
"blks_hit": 574766,
|
||||
"tup_inserted": 982,
|
||||
"tup_updated": 77,
|
||||
"tup_deleted": 11
|
||||
},
|
||||
{
|
||||
"name": "postgres",
|
||||
"bytes": 7830551,
|
||||
"backends": 1,
|
||||
"xact_commit": 146383,
|
||||
"xact_rollback": 0,
|
||||
"blks_read": 356,
|
||||
"blks_hit": 3445068,
|
||||
"tup_inserted": 0,
|
||||
"tup_updated": 4,
|
||||
"tup_deleted": 0
|
||||
},
|
||||
{
|
||||
"name": "vergabe_db",
|
||||
"bytes": 7668239,
|
||||
"backends": 0,
|
||||
"xact_commit": 0,
|
||||
"xact_rollback": 0,
|
||||
"blks_read": 0,
|
||||
"blks_hit": 0,
|
||||
"tup_inserted": 0,
|
||||
"tup_updated": 0,
|
||||
"tup_deleted": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"consumers": [
|
||||
{
|
||||
"database": "coulomb_social_db",
|
||||
"workload": "coulomb-social",
|
||||
"role": "coulomb_social",
|
||||
"cost_attribution_key": "platform:coulomb-social",
|
||||
"bytes": 8952855,
|
||||
"xact_commit": 14754,
|
||||
"backends": 0,
|
||||
"share_of_consumer_bytes": 0.5386
|
||||
},
|
||||
{
|
||||
"database": "vergabe_db",
|
||||
"workload": "vergabe-teilnahme",
|
||||
"role": "vergabe",
|
||||
"cost_attribution_key": "platform:vergabe-teilnahme",
|
||||
"bytes": 7668239,
|
||||
"xact_commit": 0,
|
||||
"backends": 0,
|
||||
"share_of_consumer_bytes": 0.4614
|
||||
}
|
||||
],
|
||||
"recovery": {
|
||||
"cluster_ready": true,
|
||||
"continuous_archiving": true,
|
||||
"scheduled_backup_present": false,
|
||||
"option_a_target": false,
|
||||
"restore_drill_recorded": false,
|
||||
"rpo": "unbounded",
|
||||
"rto": "undefined",
|
||||
"failure_domain": "single-host local-path on railiance01"
|
||||
},
|
||||
"allocation": {
|
||||
"method": "proportional",
|
||||
"driver": "database_gb",
|
||||
"method_version": "apps-pg-dbbytes-v1",
|
||||
"consumer_bytes": 16621094,
|
||||
"residual_bytes": 586800924,
|
||||
"residual_key": "platform:apps-pg-overhead",
|
||||
"notes": [
|
||||
"Consumer share is pg_database_size of declared consumer databases only.",
|
||||
"Residual is PGDATA minus all non-template databases (WAL and catalogs)."
|
||||
]
|
||||
},
|
||||
"provenance": {
|
||||
"commands": [
|
||||
"kubectl get cluster apps-pg -n databases -o json",
|
||||
"kubectl top pod -n databases -l cnpg.io/cluster=apps-pg",
|
||||
"kubectl exec -n databases apps-pg-1 -c postgres -- du -sb /var/lib/postgresql/data/pgdata",
|
||||
"psql non-secret catalog and pg_stat_database queries"
|
||||
],
|
||||
"authority": "reef-railiance Kubernetes API + local postgres catalog"
|
||||
}
|
||||
}
|
||||
118
docs/evidence/RAILIANCE-WP-0016-apps-pg-resource-evidence.md
Normal file
118
docs/evidence/RAILIANCE-WP-0016-apps-pg-resource-evidence.md
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
# apps-pg resource evidence
|
||||
|
||||
Work record: `RAILIANCE-WP-0016`
|
||||
Resource: `resource:railiance:apps-pg`
|
||||
Captured: `2026-08-14T00:04:19Z` (refresh:
|
||||
`scripts/capture-apps-pg-evidence.py -o docs/evidence/RAILIANCE-WP-0016-apps-pg-observation.json`)
|
||||
Machine-readable companion: `docs/evidence/RAILIANCE-WP-0016-apps-pg-observation.json`
|
||||
|
||||
This is the platform-owned evidence `RESOURCE-WP-0003-T04` asked for.
|
||||
It does not contain credentials, DSNs, or application rows. It is not a
|
||||
fin-hub ledger: no EUR amounts are invented here. resource-control can
|
||||
forecast and allocate from these technical facts; booked spend stays in
|
||||
fin-hub.
|
||||
|
||||
## T01 — Capacity and utilization
|
||||
|
||||
| Fact | Value | Kind | Source |
|
||||
| --- | --- | --- | --- |
|
||||
| Instances | 1 provisioned, 1 ready | declared + observed | Cluster `apps-pg` |
|
||||
| Image | `ghcr.io/cloudnative-pg/postgresql:16` (live 16.13) | declared | Cluster spec / `version()` |
|
||||
| Created | 2026-08-09T00:15:53Z | observed | Cluster metadata |
|
||||
| Phase | Cluster in healthy state | observed | Cluster status |
|
||||
| CPU / memory requests | unset (BestEffort) | declared | empty `spec.resources` |
|
||||
| CPU / memory observed | 9m / 102Mi | observed | `kubectl top` |
|
||||
| Storage provisioned | 10Gi, `local-path`, RWO | declared | PVC `apps-pg-1` |
|
||||
| PGDATA used | 619 083 120 B (~590.4 MiB) | observed | `du -sb …/pgdata` |
|
||||
| WAL since init | 587 202 560 B (~560 MiB) | observed | `pg_wal_lsn_diff` |
|
||||
| max_connections | 100 | declared | `SHOW max_connections` |
|
||||
| Sessions at capture | 7 (1 `postgres` + 6 background) | observed | `pg_stat_activity` |
|
||||
|
||||
Consumer catalogs, five days after commission:
|
||||
|
||||
| Database | Workload | Bytes | xact_commit | backends |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `coulomb_social_db` | coulomb-social | 8 952 855 | 14 754 | 0 |
|
||||
| `vergabe_db` | vergabe-teilnahme | 7 668 239 | 0 | 0 |
|
||||
| `apps_meta` | platform bootstrap | 7 830 551 | 14 374 | 0 |
|
||||
| `postgres` | engine catalog | 7 830 551 | 146 383 | 1 |
|
||||
|
||||
`vergabe_db` has never been used. `coulomb_social_db` is the only consumer
|
||||
with writes (982 inserts). Cache hit on that database is >99.9%. There is
|
||||
no I/O history older than cluster creation and no metrics retention;
|
||||
saturation proxies are the snapshot above plus WAL growth.
|
||||
|
||||
Headroom: ~9.4 GiB of the 10Gi PVC is free. The instance has no CPU or
|
||||
memory request, so it does not reserve cluster capacity. Observed use is
|
||||
idle-class.
|
||||
|
||||
## T02 — Recovery and operations
|
||||
|
||||
| Check | Result |
|
||||
| --- | --- |
|
||||
| Cluster Ready | true since 2026-08-09T00:16:16Z |
|
||||
| ContinuousArchiving | true — CNPG `wal-archive` to the instance manager, **on-node** |
|
||||
| CNPG `Backup` / `ScheduledBackup` | none |
|
||||
| Option A logical dump | **not a target**. Default list covers CoulombCore `apps-pg` and railiance01 `forgejo-db` / `net-kingdom-pg` / `state-hub-db` / `user-engine-pg` only |
|
||||
| Restore drill for this cluster | none recorded |
|
||||
| Replica / pooler | not configured (single instance) |
|
||||
| Failure domain | `railiance01` + `local-path`. Host loss is data loss |
|
||||
|
||||
Recovery objectives: **RPO unbounded, RTO undefined**. This is unresolved
|
||||
local-storage risk, not verified recovery. `docs/apps-pg.md` already said
|
||||
backup was follow-up work; this observation confirms it has not landed for
|
||||
the railiance01 cluster.
|
||||
|
||||
Maintenance: image tag `postgresql:16` is a major pin, not a patch pin.
|
||||
The live minor is 16.13. No upgrade or incident record exists for this
|
||||
cluster. Cadence is unscheduled.
|
||||
|
||||
Labor (high uncertainty, not a timesheet):
|
||||
|
||||
| Class | Estimate | Basis |
|
||||
| --- | --- | --- |
|
||||
| Setup | 6 operator-hours | RAILIANCE-WP-0003 cluster + two consumer onboardings + docs, 2026-08-09 |
|
||||
| Recurring | 0.5 operator-hours / month | ad-hoc `make apps-pg-status`; no backup, restore, or upgrade job |
|
||||
| Incidents | 0 recorded | none in workplans or Cluster conditions |
|
||||
|
||||
resource-control may convert hours at its own labor rate. Do not treat
|
||||
these hours as booked cost.
|
||||
|
||||
## T03 — Allocation drivers
|
||||
|
||||
`apps-pg` is a shared platform service. The recommended first method is
|
||||
the one resource-control already sketched, with the residual made
|
||||
explicit.
|
||||
|
||||
**Method `apps-pg-dbbytes-v1`**
|
||||
|
||||
- Driver: `database_gb` = `pg_database_size` of each **declared consumer**
|
||||
database.
|
||||
- Denominator: sum of those consumer sizes (16 621 094 B at capture).
|
||||
- Shares at capture: coulomb-social **0.5386**, vergabe-teilnahme **0.4614**.
|
||||
- Residual: PGDATA minus all non-template databases = 586 800 924 B
|
||||
(**94.8%** of used volume). Attribute to
|
||||
`platform:apps-pg-overhead`. This is WAL plus engine catalogs, not
|
||||
missing consumer data.
|
||||
- Uncertainty: **high**. Five days of life, empty `vergabe_db`, no history.
|
||||
|
||||
Candidates considered and not selected as v1:
|
||||
|
||||
| Driver | Why not first |
|
||||
| --- | --- |
|
||||
| Connections | All consumers idle at capture; peak is our own `psql` |
|
||||
| `xact_commit` / tuples | Would assign ~100% to coulomb-social and 0% to a reserved empty database |
|
||||
| Equal instance share | Fair while data is tiny, but it hides growth; keep as fallback `apps-pg-instance-v1` if residual stays above 50% after the first month |
|
||||
|
||||
Shared overhead stays unattributed to a consumer on purpose. Converting
|
||||
the residual into booked EUR is fin-hub / resource-control work. Adding a
|
||||
third consumer is a new row in `consumers` plus a Database CR; the method
|
||||
does not change.
|
||||
|
||||
## What this is not
|
||||
|
||||
- Not a cost figure. The host bill belongs to `resource:hosteurope:railiance01`.
|
||||
- Not a backup program. Covering railiance01 `apps-pg` is a later platform
|
||||
change, gated on the same object-store decision as `platform-pg`.
|
||||
- Not application telemetry. No table counts, no tenant identifiers, no
|
||||
Secret values.
|
||||
Loading…
Add table
Add a link
Reference in a new issue