-
-
Notifications
You must be signed in to change notification settings - Fork 259
Expand file tree
/
Copy pathDockerfile-multigres
More file actions
134 lines (113 loc) · 6.17 KB
/
Copy pathDockerfile-multigres
File metadata and controls
134 lines (113 loc) · 6.17 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
# syntax=docker/dockerfile:1.4
# 1.4: minimum version for heredoc support in RUN (used for nix config below); also covers COPY --chmod (1.2+)
# Multigres PostgreSQL image — layered on top of the supabase base image.
#
# Put all ARGs up top for better discoverability.
# Use non-versioned `ARG THE_ARG` in the stage that uses it to get the ref to this one.
#
# The supabase image must be built first:
# docker build -f Dockerfile-supabase -t supabase-postgres:17 .
# docker build -f Dockerfile-multigres -t multigres:17 .
#
# Override the base image at build time:
# docker build -f Dockerfile-multigres \
# --build-arg SUPABASE_IMAGE=registry.example.com/supabase-postgres:17 \
# -t multigres:17 .
ARG ALPINE_VERSION=3.23
ARG GOLANG_VERSION=1.26
ARG PGCTLD_REV=b713432298450dd0095498193e86d9f9a9f2c348
ARG SUPABASE_IMAGE=supabase-postgres:17
####################
# Stage 1: pgBackRest nix builder
####################
FROM alpine:${ALPINE_VERSION} AS pgbackrest-builder
RUN apk add --no-cache \
bash \
coreutils \
curl \
shadow \
sudo \
xz
RUN cat >/tmp/extra-nix.conf <<EOF
extra-experimental-features = nix-command flakes
extra-substituters = https://nix-postgres-artifacts.s3.amazonaws.com
extra-trusted-public-keys = nix-postgres-artifacts:dGZlQOvKcNEjvT7QEAJbcV6b6uk7VF/hWMjhYleiaLI=
EOF
RUN curl -L https://releases.nixos.org/nix/nix-2.34.6/install | sh -s -- --daemon --no-channel-add --yes --nix-extra-conf-file /tmp/extra-nix.conf
ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"
WORKDIR /nixpg
COPY flake.nix flake.lock ./
COPY nix/ ./nix/
RUN nix profile add path:.#pg-backrest && \
nix store gc && \
readlink -f /nix/var/nix/profiles/default/bin/pgbackrest > /pgbackrest-store-path
####################
# Stage 2: pgctld builder
####################
FROM golang:${GOLANG_VERSION}-alpine AS pgctld-builder
ARG PGCTLD_REV
RUN apk add --no-cache git
RUN git clone https://github.com/multigres/multigres.git /multigres && \
cd /multigres && \
git checkout ${PGCTLD_REV} && \
# Copy pico CSS assets before build (mirrors pgctld.nix preBuild step)
cp external/pico/pico.* go/common/web/templates/css/ 2>/dev/null || true && \
CGO_ENABLED=0 go build -ldflags="-s -w" -o /usr/local/bin/pgctld ./go/cmd/pgctld
####################
# Stage 3: Multigres image
####################
# SUPABASE_IMAGE is set by the release workflow via --build-arg, derived from
# PG_VERSION and the release matrix in ansible/vars.yml.
FROM ${SUPABASE_IMAGE} AS production
# Merge pgBackRest nix store closure into the inherited /nix/store, then symlink the binary.
# We copy only the store (not the profile) to avoid clobbering the supabase image's profile.
COPY --from=pgbackrest-builder /nix/store /nix/store
COPY --from=pgbackrest-builder /pgbackrest-store-path /pgbackrest-store-path
RUN ln -sf "$(cat /pgbackrest-store-path)" /usr/local/bin/pgbackrest && \
rm /pgbackrest-store-path
# Copy pgctld binary; keep it separate so the wrapper script can reference it cleanly
COPY --from=pgctld-builder /usr/local/bin/pgctld /usr/local/bin/pgctld-bin
# pgctld config template — /etc/pgctld is a mount point in k8s so use a custom dir
COPY docker/pgctld/postgresql.conf.tmpl /etc/pgctld-custom/postgresql.conf.tmpl
# Pre-init SQL: creates the postgres superuser before supabase init scripts run.
# docker-entrypoint.sh does this automatically; pgctld init does not.
COPY docker/pgctld/pre-init/ /etc/pgctld-custom/pre-init/
# Multigres-specific migration fixups: equivalents of Ansible after-create hooks
# (extension ownership, not run automatically in Docker).
# Filename sorts after 00-extension.sql so pg_stat_statements exists first.
COPY docker/pgctld/multigres-migrations/ /docker-entrypoint-initdb.d/migrations/
# Wrapper: injects --postgres-config-template on every pgctld call so unmodified
# k8s manifests and local provisioner commands work without extra flags
COPY --chmod=0755 docker/pgctld/pgctld-layered.sh /usr/local/bin/pgctld
# The supabase base config /etc/postgresql/postgresql.conf IS loaded in Multigres:
# the operator's --pg-initdb-extra-conf appends `include = '/etc/postgresql/postgresql.conf'`
# onto pgctld's generated config. It therefore must not carry settings that assume the
# base image's `postgres -D /etc/postgresql` layout, so we neutralize two here:
#
# - data_directory = '/var/lib/postgresql/data' would override pgctld's -D/PGDATA and
# redirect PostgreSQL off the freshly-initdb'd <pooler-dir>/pg_data to the base image's
# empty dir, which fails startup ("data directory ... has invalid permissions") and
# leaves the pooler stuck retrying the first backup forever. pgctld pins the data dir
# via -D, so comment it out (matching the pre-layered image, which shipped it disabled).
# - the wal-g include is dangling (wal-g is unused in Multigres; pgbackrest handles
# backups), so delete it and its now-orphaned files.
RUN sed -i \
-e "s|^data_directory = '/var/lib/postgresql/data'|#data_directory = '/var/lib/postgresql/data'|" \
-e "/^include = '\/etc\/postgresql-custom\/wal-g.conf'/d" \
/etc/postgresql/postgresql.conf && \
rm -f /etc/postgresql-custom/wal-g.conf /home/postgres/wal_fetch.sh /root/wal_change_ownership.sh
# pgctld uses pooler-dir for pgBackRest config, unix sockets, and state files.
RUN mkdir -p /var/lib/pgctld && chown postgres:postgres /var/lib/pgctld
# No HEALTHCHECK defined here: inherits the probe from the supabase base image.
# Kubernetes ignores Docker HEALTHCHECK entirely — use readinessProbe in the Pod spec.
# STOPSIGNAL inherited from supabase base image (SIGINT — smart shutdown).
USER postgres
# pgctld is the cluster lifecycle manager for Multigres: it handles initdb,
# config templating, replication setup, and coordinated restarts. Running it
# as PID 1 ensures it receives stop signals directly and can shut down
# PostgreSQL cleanly before the container exits.
ENTRYPOINT ["/usr/local/bin/pgctld"]
# "server" is pgctld's daemon mode: auto-inits PGDATA if empty, starts PostgreSQL,
# and runs as a gRPC lifecycle server. The wrapper injects --postgres-config-template
# and --pg-initdb-sql-dirs; the CMD provides the subcommand and pooler-dir.
CMD ["server", "--pooler-dir", "/var/lib/pgctld"]