Skip to content

feat(template): pre-bake initialized PGDATA to skip first-boot initdb#8

Merged
jaredLunde merged 1 commit into
mainfrom
feat/pgdata-template
Jun 26, 2026
Merged

feat(template): pre-bake initialized PGDATA to skip first-boot initdb#8
jaredLunde merged 1 commit into
mainfrom
feat/pgdata-template

Conversation

@jaredLunde

Copy link
Copy Markdown
Contributor

Why

A fresh Postgres primary ran initdb + the full CREATE EXTENSION suite in the guest before accepting connections — ~1-2s+ on the cold-boot critical path. This bakes an already-initialized cluster into the rootfs at image-build time and copies it onto the fresh data volume on first boot instead.

What

  • beyond-pg build-template <dir> (new subcommand) — runs the canonical pg::initdb flag set, starts a build-time postgres with the runtime's filtered shared_preload_libraries, and creates the same REQUIRED+OPTIONAL extension set the supervisor would (reusing its lists + extension_installed filter, so the baked cluster can't drift). Run by a new packer/scripts/10-pgdata-template.sh provisioner in the image build.
  • maybe_initdb materializes the template when present (atomic staging + rename, pg_wal symlink repointed, targeted fsync), else falls back to runtime initdb.
  • Per-instance state (superuser/replicator passwords, roles) stays out of the template — post_start applies it every boot, so no shared secret is exposed and CREATE EXTENSION IF NOT EXISTS becomes a no-op on first boot.

Verification

  • Chroot build-template produces a 40M template (initdb + beyond_queue, pg_cron, pg_stat_statements, pg_trgm, hypopg, pg_repack) + clean delta (334MB).
  • Unit tests: materialize copy / symlink repoint / idempotency / leftover-staging recovery.

🤖 Generated with Claude Code

A fresh Postgres primary ran `initdb` plus the full `CREATE EXTENSION` suite in
the guest before accepting connections — ~1-2s+ squarely on the cold-boot
critical path. Bake an already-initialized cluster (initdb + extensions) into the
rootfs at image-build time and copy it onto the fresh data volume on first boot
instead.

- `beyond-pg build-template <dir>` (new subcommand): runs the canonical
  `pg::initdb` flag set into <dir>/main, starts a build-time postgres with the
  same filtered `shared_preload_libraries`, and creates the same
  REQUIRED+OPTIONAL extension set the supervisor would (reusing its lists +
  `extension_installed` filter) — single source, so the baked cluster can't drift
  from what the runtime expects. Points at the shipped pg_hba (local peer) so the
  build-time psql authenticates without a password.

- `maybe_initdb` materializes the template when present (atomic staging + rename,
  pg_wal symlink repointed to the runtime waldir, targeted fsync), else falls
  back to runtime initdb. PG_VERSION only appears once a complete, correct PGDATA
  is published, so the skip-on-PG_VERSION check stays safe and an interrupted
  materialize is simply redone next boot.

- Per-instance state (superuser/replicator passwords, roles) stays OUT of the
  template; `post_start` applies it every boot, so no shared build-time secret is
  exposed and `CREATE EXTENSION IF NOT EXISTS` becomes a no-op on first boot.

Verified: chroot build-template produces a 40M template (initdb + beyond_queue,
pg_cron, pg_stat_statements, pg_trgm, hypopg, pg_repack) and a clean delta; unit
tests cover materialize copy/symlink/idempotency/leftover-staging recovery.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jaredLunde jaredLunde merged commit 89db3e5 into main Jun 26, 2026
1 check passed
@jaredLunde jaredLunde deleted the feat/pgdata-template branch June 26, 2026 16:39
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