-
-
Notifications
You must be signed in to change notification settings - Fork 257
Expand file tree
/
Copy pathDockerfile-supabase
More file actions
224 lines (188 loc) · 9.68 KB
/
Copy pathDockerfile-supabase
File metadata and controls
224 lines (188 loc) · 9.68 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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# syntax=docker/dockerfile:1.4
# 1.4: minimum version for heredoc support in RUN (used for nix config below)
# Supabase PostgreSQL image with Nix extensions — parameterised by major version.
#
# Build (defaults to PostgreSQL 17):
# docker build -f Dockerfile-supabase -t supabase-postgres:17 .
#
# Build for a different PostgreSQL version:
# docker build -f Dockerfile-supabase --build-arg PG_VERSION=15 -t supabase-postgres:15 .
# Put all ARGs up top for better discoverability
# Use non-versioned `ARG THE_ARG` in the layer that uses it to get the ref to this one
ARG ALPINE_VERSION=3.23
ARG GO_VERSION=1.26.1
ARG GOSU_VERSION=1.19
ARG PG_VERSION=17
####################
# Stage 1: Nix builder
####################
FROM alpine:${ALPINE_VERSION} AS nix-builder
ARG PG_VERSION
# Install dependencies for nix installer (coreutils for GNU cp, sudo for installer)
RUN apk add --no-cache \
bash \
coreutils \
curl \
shadow \
sudo \
xz
# Create users (Alpine syntax)
RUN addgroup -S postgres && \
adduser -S -h /var/lib/postgresql -s /bin/bash -G postgres postgres && \
addgroup -S wal-g && \
adduser -S -s /bin/bash -G wal-g wal-g
# Create nix config
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"
RUN nix --version
WORKDIR /nixpg
COPY . .
# Build PostgreSQL with extensions
RUN nix profile add path:.#psql_${PG_VERSION}_slim/bin
RUN nix store gc
# Build groonga and copy plugins
RUN nix profile add path:.#supabase-groonga && \
mkdir -p /tmp/groonga-plugins && \
cp -r /nix/var/nix/profiles/default/lib/groonga/plugins /tmp/groonga-plugins/
RUN nix store gc
####################
# Stage 2: Gosu builder
####################
FROM alpine:${ALPINE_VERSION} AS gosu-builder
ARG TARGETARCH
ARG GO_VERSION
ARG GOSU_VERSION
RUN apk add --no-cache curl git
# Install Go
RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz" | tar -C /usr/local -xz
ENV PATH="/usr/local/go/bin:${PATH}"
# Build gosu from source
RUN git clone --depth 1 --branch "${GOSU_VERSION}" https://github.com/tianon/gosu.git /gosu && \
cd /gosu && \
CGO_ENABLED=0 go build -ldflags="-s -w" -o /usr/local/bin/gosu . && \
chmod +x /usr/local/bin/gosu
####################
# Stage 3: Final production image
####################
FROM alpine:${ALPINE_VERSION} AS production
ARG PG_VERSION
# Install minimal runtime dependencies
RUN apk add --no-cache \
bash \
curl \
shadow \
su-exec \
tzdata \
musl-locales \
musl-locales-lang \
&& rm -rf /var/cache/apk/*
# Create postgres user/group
RUN addgroup -S postgres && \
adduser -S -G postgres -h /var/lib/postgresql -s /bin/bash postgres && \
addgroup -S wal-g && \
adduser -S -G wal-g -s /bin/bash wal-g && \
adduser postgres wal-g
# Copy Nix store and profiles from builder (profile already created by nix profile install)
COPY --from=nix-builder /nix /nix
# Copy groonga plugins
COPY --from=nix-builder /tmp/groonga-plugins/plugins /usr/lib/groonga/plugins
# Copy gosu
COPY --from=gosu-builder /usr/local/bin/gosu /usr/local/bin/gosu
# Setup PostgreSQL directories
RUN mkdir -p /usr/lib/postgresql/bin \
/usr/lib/postgresql/share/postgresql \
/usr/share/postgresql \
/var/lib/postgresql/data \
/var/run/postgresql \
&& chown -R postgres:postgres /usr/lib/postgresql \
&& chown -R postgres:postgres /var/lib/postgresql \
&& chown -R postgres:postgres /usr/share/postgresql \
&& chown -R postgres:postgres /var/run/postgresql
# Create symbolic links for binaries
RUN for f in /nix/var/nix/profiles/default/bin/*; do \
ln -sf "$f" /usr/lib/postgresql/bin/ 2>/dev/null || true; \
ln -sf "$f" /usr/bin/ 2>/dev/null || true; \
done
# Create symbolic links for PostgreSQL shares
RUN ln -sf /nix/var/nix/profiles/default/share/postgresql/* /usr/lib/postgresql/share/postgresql/ 2>/dev/null || true && \
ln -sf /nix/var/nix/profiles/default/share/postgresql/* /usr/share/postgresql/ 2>/dev/null || true && \
ln -sf /usr/lib/postgresql/share/postgresql/timezonesets /usr/share/postgresql/timezonesets 2>/dev/null || true
# Set permissions
RUN chown -R postgres:postgres /usr/lib/postgresql && \
chown -R postgres:postgres /usr/share/postgresql
# Setup configs
COPY --chown=postgres:postgres ansible/files/postgresql_config/postgresql.conf.j2 /etc/postgresql/postgresql.conf
COPY --chown=postgres:postgres ansible/files/postgresql_config/pg_hba.conf.j2 /etc/postgresql/pg_hba.conf
COPY --chown=postgres:postgres ansible/files/postgresql_config/pg_ident.conf.j2 /etc/postgresql/pg_ident.conf
COPY --chown=postgres:postgres ansible/files/postgresql_config/conf.d /etc/postgresql/postgresql.conf.d
COPY --chown=postgres:postgres ansible/files/postgresql_config/postgresql-stdout-log.conf /etc/postgresql/logging.conf
COPY --chown=postgres:postgres ansible/files/postgresql_config/supautils.conf.j2 /etc/postgresql-custom/supautils.conf
COPY --chown=postgres:postgres ansible/files/postgresql_extension_custom_scripts /etc/postgresql-custom/extension-custom-scripts
COPY --chown=postgres:postgres ansible/files/pgsodium_getkey_urandom.sh.j2 /usr/lib/postgresql/bin/pgsodium_getkey.sh
COPY --chown=postgres:postgres ansible/files/postgresql_config/custom_walg.conf /etc/postgresql-custom/wal-g.conf
COPY --chown=postgres:postgres ansible/files/postgresql_config/custom_read_replica.conf /etc/postgresql-custom/read-replica.conf
COPY --chown=postgres:postgres ansible/files/walg_helper_scripts/wal_fetch.sh /home/postgres/wal_fetch.sh
COPY ansible/files/walg_helper_scripts/wal_change_ownership.sh /root/wal_change_ownership.sh
# Configure PostgreSQL settings
RUN sed -i \
-e "s|#unix_socket_directories = '/tmp'|unix_socket_directories = '/var/run/postgresql'|g" \
-e "s|#session_preload_libraries = ''|session_preload_libraries = 'supautils'|g" \
-e "s|#include = '/etc/postgresql-custom/supautils.conf'|include = '/etc/postgresql-custom/supautils.conf'|g" \
-e "s|#include = '/etc/postgresql-custom/wal-g.conf'|include = '/etc/postgresql-custom/wal-g.conf'|g" /etc/postgresql/postgresql.conf && \
echo "pgsodium.getkey_script= '/usr/lib/postgresql/bin/pgsodium_getkey.sh'" >> /etc/postgresql/postgresql.conf && \
echo "vault.getkey_script= '/usr/lib/postgresql/bin/pgsodium_getkey.sh'" >> /etc/postgresql/postgresql.conf && \
chown -R postgres:postgres /etc/postgresql-custom && \
ln -s /etc/postgresql/postgresql.conf.d /etc/postgresql-custom/conf.d
# pg17+ does not ship timescaledb or plv8; db_user_namespace was removed in pg17.
# Applied conditionally so the same Dockerfile works for pg15 (where these are valid).
RUN if [ "${PG_VERSION}" -ge 17 ]; then \
sed -i 's/ timescaledb,//g; s/ plv8,//g' /etc/postgresql/postgresql.conf && \
sed -i 's/db_user_namespace = off/#db_user_namespace = off/g' /etc/postgresql/postgresql.conf && \
sed -i 's/ timescaledb,//g; s/ plv8,//g' /etc/postgresql-custom/supautils.conf; \
fi
# Include schema migrations
COPY migrations/db /docker-entrypoint-initdb.d/
COPY ansible/files/pgbouncer_config/pgbouncer_auth_schema.sql /docker-entrypoint-initdb.d/init-scripts/00-schema.sql
COPY ansible/files/stat_extension.sql /docker-entrypoint-initdb.d/migrations/00-extension.sql
# Add entrypoint script from the official postgres Docker library (version-matched)
ADD --chmod=0755 \
https://raw.githubusercontent.com/docker-library/postgres/6edb0a8c4def40c371514b34aef9037ec82d9110/${PG_VERSION}/alpine3.23/docker-entrypoint.sh \
/usr/local/bin/docker-entrypoint.sh
# Setup pgsodium key script
RUN mkdir -p /usr/share/postgresql/extension/ && \
ln -s /usr/lib/postgresql/bin/pgsodium_getkey.sh /usr/share/postgresql/extension/pgsodium_getkey && \
chmod +x /usr/lib/postgresql/bin/pgsodium_getkey.sh
# Environment variables
ENV PATH="/nix/var/nix/profiles/default/bin:/usr/lib/postgresql/bin:${PATH}"
ENV PGDATA=/var/lib/postgresql/data
ENV POSTGRES_HOST=/var/run/postgresql
ENV POSTGRES_USER=supabase_admin
ENV POSTGRES_DB=postgres
ENV POSTGRES_INITDB_ARGS="--allow-group-access --locale-provider=icu --encoding=UTF-8 --icu-locale=en_US.UTF-8"
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8
ENV GRN_PLUGINS_DIR=/usr/lib/groonga/plugins
# Point to minimal glibc locales included in slim Nix package for initdb locale support
ENV LOCALE_ARCHIVE=/nix/var/nix/profiles/default/lib/locale/locale-archive
# Marks the container unhealthy after 10 failed pg_isready probes, which blocks
# dependent services in Docker Compose (depends_on: condition: service_healthy).
# Kubernetes ignores Docker HEALTHCHECK entirely — use readinessProbe in the Pod spec.
HEALTHCHECK --interval=2s --timeout=2s --retries=10 CMD pg_isready -U postgres -h localhost
# SIGINT triggers PostgreSQL smart shutdown: waits for active sessions to finish
# before stopping. This avoids interrupting in-flight transactions but can delay
# pod termination if long-running queries are active.
# Consider SIGTERM (fast shutdown) to disconnect clients immediately, which
# respects Kubernetes terminationGracePeriodSeconds more predictably.
STOPSIGNAL SIGINT
EXPOSE 5432
# No USER directive: the entrypoint starts as root to fix volume ownership and
# set up permissions, then drops to the postgres user via gosu before exec'ing
# the postgres process. This follows the standard official PostgreSQL image pattern.
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["postgres", "-D", "/etc/postgresql"]