pg-source: where the pinned PostgreSQL 18 comes from (0006 M0-PG-SOURCE)
Date: 2026-10-11 (measured on hat-8, Fedora 44, glibc 2.43, x86_64, as uid 1000). Consumers: the gateway kcp store (M2-KCP-STORE, kine -> postgres over a unix socket) and every tenant cluster store (M2-POSTGRES). Dev and bidder kcp stores are kine-sqlite and need none of this.
1. Decision order (user, 2026-10-11, final)
- Official binaries first. The PostgreSQL Global Development Group publishes no generic Linux binary tarball; its official binaries are the PGDG packages (apt.postgresql.org debs, yum.postgresql.org rpms). Use them if they can be extracted without root and run relocatably as a non-root user.
- Build from the official source tarball (ftp.postgresql.org/pub/source) only if (1) cannot be
made to work, with a build-host script
scripts/build-postgres.sh. This is the fallback. - Third-party repackagers are out: zonky embedded-postgres-binaries and theseus-rs/postgresql-binaries are not used. Section 6 keeps the facts measured before that ruling, for the record only.
2. Choice
PGDG jammy-pgdg debs for PostgreSQL 18.6 (18.6-1.pgdg22.04+2), amd64 and arm64, plus their
Ubuntu 22.04 (jammy) shared-library dependency closure, extracted without root into one
relocatable tree. PGDG works on hat-8 and on every distro image tried, so the fallback was not
needed. A source build was prototyped and measured before the user's final order (section 5). Its
script is not committed.
Why jammy and not bookworm, noble or the EL rpms: PGDG binaries link the host distro's ICU, OpenLDAP and OpenSSL by soname. The oldest PGDG target at or below the plan's floor (Ubuntu 22.04) is jammy: max GLIBC_2.34 in the PG binaries and GLIBC_2.35 across the bundled libraries. EL8 links OpenSSL 1.1, and EL9 links ICU 67. Both have the same soname problem as jammy, and neither lowers the floor.
What "relocatable" means for the PGDG tree (measured)
- Layout must be kept. PGDG compiles in
bindir=/usr/lib/postgresql/18/bin,sharedir=/usr/share/postgresql/18andpkglibdir=/usr/lib/postgresql/18/lib. At startup PostgreSQL resolves share and pkglib relative to the running binary (make_relative_path) only while the taillib/postgresql/18/binof the binary's path matches. So the tree is kept as<any-root>/usr/lib/postgresql/18/{bin,lib}plus<any-root>/usr/share/postgresql/18, where<any-root>can be any path. That was proven from.../arbitrary2/x y/z/...(a path containing a space) on hat-8, and from/opt/any/where/...read-only in containers. Flattening tobin/ lib/ share/breaks it. - No RUNPATH in PGDG binaries.
libpq.so.5(from the PGDG libpq5 deb) and the jammy libraries sit in<any-root>/usr/lib/sys/, and are found only throughLD_LIBRARY_PATH=<any-root>/usr/lib/sys. That variable must be set on the postgres, initdb and pg_dump exec ONLY, never in the core's own environment. Measured: hat-8'sgrep, spawned under that variable, loaded jammy's libpcre2 and warnedlibpcre2-8.so.0: no version information available.pg_ctlstarts postgres through/bin/sh, which then inherits the variable. That is one more reason the units execpostgresdirectly (M2-POSTGRES, M2-KCP-STORE already do), notpg_ctl. - Host requirements left: glibc >= 2.35 (
libc.so.6 libm.so.6 libresolv.so.2 ld-linux-*.so) and host tzdata. PGDG is built--with-system-tzdata=/usr/share/zoneinfo, an absolute path that is not relocatable. Onubuntu:22.04(no tzdata in the image) the server started withTimeZone=UTC0, andSET timezone='UTC'failed withinvalid value for parameter "TimeZone". On every image with/usr/share/zoneinfoit worked. check-host (M1) must require/usr/share/zoneinfo/UTCon gateway hosts. - Non-root: every run was as uid 1000 on hat-8 and as uid 65534 in the container stand-ins. initdb refuses root anyway.
- Port 0: postgres refuses it in every build:
FATAL: 0 is outside the valid range for parameter "port" (1 .. 65535)(the GUC minimum is 1). This shapes the two stores differently:- The gateway kcp store opens no TCP port at all:
listen_addresses=''plus a unix socket directory. M2-KCP-STORE already specifies this. - Tenant stores that need TCP must lease a port (M2-POSTGRES "0 = leased"). The bound port is
read back from
ss -ltnp(matched on the postmaster pid) and from line 4 ofpostmaster.pid. - kine itself takes
--listen-address 127.0.0.1:0and announces the bound port.
- The gateway kcp store opens no TCP port at all:
- Collation: initdb with
--locale-provider=builtin --builtin-locale=C.UTF-8 -E UTF8, which givesdatlocprovider=b,datlocale=C.UTF-8anddatcollversion=1. The builtin provider is versioned with PostgreSQL itself, independent of glibc and ICU. kine'snamecolumn isCOLLATE "C"anyway (kine v0.17.1 pkg/drivers/pgsql/pgsql.go:40). ICU 70.1 is still linked, and itsunicodecollation reportscollversion=153.112. M2-POSTGRES records that value and treats a change as major-class only for databases that actually use ICU collations. - Security update churn: 44 of the 47 pins are Ubuntu jammy packages (taken from jammy + jammy-updates + jammy-security, highest version). Every Ubuntu security update to libssl3, libxml2, krb5 and the rest changes the bundle's pins.
3. Verification steps (performed; M1-ASSETS repeats them in its assembly script)
- PGDG key:
https://www.postgresql.org/media/keys/ACCC4CF8.asc, imported into a fresh GNUPGHOME. Fingerprint B97B 0AFC AA1A 47F0 44F2 44A0 7FCC 7D46 ACCC 4CF8 ("PostgreSQL Debian Repository", rsa4096, 2011-10-13). https://apt.postgresql.org/pub/repos/apt/dists/jammy-pgdg/InReleasewas verified against that key: Good signature, made 2026-10-11 09:30:45 UTC.- Ubuntu archive key F6EC B376 2474 EDA9 D21B 7022 8719 20D1 991B C93C ("Ubuntu Archive
Automatic Signing Key (2018)") was fetched by full fingerprint from keyserver.ubuntu.com. It
verified the
jammy,jammy-updatesandjammy-securityInRelease files: archive.ubuntu.com for amd64, ports.ubuntu.com for arm64. All Good. - Each
main/binary-<arch>/Packages.gzsha256 was checked against the SHA256 section of its signed InRelease. - Each .deb sha256 was checked against its
Packagesstanza (47 per arch, all matched; table below). - Extraction without root:
ar x <deb>thentar -xf data.tar.*into a scratch root (no dpkg, no maintainer scripts). Then copyusr/lib/postgresql/18/{bin,lib},usr/share/postgresql/18, and every*.so*fromlib/<triplet>andusr/lib/<triplet>intousr/lib/sys. Dropusr/share/postgresql/18/manandusr/lib/postgresql/18/lib/bitcode(JIT bitcode; llvm-jit is a separate package and is not installed). - Repack:
tar --sort=name --owner=0 --group=0 --numeric-owner --mtime=@1786473511 | zstd -19. The epoch is the newest mtime in postgresql-18.6.tar.bz2.
Helper scripts used: apt_fetch.py, jammy_closure.py, pgrun.sh, pgmini.sh and
minisign_verify.py, all in the session scratchpad. M1-ASSETS turns steps 1-7 into its own
script.
4. Pins
Repository bases: https://apt.postgresql.org/pub/repos/apt/ (pgdg). For ubuntu,
https://archive.ubuntu.com/ubuntu/ (amd64) and https://ports.ubuntu.com/ubuntu-ports/ (arm64).
Filename = <pool dir><package>_<version without epoch>_<arch>.deb, for example
https://apt.postgresql.org/pub/repos/apt/pool/main/p/postgresql-18/postgresql-18_18.6-1.pgdg22.04+2_amd64.deb.
| package | version | repo | pool dir | sha256 amd64 | sha256 arm64 |
|---|---|---|---|---|---|
| postgresql-18 | 18.6-1.pgdg22.04+2 | pgdg | pool/main/p/postgresql-18/ | 2aab00b13babd3d9abc257bc5f6b00efa1f7c27cda071413f358d2e0cdb84420 | 8a379f0684b480b60e79657ac8178e8b00c835e7575e85ae746c091d336563d3 |
| postgresql-client-18 | 18.6-1.pgdg22.04+2 | pgdg | pool/main/p/postgresql-18/ | ad4e491adceaf1453162c62691473ace78ed81ab20f50d11b344a793d13ed4bd | 21f1b418621fc9c90785b18ec2d7fe4fd8ff111cc607fc3b3625464fc6e7886b |
| libpq5 | 18.6-1.pgdg22.04+2 | pgdg | pool/main/p/postgresql-18/ | 8af0b458834e219f3aa7c904fa1237ea484950486e3165a3a90204878e060530 | fc0d787c9da82bd0146e5e365989f3c92dbb3d73c3a32c62a2e4d56ab90933a6 |
| libaudit-common | 1:3.0.7-1ubuntu0.1 | ubuntu | pool/main/a/audit/ | 3e4e8586db5f57f431954a9125556fe6df86610592c0cf46ba1127fae8871e3f | 3e4e8586db5f57f431954a9125556fe6df86610592c0cf46ba1127fae8871e3f |
| libaudit1 | 1:3.0.7-1ubuntu0.1 | ubuntu | pool/main/a/audit/ | 00d7eb086dedc85bd5b9cbde650a1c71460499cb62e439acb761bc7bcb4eaaac | 963474b42258e8caa15eec1db61d8424fd6b7ef717ca4e371b3240506854b3fe |
| libcap-ng0 | 0.7.9-2.2build3 | ubuntu | pool/main/libc/libcap-ng/ | 124d0c8748a841f279e996298ef8aac69a249e294792f4b5e16dc00496f1d3ac | 884c8bc87da241abaa2b0ca80162486cf66eff67dfc545bea56622e1170e9ee5 |
| libcap2 | 1:2.44-1ubuntu0.22.04.3 | ubuntu | pool/main/libc/libcap2/ | c497efb7fa3cd19a7ff297d95c7c5d678063c80c9fc230c9d034a8ee02ca8446 | 7a8eb6549355a16f327ede574f12e6ebed983b52ab38ce4a618e6e9274b9d4f5 |
| libcom-err2 | 1.46.5-2ubuntu1.2 | ubuntu | pool/main/e/e2fsprogs/ | 552bc8169451cfdcf174a8da845b13ced0a55777149af5cf47491193161ed791 | 3a7b6a2b34c2171b7c8f9ddae58c93b6e416fcd9ac4fa8eb5a15a1a8f3f99afa |
| libdb5.3 | 5.3.28+dfsg1-0.8ubuntu3 | ubuntu | pool/main/d/db5.3/ | ce60e446c9cb0e94bb4b4d0fe4f969e772edec250deb186bacf955e4d196548b | e5b672aeaca690b3b7ee97b03dbc07ddb49be7b6ea0a770fa6707666ca1cef59 |
| libffi8 | 3.4.2-4 | ubuntu | pool/main/libf/libffi/ | b4f88c91fa6f4c942097be6abfc365fb133c5e147640168cbb7704fd855eac10 | a0cdf938e8da19bd2252c681f80268609a32d06496a1f8d0ebe1fa41debec697 |
| libgcc-s1 | 12.3.0-1ubuntu1~22.04.3 | ubuntu | pool/main/g/gcc-12/ | d383e642d83263147f7b4b69fb92cf1036e5246c6be3accf10b77f986684589a | 46626e1af6b159061e055f843654ee1f0f1e65fa280331ed47ee76ba1b1f6045 |
| libgcrypt20 | 1.9.4-3ubuntu3.3 | ubuntu | pool/main/libg/libgcrypt20/ | 8f16329a0aabf4900271a3687890721bbef307e60983acae5b92eeff12e799b3 | bd98a709641e7e61c8798bb84030886a96fd56424b053a6e9996a8391ce20597 |
| libgmp10 | 2:6.2.1+dfsg-3ubuntu1 | ubuntu | pool/main/g/gmp/ | d199a77e11701d4d620dd4f62e05740e3072dce893856ea3bbaa6ae9fa19fef1 | 32233a3bf7c8b19e86ef3629334f0bece716bb163605d12e0d3a443d57a401d7 |
| libgnutls30 | 3.7.3-4ubuntu1.9 | ubuntu | pool/main/g/gnutls28/ | 65e08f0b5d1e620cc5cc9478cd1035f83ea752a6fae23141afd2d111a8f6c555 | cce4bf33fa79446ddee42a992e569f12a57c1a6f8916a2e8349249be0f7ad655 |
| libgpg-error0 | 1.43-3 | ubuntu | pool/main/libg/libgpg-error/ | 1fbacdf9bd1e431cee874a697b339f6f925182bc79bba5a112b53669b33265c5 | ffa9029cdeb2786e0db1f614f3d2205f75f466a66b25e22aa89ecdf814491875 |
| libgssapi-krb5-2 | 1.19.2-2ubuntu0.10 | ubuntu | pool/main/k/krb5/ | 08e98a3dc74361cdb13c0d68bc73e0352552490546c1ad3ce5bff5426f6a2dfe | e1001bffd91dd306498ec1824a8330014399a0e0889a562069003726348d7f55 |
| libhogweed6 | 3.7.3-1build2 | ubuntu | pool/main/n/nettle/ | 2402ac51ebc760799b01f3fd4933126c5eb446e5b043832601fb589f5e50c363 | 844e5d093dd3982a85c134d47a9e22b129123fb817eb3eea96e936805b0f5170 |
| libicu70 | 70.1-2 | ubuntu | pool/main/i/icu/ | 58a154f6307289813da2276f900498ef536ae7c0522d2cf31a3c3c5cf62dfd9a | ac68372cf4a976e6a206858fd9b28c68e49d37d650b9b8653270038a6e7bc174 |
| libidn2-0 | 2.3.2-2build1 | ubuntu | pool/main/libi/libidn2/ | bc935e1871aa4a75d3f4ff549af32b7316aecfbea2200d85055878767b8398c8 | aeb29cc8deedc0710a97e44088ef0271dfe1197e77c0a0fc0c5602e14aeb938f |
| libk5crypto3 | 1.19.2-2ubuntu0.10 | ubuntu | pool/main/k/krb5/ | 40429c0099678fbc35045f0c63a10bc3490251d80cf1006095eaa0272c8d5e27 | e51d72b346813b57f26c09827f96eb856adb9b553814fbc61a5e8c8a25d292a3 |
| libkeyutils1 | 1.6.1-2ubuntu3 | ubuntu | pool/main/k/keyutils/ | 940daf78ee0229549b4eabc92ffd79dd038ed96a44e2e912305a23540cf22a0a | fc26b34c487ea5187585ee0f2c67c738b97e8bae434cca4b546d86743b9e6c80 |
| libkrb5-3 | 1.19.2-2ubuntu0.10 | ubuntu | pool/main/k/krb5/ | 0da3e0df7d6314615160a42f65ff345986783be02cd65a6ce797cfbacc7bcb0d | 8de066e35be457bf0c53c995f8baa270ad61566dcd892d0a7cc3c0438ff513b7 |
| libkrb5support0 | 1.19.2-2ubuntu0.10 | ubuntu | pool/main/k/krb5/ | 0406052ac2d267f05088ada6d36df61aaa338cbe8d5e13fb1d7f79da560817ed | c535d5ccf5ea99fb63d86b33082c5ed553a6aa8c7cbf3fed1ef0dac1d7b7dcd6 |
| libldap-2.5-0 | 2.5.20+dfsg-0ubuntu0.22.04.1 | ubuntu | pool/main/o/openldap/ | a3ee4ac116a2c50c9ddfe9de91c0781a50704244771474334340cdce02f5cd4f | 305ec2bf85ad8e8a6309b1a48e601f172503a267ca90d511ccbb098cdf009d6b |
| liblz4-1 | 1.9.3-2build2 | ubuntu | pool/main/l/lz4/ | ac9b54d0feb840345060c74fb687675c5e1eb2b195effafae38c5f9991041e98 | 3e2274893e0963c758f0d18ba80d033736909373247a7deb211e9ff590a09133 |
| liblzma5 | 5.2.5-2ubuntu1.1 | ubuntu | pool/main/x/xz-utils/ | af77f099e7fa95a31267023535832804382fa66572a6b38002187be6e15116cb | 97f4c7e360aa229d3bf0a5b56b204652ce4f1704536dc0256c0e2537b356f397 |
| libnettle8 | 3.7.3-1build2 | ubuntu | pool/main/n/nettle/ | 6da09e685e5587f8873f662b007de45f75424fb33d2c4a51837380e683d33c7e | bcd667d9a51c2474f7ffc52807ab4a24f8b877b6da1a6f5b75e50e48ec4d634a |
| libnuma1 | 2.0.14-3ubuntu2 | ubuntu | pool/main/n/numactl/ | 0721c89001fbbd1ada23e89da5d60e762763c1a7b3dc814a2e9a518480a8043d | ca67a774b20ed639361715ef0981d236f294ff2987579b3d18faede67c3a9152 |
| libp11-kit0 | 0.24.0-6ubuntu0.1 | ubuntu | pool/main/p/p11-kit/ | 9d949950970a062a81051a78ec4075b8dba608f063afaa5c8752a612d139a9b5 | 0cfad0790be90ccb56de67e6c58a67d73e4769028eb19a2c0d799fa19478c2ff |
| libpam0g | 1.4.0-11ubuntu2.8 | ubuntu | pool/main/p/pam/ | faaf4b6d1bfb33a7fc4e195448439c202869d67c8de17c4ecd29b7719e0ac4d6 | f61ae0342dfba2b6c6b61f3d46925371434a4719a251f7585f9baa1341fcc9e2 |
| libpcre2-8-0 | 10.39-3ubuntu0.1 | ubuntu | pool/main/p/pcre2/ | 01a5a74f3d305cad32fffffdc200c2a92fd8e5a01bff97de76ac598fb444d53e | b85beefd54108f1c34a89cb26688eb1b2eeaa099e4995091295a1d39f9c67a91 |
| libreadline8 | 8.1.2-1 | ubuntu | pool/main/r/readline/ | 51fd16f608efa710c987e4b071ffba0bec63a9ac8e55eddd5770f5e5252edc09 | 54291f2dd185d3a759227b31b7de4269e495a084fdad89e24a9cc4d0d20888a7 |
| libsasl2-2 | 2.1.27+dfsg2-3ubuntu1.2 | ubuntu | pool/main/c/cyrus-sasl2/ | 391cb48d7e601d5bb590da8d426750acf6c987241ba280a36227873b94f20cee | d4f60677a0024f2b888a563f1d396a1f43fe22097e01d0a7048695c3c1ef8e18 |
| libsasl2-modules-db | 2.1.27+dfsg2-3ubuntu1.2 | ubuntu | pool/main/c/cyrus-sasl2/ | 0e222c26d70c2cfd132c8de035bcf9673067b6cbfea0a7421dced7b6256ae774 | 438df2296b2f828ab05287fadbf1a29f2e3bc0d618807b01128829313be91895 |
| libselinux1 | 3.3-1build2 | ubuntu | pool/main/libs/libselinux/ | b96c6b40ee2388bd51341cb11c0f1d5bcca29b9180b6e3a77a06b881f2913f7e | 3a0726b2174a40fa28e74712867aa6e40d3d725543e8f668af9e9e59a28c817c |
| libssl3 | 3.0.2-0ubuntu1.30 | ubuntu | pool/main/o/openssl/ | d1b4636e32ac6d3b95d583ac05ac548b1aa248414bae1c51b14f54be0f8fd7bc | 1c4b8cc736eed8a0caafc385f854fa6852382221d84be4795f1d19a52b9fec53 |
| libstdc++6 | 12.3.0-1ubuntu1~22.04.3 | ubuntu | pool/main/g/gcc-12/ | 29ef3d289b272704b75141906c8f683db0f2bdb0942061366691333bfb289bdc | 59d244119e6129c7e9c0897491c0e210e925d15881b2dedcf8965ceb4fbf1aa3 |
| libsystemd0 | 249.11-0ubuntu3.22 | ubuntu | pool/main/s/systemd/ | 4fae4644bcfd86f891faae12cedbf30aca280cf76a034768aec3a03fe42ddc25 | 9805c8c136fd41d9bff355297fdf6f811529960908711f647e38e1fd39a198ec |
| libtasn1-6 | 4.18.0-4ubuntu0.2 | ubuntu | pool/main/libt/libtasn1-6/ | a0903b4fae3ac2548a22d8822382e6d23586e42196d83ff67e82df36cd39fc6c | d9f0ed3ca0cb86f6116bb59388aea92b021c05797b4fba7451a2fed594cb1e1e |
| libtinfo6 | 6.3-2ubuntu0.3 | ubuntu | pool/main/n/ncurses/ | 3b8dff43a31168f5020928f2ab9a97324c5b47ae708311781f6bd01306c96214 | 971b5fd1cf8f7d68ba00f40d8eec6474fae6a6adbe19883aa42dd2b74c672e4a |
| libunistring2 | 1.0-1 | ubuntu | pool/main/libu/libunistring/ | 988fb59de6a0a313844277e8a6e45d3dc16f5ea75a603a46b16b936426f0ac65 | 59e4af5c1fac70d1fbc19f3c732331ace8449f1f7112887e7b56b8370bd8942b |
| liburing2 | 2.1-2build1 | ubuntu | pool/main/libu/liburing/ | f6e9bdf50c9683cd9a74ad92d51dde085f40baf0a5fcd8a56fc68425c1bd3c5f | a9221f0d47fd32819558f7a91677e97c72bd88646d38d369ffa70720ac49c27d |
| libuuid1 | 2.37.2-4ubuntu3.6 | ubuntu | pool/main/u/util-linux/ | 97eaa1090c2e7ddaad55d58f9d0d7907d64b70f89228405d68a7ce7d56a89d67 | 2478ccd8df956d8e5cf087bff1471bcd9991838be9c7999e5737d092034c492d |
| libxml2 | 2.9.13+dfsg-1ubuntu0.14 | ubuntu | pool/main/libx/libxml2/ | 16e395b2c52d6ab232053468febc69f0876956ec2fae357a941a2a8dab36574f | 1e85b731baabd51331d70a6392c652bc39fa2c231ff784555bd6a61631009387 |
| libxslt1.1 | 1.1.34-4ubuntu0.22.04.5 | ubuntu | pool/main/libx/libxslt/ | 5e50bc83e9365942cf63272d8a45ce71170aaf4a1a4e3c4b30f591f6194d77ef | dd533b9980918ca64531254ccbdfd5efc492bbef37c70f0b5559b3b8f306b626 |
| libzstd1 | 1.4.8+dfsg-3build1 | ubuntu | pool/main/libz/libzstd/ | ae7db00ce8b093e50c994518b90203544e063b4bc574836a048bb142b950b2c9 | 0102eb80384c2432c4be819663341a1c4e511d05f13ec1467643696531ec6491 |
| zlib1g | 1:1.2.11.dfsg-2ubuntu9.2 | ubuntu | pool/main/z/zlib/ | 9dc17e51a1be2d9ed63b7b84ef0e4e29c5abe6f1bc62cb03e7181483cce8a2f2 | cfd99d1ca41e710fdd3f68bfdc4d36dd24e14377656764f00b215b89cf6976e8 |
Debs per arch: 47 (3 PGDG + 44 Ubuntu); 30,428,248 bytes (amd64) and 29,440,882 bytes (arm64).
Index digests at pin time (signed InRelease of 2026-10-11): jammy-pgdg
main/binary-amd64/Packages.gz ca96279cfb8c49c2ac59dbdb083cb099223ad9e9f23313951eb8f715c5a1577c and
main/binary-arm64/Packages.gz 911dc4a3e960d5df5679e29fe7756c6d0eee1f9ffb79fbc0a5d8cd3735f8f32b.
Assembled trees (this spike's assembly; M1-ASSETS re-pins its own output):
| arch | raw bytes | zstd -19 bytes | sha256 of .tar.zst |
|---|---|---|---|
| amd64 | 84,342,619 (pg bin 15.8 M, pg lib 5.7 M, sys libs 61.0 M of which libicudata 29.5 M, share 1.9 M) | 25,654,278 | 467436b73669a7ca00ee3c5c44c468f892cabcf670dd529ebeeb99aeb63123fd |
| arm64 | 81,912,395 | 25,072,723 | 39847c32e8c7d71667ce33c5b625a96d0a3273cb0f1bcfc9f0c42545e4eb12b2 |
Size lever for M0-SIZE-BUDGET: ICU is 30 MB of the 84 MB, and the builtin provider does not use it. PGDG links it, though, so it cannot be dropped without the fallback build.
5. Measurements on hat-8 (uid 1000, arbitrary path, kine v0.17.1 /usr/local/bin/kine)
Harness: initdb, pg_ctl on a unix socket, psql, kine against the socket, an etcd v3 put+get through
kine (go.etcd.io/etcd/client/v3 v3.6.8), pg_dump, stop, port 0 attempt, then a leased TCP port.
Commands, PGDG tree (B=<root>/usr/lib/postgresql/18/bin, LD_LIBRARY_PATH=<root>/usr/lib/sys):
$B/initdb -D $T/data -U postgres --auth=trust -E UTF8 --locale-provider=builtin --builtin-locale=C.UTF-8
$B/pg_ctl -D $T/data -l $T/pg.log -w -o "-c listen_addresses='' -c unix_socket_directories='$T/run' -p 5432" start
$B/psql -h $T/run -U postgres -d postgres -Atc 'select 1'
kine --endpoint "postgres://postgres@localhost/kine?host=$T/run&sslmode=disable" --listen-address 127.0.0.1:0
$B/pg_dump -h $T/run -U postgres -d kine -f $T/kine.sql
$B/pg_ctl -D $T/data -m fast -w stop
$B/postgres -D $T/data -c listen_addresses=127.0.0.1 -c unix_socket_directories='' -p 0
| step | PGDG bundle (choice) | source build (fallback prototype) |
|---|---|---|
| initdb | 0.338 s | 0.266 s |
| pg_ctl start, unix socket only (no TCP listener: 0) | 0.109 s | 0.103 s |
first SELECT 1 after start returns | 0.009 s (0.123 s from start command) | 0.005 s (0.113 s) |
| kine on the socket | announced and bound 127.0.0.1:37867 (port 0) | 127.0.0.1:37055 |
| etcd put+get through kine | ok, rev 3, 4.7 ms | ok, rev 3, 5.2 ms |
| pg_dump of the kine db | 0.030 s, 3,385 bytes, has CREATE TABLE public.kine | 0.027 s, 3,329 bytes |
| pg_ctl stop -m fast | 0.102 s | 0.102 s |
-p 0 | refused: 0 is outside the valid range for parameter "port" (1 .. 65535) | same |
| leased TCP port | 33959 bound, read back from ss and postmaster.pid, inet_server_port()=33959 | 38745, same |
| RSS, postmaster tree idle (sum of VmRSS) | 101,736 kB | 56,812 kB |
| RSS, postmaster tree with kine connected | 183,752 kB | 118,668 kB |
| RSS, kine | 36,696 kB | 36,872 kB |
| fresh data dir | 66.3 MB | 48.6 MB |
Distro stand-ins (container images, uid 65534, --network none, tree bind-mounted read-only at
/opt/any/where/...): initdb + pg_ctl on a unix socket + SELECT 1 + pg_dump + stop all passed
for the PGDG bundle and for the source build on these images:
ubuntu:22.04@sha256:5ec03bb3441e8b0bf3b4f9cd4629a1ae763010dc3035bb8da3ae6cf026486401(glibc 2.35, no tzdata)ubuntu:24.04@sha256:534baea6a22c03a63003dbc8dbe78fe34bc0d7e595d9a9dc9834884ff530eb55(2.39, no tzdata)debian:12-slim@sha256:7c7b2c966bc9ee8cedfeef67e0e279108992c77681fa595db4a9d65c06ccc587(2.36)debian:13-slim@sha256:a29215f6a35e51e22adffa17f89e9d2ef06214e64a2bad10d765c46aea49f11f(2.41)fedora:44@sha256:43b29f65a41eb9c35e1cd5323e3bdf3b655c2357a9f4f1ff2f9c2798e5045d80(2.43)
On the images without tzdata, PGDG ran with TimeZone=UTC0 and refused SET timezone='UTC'. The
source build carries its own share/timezone and accepted UTC and Europe/Berlin everywhere.
arm64: the PGDG arm64 bundle passed the same test in debian:12-slim (linux/arm64) under hat-8's
qemu-aarch64 binfmt (uname -m = aarch64).
Without the bundle's libraries, the bare PGDG debs on hat-8 failed:
libldap-2.5.so.0: cannot open shared object file. libicu*.so.70 and libpq.so.5 were missing as
well. On minimal images, libnuma, liburing, libxml2, readline, krb5 and OpenSSL 3 were also
missing (debian:13 additionally lacked libgnutls30). That is why the bundle carries the whole
jammy closure.
6. Fallback: build from the official source tarball (status: prototyped, not committed)
Use only if the user rejects section 2's costs: the 44 Ubuntu pins, LD_LIBRARY_PATH, host tzdata,
25 MB zstd and 100 MB RSS. Measured prototype, copy kept at
$TASK_STATE_DIR/build-postgres.sh.fallback-prototype:
-
Source:
https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2, sha256555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f(matches the published.sha256; upstream publishes no PGP signature for source tarballs). -
Since PG 17 the tarball ships no generated parser, so the build host needs bison, flex and perl. The prototype builds pinned host tools with zig itself:
- m4-1.4.21: f25c6ab5...ab66, GPG Good, Eric Blake 71C2CC22B1C4602927D2F3AAA7A16B4A2527436A
- bison-3.8.2: 9bba0214...5bf2, GPG Good, Akim Demaille 7DF84374B1EE1F9764BBE25D0DDCAA3278D5264E
- flex-2.6.4: e87aae03...e995, GPG Good, Will Estes 56C67868E93390AA1039AD1CE4B29C8D64885307
-
Toolchain: zig 0.16.0, x86_64 sha256 70e49664a74374b48b51e6f3fdfbf437f6395d42509050588bd49abe52ba3d00, minisign Good with
RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U; aarch64 sha256 ea4b09bfb22ec6f6c6ceac57ab63efb6b46e17ab08d21f69f3a48b38e1534f17. It targets<arch>-linux-gnu.2.28, so the glibc floor is 2.28 regardless of build host, and it cross-compiles arm64 on hat-8 with no container, no qemu and no apt. -
Configure flags:
--prefix=/opt/postgresql --without-icu --without-readline --without-zlib --without-opensslplus every other optional library off. It is not--with-systemd. The make variablerpathdir='$$ORIGIN/../lib'gives RUNPATH$ORIGIN/../lib. The prefix contains "postgres", so pkglibdir = lib/ and sharedir = share/. -
Result: NEEDED only libc/libm/libpthread/libdl/librt, max GLIBC_2.27, own tzdata, no env vars.
arch raw zstd -19 build time on hat-8 amd64 16.2 MB 4,853,858 bytes 96-180 s arm64 - 4,380,281 bytes (cross) 206 s -
Not yet byte-reproducible: two amd64 runs in different work directories differed in
bin/postgres, because pg_config's compiled-in CC, CFLAGS and configure arguments embed the work path. The fix is a fixed build path. The dry-run test (--dry-runprints every pin) would be committed with the script.
7. Rejected candidates (facts recorded before the user ruled repackagers out)
- zonky
io.zonky.test.postgres:embedded-postgres-binaries-linux-{amd64,arm64v8}:18.6.0(Maven Central, jar sha256 amd64 008ee189eaa7ca2b58bd01dd950291e638b998392cf982297acd4779ec898ac1, arm64 5f54e016723afa6213925a8acb939bac52944b1d348f65c7a20f0cd2928c31be). Problems:- Only
initdb pg_ctl postgres: no pg_dump and no psql. - Bundles EOL OpenSSL 1.1 and ICU 60.
- The maven
.ascis signed by key 6B02ED0ED53F9FD3, which is not retrievable from keyserver.ubuntu.com or keys.openpgp.org, so it is unverifiable.
- Only
- theseus-rs
postgresql-18.6.0-{x86_64,aarch64}-unknown-linux-gnu.tar.gz(sha256 bb3d09f8...ca61 and 5d2b5e8b...ee13). Problems:- Only a same-channel
.sha256. GitHub attestation API returns 404. - Built on Debian 12 gcc 12 with
--without-icu --with-system-tzdata. - Links host libssl3, libxml2, krb5, lz4, zstd and readline (not bundled).
- The musl variants need a musl host.
- Only a same-channel
8. Proposed internal/versions/versions.json entry (the lead edits the file)
"postgres": {
"version": "18.6",
"how": "PGDG official debs (apt.postgresql.org jammy-pgdg 18.6-1.pgdg22.04+2: postgresql-18, postgresql-client-18, libpq5) plus their Ubuntu 22.04 shared-library closure (44 debs from jammy, jammy-updates, jammy-security), each verified by signed InRelease -> Packages.gz sha256 -> deb sha256, extracted without root (ar + tar) into <root>/usr/lib/postgresql/18/{bin,lib}, <root>/usr/share/postgresql/18, <root>/usr/lib/sys; see docs/research/2026-10-11-vm-lifecycle/pg-source.md for the 47 per-arch deb pins",
"pgdgKeyFingerprint": "B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8",
"ubuntuArchiveKeyFingerprint": "F6ECB3762474EDA9D21B7022871920D1991BC93C",
"debs": {
"linux/amd64": {"postgresql-18": "2aab00b13babd3d9abc257bc5f6b00efa1f7c27cda071413f358d2e0cdb84420", "postgresql-client-18": "ad4e491adceaf1453162c62691473ace78ed81ab20f50d11b344a793d13ed4bd", "libpq5": "8af0b458834e219f3aa7c904fa1237ea484950486e3165a3a90204878e060530"},
"linux/arm64": {"postgresql-18": "8a379f0684b480b60e79657ac8178e8b00c835e7575e85ae746c091d336563d3", "postgresql-client-18": "21f1b418621fc9c90785b18ec2d7fe4fd8ff111cc607fc3b3625464fc6e7886b", "libpq5": "fc0d787c9da82bd0146e5e365989f3c92dbb3d73c3a32c62a2e4d56ab90933a6"}
},
"glibcFloor": "2.35",
"icu": "70.1 (unicode collversion 153.112; unused: initdb --locale-provider=builtin --builtin-locale=C.UTF-8, datcollversion 1)",
"invariant": "Relocatable ONLY with the deb layout kept (<root>/usr/lib/postgresql/18/bin; PostgreSQL resolves share and pkglib relative to that tail) and LD_LIBRARY_PATH=<root>/usr/lib/sys set on the postgres/initdb/pg_dump exec alone, never on the core (it leaks jammy libs into any child: grep under it loaded jammy libpcre2). Timezone files are the HOST's /usr/share/zoneinfo (compiled-in absolute path): check-host requires /usr/share/zoneinfo/UTC. postgres REFUSES -p 0 (GUC minimum 1): the kcp store is unix-socket only (listen_addresses=''), tenant stores lease. Runs as non-root only. Any Ubuntu jammy security update changes the closure pins."
}
Replace the existing embedded-postgres entry ("the host's own binaries ... on PATH") when
M2-POSTGRES lands. Its port and root invariants still hold.