Skip to content

Add postgres-r2: durable Postgres in a CVM, disk- and node-loss drills - #125

Draft
amiller wants to merge 1 commit into
Dstack-TEE:mainfrom
amiller:postgres-r2-pr
Draft

amiller wants to merge 1 commit into
Dstack-TEE:mainfrom
amiller:postgres-r2-pr

Conversation

@amiller

@amiller amiller commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

Postgres in a dstack CVM that treats the disk as a cache. wal-g ships every WAL segment to an S3-compatible bucket (Cloudflare R2), encrypted under a key the app derives from the KMS — nothing outside the enclave ever holds it. A node that loses its disk, or a whole node, rebuilds from the archive.

Two drills

  • Disk loss — wipe the volume, redeploy the same app as a standby, SELECT pg_promote(). The canary survives; no key was carried across, the app re-derived it.
  • Node lossphala cvms replicate a standby onto a second node (same app id → same derived key, primary_conninfo empty, never connects to the primary), SIGKILL the primary mid-write, promote the standby, count acknowledged writes lost.

Measured

Two real CVMs on two nodes, writer through the gateway, docker rm -f on the primary (SIGKILL, no archive flush):

archive_timeout acked lost
60s 771 429
15s 739 16

RPO is bounded by archive_timeout (that's the guarantee); the sample depends on where the kill lands in the archive cycle. verify.sh checks the three claims against a live CVM: keys derived not stored, archive current, bucket holds ciphertext.

What's here

  • docker-compose.yml — inline entrypoint: derives the superuser password and WAL key from GetKey, PG_ROLE primary/standby, archive on both roles so a promoted standby re-arms, wal_retrieve_retry_interval=30s so a caught-up standby stops polling the bucket.
  • README.md — the two drills, the numbers with denominators, how it works, and the honest open problems (RPO 0 needs streaming; archive rollback).
  • verify.sh — live verification.

Draft: opening for a review pass before marking ready.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BVSS9AUWZVgcHbmLr4KvBt

Postgres in a dstack CVM that treats the disk as a cache: wal-g ships every
WAL segment to an S3-compatible bucket (Cloudflare R2), encrypted under a key
the app derives from the KMS — nothing outside the enclave ever holds it.

Two drills. Disk loss: wipe the volume, redeploy the same app as a standby,
promote. Node loss: `phala cvms replicate` a standby onto another node (same
app id -> same derived key, no connection to the primary), SIGKILL the primary
mid-write, promote, count acked writes lost. Real numbers: 429/771 lost at
archive_timeout=60s, 16/739 at 15s (the bound is the guarantee, the sample
depends on where the kill lands). verify.sh checks the three claims live.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01BVSS9AUWZVgcHbmLr4KvBt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant