Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
206 lines (183 loc) · 9.92 KB
/
Copy pathDockerfile
File metadata and controls
206 lines (183 loc) · 9.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# syntax=docker/dockerfile:1
#
# Drop-in replacement for the official `postgres` Docker image
# (docker-library/postgres), backed by the pgrust `postgres` binary (a Rust port
# of PostgreSQL 18.3) instead of C postgres.
#
# Anyone can swap `postgres` -> `pgrust` in their `docker run` / compose and get
# the same contract: POSTGRES_PASSWORD / POSTGRES_USER / POSTGRES_DB /
# POSTGRES_INITDB_ARGS / POSTGRES_HOST_AUTH_METHOD / PGDATA env vars,
# /docker-entrypoint-initdb.d first-init scripts, PGDATA at
# /var/lib/postgresql/data (declared a VOLUME), the `postgres` unix user (uid
# 999), the /var/run/postgresql socket dir, EXPOSE 5432, STOPSIGNAL SIGINT,
# ENTRYPOINT ["docker-entrypoint.sh"], CMD ["postgres"], and gosu step-down.
#
# The substitution: BOTH the user-facing SERVER and the catalog bootstrap
# (`initdb`) are the pgrust binary — pgrust's own `--initdb` driver (a faithful
# port of initdb.c) now does the bootstrap. The only C tool left is `psql`, the
# init-script / healthcheck client (pgrust has no psql replacement); it comes
# from the bundled PostgreSQL 18 PGDG client package. No C `postgres` backend and
# no C `initdb` are present in the final image.
#
# Three stages:
# 1. rustbuild — builds the pgrust `postgres` binary. `nodetags.h` is vendored
# (crates/_support/types/nodes/vendor/nodetags.h), so this stage
# needs no PostgreSQL source — just Rust + libicu-dev.
# 2. pgtools — harvests C psql + libpq from the PGDG client package, plus the
# PostgreSQL share tree (postgres.bki, system_*.sql,
# system_views.sql, information_schema.sql, sql_features.txt,
# snowball_create.sql, config samples, tz data) that pgrust's
# --initdb / --boot read. NO C postgres backend, NO C initdb, NO
# bootstrap loadable modules.
# 3. final — official-postgres-compatible runtime.
#
# Build: docker build -t pgrust .
# Run: docker run --rm -e POSTGRES_PASSWORD=secret -p 5432:5432 pgrust
# psql + libpq are kept at their PGDG-native paths in the final image; the share
# tree is kept at its PGDG-native path too (PG_SHAREDIR) because the pgrust
# binary's baked-in PGRUST_PGSHAREDIR points there for the tz tree, and the
# entrypoint passes it to `--initdb` via `-L`.
ARG PG_MAJOR=18
ARG PG_LIBROOT=/usr/lib/postgresql/18
ARG PG_SHAREDIR=/usr/share/postgresql/18
# ---------------------------------------------------------------------------
# Stage 1: build the pgrust `postgres` binary (self-contained — vendored nodetags.h)
# ---------------------------------------------------------------------------
FROM rust:1-bookworm AS rustbuild
ARG PG_SHAREDIR
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential pkg-config libicu-dev libldap2-dev libpam0g-dev libssl-dev \
&& rm -rf /var/lib/apt/lists/*
# Bake the runtime share dir (timezone/timezonesets) location into the binary so
# it resolves the tz tree shipped in the final image.
ENV PGRUST_PGSHAREDIR=${PG_SHAREDIR}
# Dedicated target dir, off the source tree.
ENV CARGO_TARGET_DIR=/build/target
WORKDIR /src
COPY . /src
RUN cargo build --release --locked --bin postgres \
&& cp /build/target/release/postgres /opt/pgrust-postgres
# ---------------------------------------------------------------------------
# Stage 2: obtain psql + libpq + the share tree from PGDG
# ---------------------------------------------------------------------------
FROM debian:bookworm-slim AS pgtools
ARG PG_LIBROOT
ARG PG_SHAREDIR
ENV DEBIAN_FRONTEND=noninteractive
# Add the PGDG apt repo and install the PostgreSQL 18 server + client packages.
# We need the CLIENT package for psql + libpq, and the SERVER package only for
# its share/ tree (postgres.bki, system_*.sql, system_views.sql,
# information_schema.sql, sql_features.txt, snowball_create.sql, config samples)
# — pgrust's --initdb / --boot read those. The server package's binaries and
# loadable modules are NOT copied into the final image.
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates gnupg wget \
&& install -d /usr/share/postgresql-common/pgdg \
&& wget -qO /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \
https://www.postgresql.org/media/keys/ACCC4CF8.asc \
&& echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" \
> /etc/apt/sources.list.d/pgdg.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
postgresql-18 postgresql-client-18 \
&& rm -rf /var/lib/apt/lists/*
# Stage the C tools the final image keeps (psql only) into a clean bin dir,
# verify the share files pgrust's --initdb needs are present, and gather the
# non-glibc shared libs psql pulls in (libpq, libldap, ...) into a single dir we
# can copy wholesale. The C `postgres` backend, C `initdb`, and the bootstrap
# loadable modules are deliberately left behind.
RUN set -eux; \
test -x "${PG_LIBROOT}/bin/psql"; \
test -f "${PG_SHAREDIR}/postgres.bki"; \
test -f "${PG_SHAREDIR}/system_constraints.sql"; \
test -f "${PG_SHAREDIR}/system_functions.sql"; \
test -f "${PG_SHAREDIR}/system_views.sql"; \
test -f "${PG_SHAREDIR}/information_schema.sql"; \
test -f "${PG_SHAREDIR}/sql_features.txt"; \
test -f "${PG_SHAREDIR}/snowball_create.sql"; \
test -f "${PG_SHAREDIR}/pg_hba.conf.sample"; \
test -f "${PG_SHAREDIR}/postgresql.conf.sample"; \
test -f "${PG_SHAREDIR}/pg_ident.conf.sample"; \
mkdir -p /opt/pgbin /opt/runlibs; \
cp -L "${PG_LIBROOT}/bin/psql" /opt/pgbin/psql; \
ldd "${PG_LIBROOT}/bin/psql" | awk '/=> \//{print $3}' \
| sort -u | while read -r so; do \
case "$so" in /lib/*|/usr/lib/*) cp -L "$so" /opt/runlibs/ || true;; esac; \
done
# ---------------------------------------------------------------------------
# Stage 3: runtime image — drop-in compatible with the official postgres image
# ---------------------------------------------------------------------------
FROM debian:bookworm-slim AS final
ARG PG_MAJOR
ARG PG_LIBROOT
ARG PG_SHAREDIR
ENV DEBIAN_FRONTEND=noninteractive
# The "postgres" user/group with uid/gid 999, exactly like the official image —
# so a host mounting the data volume sees identical ownership.
RUN set -eux; \
groupadd -r postgres --gid=999; \
useradd -r -g postgres --uid=999 --home-dir=/var/lib/postgresql --shell=/bin/bash postgres; \
install --verbose --directory --owner postgres --group postgres --mode 1777 /var/lib/postgresql
# Runtime packages:
# libicu72 — linked directly by the pgrust binary (ICU collation provider)
# libxml2 — linked directly by the pgrust binary (xml type support)
# tzdata — system zoneinfo (Debian PG is --with-system-tzdata)
# locales — en_US.utf8 (matches the official image's LANG)
# gosu — root -> postgres step-down (Debian package, like upstream)
# xz-utils/zstd/gzip — decompress *.sql.{xz,zst,gz} init scripts
# (the official image's libnss-wrapper is NOT needed here: only C initdb
# consulted /etc/passwd; pgrust initdb takes the superuser name from --username.)
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
libicu72 libxml2 tzdata locales xz-utils zstd gzip \
libldap-2.5-0 libpam0g libssl3 \
gosu \
; \
rm -rf /var/lib/apt/lists/*; \
# verify gosu works (and that the "nobody" user resolves) like the official image \
gosu nobody true; \
localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 || true
ENV LANG=en_US.utf8
ENV PG_MAJOR=${PG_MAJOR}
# The pgrust binary. This IS both the user-facing server and the catalog
# bootstrap driver (`pgrust-postgres --initdb`). It is named `pgrust-postgres`;
# the entrypoint always launches it by this absolute path.
COPY --from=rustbuild /opt/pgrust-postgres /usr/local/bin/pgrust-postgres
# psql — the only C tool retained (init-script / healthcheck client; pgrust has
# no psql replacement). Placed on PATH at the PGDG-native bin location.
COPY --from=pgtools /opt/pgbin/psql ${PG_LIBROOT}/bin/psql
# The PostgreSQL share tree: tz data + the initdb bootstrap templates
# (postgres.bki, system_*.sql, system_views.sql, information_schema.sql,
# sql_features.txt, snowball_create.sql, config samples) that pgrust --initdb /
# --boot read.
COPY --from=pgtools ${PG_SHAREDIR} ${PG_SHAREDIR}
# The non-glibc shared libs psql links (libpq, libldap, ...).
COPY --from=pgtools /opt/runlibs /opt/runlibs
ENV PATH=${PG_LIBROOT}/bin:$PATH
ENV LD_LIBRARY_PATH=/opt/runlibs
# pgrust's --initdb passes this to its --boot/--single phases via `-L`, and the
# binary's baked-in PGRUST_PGSHAREDIR points here too.
ENV PG_SHAREDIR=${PG_SHAREDIR}
# Debian's PostgreSQL is built --with-system-tzdata, so the package share dir
# ships NO `timezone/` subtree. The pgrust binary looks for
# ${PGRUST_PGSHAREDIR}/timezone, so point it at the system tzdata.
RUN test -d /usr/share/zoneinfo \
&& ln -snf /usr/share/zoneinfo "${PG_SHAREDIR}/timezone"
# Official-image data dir + socket dir conventions.
ENV PGDATA=/var/lib/postgresql/data
RUN install --verbose --directory --owner postgres --group postgres --mode 1777 /var/lib/postgresql/data
RUN mkdir -p /var/run/postgresql && chown -R postgres:postgres /var/run/postgresql && chmod 3777 /var/run/postgresql
# The entrypoint, installed under the official name so `docker-entrypoint.sh` on
# PATH works for users who reference it explicitly.
COPY docker/entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN ln -snf /usr/local/bin/docker-entrypoint.sh /docker-entrypoint.sh # backwards compat
# First-init scripts dir (official image convention).
RUN mkdir -p /docker-entrypoint-initdb.d
VOLUME /var/lib/postgresql/data
EXPOSE 5432
STOPSIGNAL SIGINT
ENTRYPOINT ["docker-entrypoint.sh"]
# Default: run the server (the entrypoint rewrites this to the pgrust binary).
CMD ["postgres"]