Skip to content

Commit cb68169

Browse files
authored
Upgrade encore image to PSQL 18 (#11)
1 parent 6b6a2e1 commit cb68169

4 files changed

Lines changed: 214 additions & 17 deletions

File tree

.github/workflows/cd.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@ on:
1414
jobs:
1515
publish-docker-images:
1616
name: "publish docker images"
17-
runs-on: ubuntu-20.04
17+
runs-on: ubuntu-24.04
1818

1919
steps:
20-
- uses: actions/checkout@v3
20+
- uses: actions/checkout@v4
2121

2222
- name: Setup Docker Buildx
23-
uses: docker/setup-buildx-action@v1
23+
uses: docker/setup-buildx-action@v3
2424

2525
- name: Login to Docker Registry
26-
uses: docker/login-action@v2
26+
uses: docker/login-action@v3
2727
with:
2828
username: ${{ secrets.DOCKERHUB_USERNAME }}
2929
password: ${{ secrets.DOCKERHUB_TOKEN }}
3030

3131
- name: Cache Docker layers
32-
uses: actions/cache@v2
32+
uses: actions/cache@v4
3333
with:
3434
path: /tmp/.buildx-cache
3535
key: ${{ runner.os }}-buildx-${{ github.sha }}
@@ -38,7 +38,7 @@ jobs:
3838
3939
- name: Extract metadata (tags, labels) for Docker
4040
id: meta
41-
uses: docker/metadata-action@v4
41+
uses: docker/metadata-action@v5
4242
with:
4343
images: encoredotdev/postgres
4444
labels: |
@@ -54,7 +54,7 @@ jobs:
5454
type=ref,event=pr
5555
5656
- name: Build and push
57-
uses: docker/build-push-action@v4
57+
uses: docker/build-push-action@v6
5858
with:
5959
context: .
6060
platforms: linux/amd64,linux/arm64

Dockerfile

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This file is inspired by github.com/neondatabase/neon's docker file.
22

3-
ARG PG_MAJOR=15
3+
ARG PG_MAJOR=18
44
ARG EXTENSION_DIR=/usr/share/postgresql/${PG_MAJOR}/extension
55
ARG INCLUDE_DIR=/usr/include/postgresql/${PG_MAJOR}
66
ARG LIB_DIR=/usr/lib/postgresql/${PG_MAJOR}
@@ -14,10 +14,10 @@ ARG PGCONFIG=${BIN_DIR}/pg_config
1414
#
1515
#########################################################################################
1616

17-
FROM postgres:${PG_MAJOR}-bullseye AS pg-build
17+
FROM postgres:${PG_MAJOR}-trixie AS pg-build
1818

1919
RUN apt update && \
20-
apt install -y postgresql-server-dev-$PG_MAJOR
20+
apt install -y postgresql-server-dev-$PG_MAJOR
2121

2222

2323
#########################################################################################
@@ -26,7 +26,7 @@ RUN apt update && \
2626
# Used to copy postgres header files from, without needing postgres installed
2727
#
2828
#########################################################################################
29-
FROM debian:bullseye-slim AS build-deps
29+
FROM debian:trixie-slim AS build-deps
3030

3131
ARG EXTENSION_DIR
3232
ARG LIB_DIR
@@ -40,7 +40,7 @@ ENV CXX=g++
4040
RUN apt update && \
4141
apt install -y git autoconf automake libtool build-essential bison flex libreadline-dev \
4242
zlib1g-dev libxml2-dev libcurl4-openssl-dev libossp-uuid-dev wget pkg-config libssl-dev \
43-
libicu-dev libxslt1-dev liblz4-dev libzstd-dev zstd clang-13
43+
libicu-dev libxslt1-dev liblz4-dev libzstd-dev zstd clang-19
4444

4545

4646
#########################################################################################
@@ -56,8 +56,8 @@ ARG LIB_DIR
5656
ARG INCLUDE_DIR
5757
ARG PGCONFIG
5858

59-
ENV PGVECTOR_VERSION 0.7.0
60-
ENV PGVECTOR_SHA 1b5503a35c265408b6eb282621c5e1e75f7801afc04eecb950796cfee2e3d1d8
59+
ENV PGVECTOR_VERSION=0.8.2
60+
ENV PGVECTOR_SHA=69f4019389af05dc1c9548deb8628e62878e6e207c03907f2b8af2016472cdaa
6161

6262
COPY --from=pg-build ${EXTENSION_DIR}/ ${EXTENSION_DIR}/
6363
COPY --from=pg-build ${LIB_DIR}/ ${LIB_DIR}/
@@ -74,20 +74,20 @@ RUN mkdir /out /out/lib /out/share /out/share/extension && \
7474
cp ${EXTENSION_DIR}/vector* /out/share/extension/ && \
7575
echo 'trusted = true' >> /out/share/extension/vector.control
7676

77-
77+
7878
#########################################################################################
7979
#
8080
# Final image
8181
#
8282
#########################################################################################
8383

84-
FROM postgres:${PG_MAJOR}-bullseye
84+
FROM postgres:${PG_MAJOR}-trixie
8585

8686
LABEL maintainer="Encore - https://encore.dev"
8787
ARG EXTENSION_DIR
8888
ARG LIB_DIR
8989

90-
ENV POSTGIS_MAJOR 3
90+
ENV POSTGIS_MAJOR=3
9191

9292
RUN apt update \
9393
&& apt install -y --no-install-recommends \
@@ -114,3 +114,30 @@ RUN for ext in address_standardizer address_standardizer-3 address_standardizer_
114114
echo "trusted = true" >> "$EXTENSION_DIR/$ext.control"; \
115115
fi \
116116
done
117+
118+
# Raise max_connections on first init. initdb's -c writes the setting into
119+
# the generated postgresql.conf; editing postgresql.conf.sample alone is
120+
# not enough because initdb recomputes max_connections from kernel limits.
121+
ENV POSTGRES_INITDB_ARGS="-c max_connections=1000"
122+
123+
# Install legacy PostgreSQL server binaries plus matching extension
124+
# libraries (postgis, pgvector) so the OLD cluster can load extensions
125+
# during pg_upgrade's schema dump (opt-in via AUTO_PG_UPGRADE=1). Override
126+
# at build time with --build-arg LEGACY_PG_VERSIONS="15 16 17" to support more.
127+
ARG LEGACY_PG_VERSIONS="15"
128+
RUN mkdir -p /etc/postgresql-common && \
129+
echo 'create_main_cluster = false' > /etc/postgresql-common/createcluster.conf && \
130+
apt update && \
131+
for v in $LEGACY_PG_VERSIONS; do \
132+
apt install -y --no-install-recommends \
133+
postgresql-$v \
134+
postgresql-$v-postgis-$POSTGIS_MAJOR \
135+
postgresql-$v-pgvector; \
136+
done && \
137+
rm -rf /var/lib/apt/lists/*
138+
139+
COPY scripts/auto-upgrade-entrypoint.sh scripts/pg-auto-upgrade.sh /usr/local/bin/
140+
RUN chmod +x /usr/local/bin/auto-upgrade-entrypoint.sh /usr/local/bin/pg-auto-upgrade.sh
141+
142+
ENTRYPOINT ["auto-upgrade-entrypoint.sh"]
143+
CMD ["postgres"]

scripts/auto-upgrade-entrypoint.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
# Opt-in: only run the auto-upgrade probe when AUTO_PG_UPGRADE=1.
5+
# When enabled, detects a PG_VERSION mismatch between the mounted PGDATA
6+
# and this image, and runs pg_upgrade as the postgres user before chaining
7+
# to the official entrypoint.
8+
if [ "${AUTO_PG_UPGRADE:-0}" = "1" ] \
9+
&& [ "$(id -u)" = "0" ] \
10+
&& [ -s "${PGDATA}/PG_VERSION" ]; then
11+
OLD_VER="$(cat "${PGDATA}/PG_VERSION")"
12+
if [ "$OLD_VER" != "$PG_MAJOR" ]; then
13+
chown -R postgres:postgres "$PGDATA" "$(dirname "$PGDATA")"
14+
gosu postgres /usr/local/bin/pg-auto-upgrade.sh
15+
fi
16+
fi
17+
18+
exec docker-entrypoint.sh "$@"

scripts/pg-auto-upgrade.sh

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
OLD_VER="$(cat "${PGDATA}/PG_VERSION")"
5+
NEW_VER="${PG_MAJOR}"
6+
7+
if [ "$OLD_VER" = "$NEW_VER" ]; then
8+
exit 0
9+
fi
10+
11+
if [ "$OLD_VER" -gt "$NEW_VER" ]; then
12+
echo "pg-auto-upgrade: refusing to downgrade PGDATA from PG${OLD_VER} to PG${NEW_VER}" >&2
13+
exit 1
14+
fi
15+
16+
OLD_BIN="/usr/lib/postgresql/${OLD_VER}/bin"
17+
NEW_BIN="/usr/lib/postgresql/${NEW_VER}/bin"
18+
19+
if [ ! -x "$OLD_BIN/pg_upgrade" ]; then
20+
echo "pg-auto-upgrade: PG${OLD_VER} binaries are not installed in this image; cannot upgrade." >&2
21+
echo "pg-auto-upgrade: rebuild with LEGACY_PG_VERSIONS including ${OLD_VER}." >&2
22+
exit 1
23+
fi
24+
25+
echo "pg-auto-upgrade: migrating PGDATA from PG${OLD_VER} to PG${NEW_VER}"
26+
27+
# Stage both clusters as subdirectories of PGDATA itself. This keeps them
28+
# on the same filesystem (required for pg_upgrade --link) regardless of
29+
# whether the user mounted the volume at PGDATA or its parent.
30+
TS="$(date -u +%Y%m%dT%H%M%SZ)"
31+
SUBDIR_OLD="${PGDATA}/.upgrade-old-${TS}"
32+
SUBDIR_NEW="${PGDATA}/.upgrade-new-${TS}"
33+
34+
mkdir -p "$SUBDIR_OLD" "$SUBDIR_NEW"
35+
chmod 700 "$SUBDIR_OLD" "$SUBDIR_NEW"
36+
37+
# Roll back only failures that happen before pg_upgrade --link has run.
38+
ROLLBACK_SAFE=1
39+
on_failure() {
40+
if [ "$ROLLBACK_SAFE" != "1" ]; then
41+
return
42+
fi
43+
echo "pg-auto-upgrade: failed before pg_upgrade ran; restoring PGDATA contents" >&2
44+
rm -rf "$SUBDIR_NEW" 2>/dev/null || true
45+
if [ -d "$SUBDIR_OLD" ]; then
46+
find "$SUBDIR_OLD" -mindepth 1 -maxdepth 1 \
47+
-exec mv -t "$PGDATA" {} + 2>/dev/null || true
48+
rmdir "$SUBDIR_OLD" 2>/dev/null || true
49+
fi
50+
}
51+
trap on_failure ERR
52+
53+
# Move existing cluster contents into SUBDIR_OLD (skip the upgrade subdirs themselves).
54+
find "$PGDATA" -mindepth 1 -maxdepth 1 \
55+
! -path "$SUBDIR_OLD" ! -path "$SUBDIR_NEW" \
56+
-exec mv -t "$SUBDIR_OLD" {} +
57+
58+
# Match the new cluster's data-checksum setting to the old cluster's;
59+
# pg_upgrade refuses if they differ.
60+
OLD_CHECKSUM_VER="$("$OLD_BIN/pg_controldata" "$SUBDIR_OLD" \
61+
| awk -F': *' '/Data page checksum version/{print $2}')"
62+
if [ "${OLD_CHECKSUM_VER:-0}" -gt 0 ]; then
63+
CHECKSUM_ARG="--data-checksums"
64+
else
65+
CHECKSUM_ARG="--no-data-checksums"
66+
fi
67+
68+
"$NEW_BIN/initdb" \
69+
--username="${POSTGRES_USER:-postgres}" \
70+
"$CHECKSUM_ARG" \
71+
-c max_connections=1000 \
72+
-D "$SUBDIR_NEW"
73+
74+
cd /tmp
75+
ROLLBACK_SAFE=0
76+
"$NEW_BIN/pg_upgrade" \
77+
--old-bindir="$OLD_BIN" \
78+
--new-bindir="$NEW_BIN" \
79+
--old-datadir="$SUBDIR_OLD" \
80+
--new-datadir="$SUBDIR_NEW" \
81+
--link
82+
83+
# Promote the new cluster's files into PGDATA up front, so that even if
84+
# a later step fails the volume contains a startable cluster.
85+
find "$SUBDIR_NEW" -mindepth 1 -maxdepth 1 -exec mv -t "$PGDATA" {} +
86+
rmdir "$SUBDIR_NEW"
87+
88+
# Refresh collation versions: the OS glibc may differ from when the old
89+
# cluster was created (e.g. bullseye -> trixie), which silently breaks
90+
# b-tree ordering. REINDEX rebuilds indexes against current collation
91+
# rules; REFRESH updates the catalog's recorded version.
92+
refresh_collations() {
93+
local pg_temp_port=50432
94+
local pg_temp_log=/tmp/pg_post_upgrade.log
95+
96+
"$NEW_BIN/pg_ctl" -D "$PGDATA" \
97+
-o "-c listen_addresses='' -c unix_socket_directories=/tmp -p $pg_temp_port" \
98+
-l "$pg_temp_log" -w start
99+
100+
local psql=("$NEW_BIN/psql" -h /tmp -p "$pg_temp_port" \
101+
-U "${POSTGRES_USER:-postgres}" -X -At -v ON_ERROR_STOP=1)
102+
103+
local dbs
104+
dbs="$("${psql[@]}" -d postgres -c "
105+
SELECT datname FROM pg_database
106+
WHERE datallowconn AND datname <> 'template0'
107+
AND datcollversion IS DISTINCT FROM pg_database_collation_actual_version(oid)
108+
")" || dbs=""
109+
110+
local db
111+
while read -r db; do
112+
[ -n "$db" ] || continue
113+
echo "pg-auto-upgrade: REINDEX + REFRESH for database $db"
114+
"${psql[@]}" -d "$db" -c "REINDEX DATABASE \"$db\""
115+
"${psql[@]}" -d "$db" -c "ALTER DATABASE \"$db\" REFRESH COLLATION VERSION"
116+
"${psql[@]}" -d "$db" <<'SQL'
117+
DO $$
118+
DECLARE r record;
119+
BEGIN
120+
FOR r IN SELECT n.nspname, c.collname
121+
FROM pg_collation c JOIN pg_namespace n ON c.collnamespace = n.oid
122+
WHERE c.collversion IS NOT NULL
123+
AND c.collversion <> pg_collation_actual_version(c.oid)
124+
LOOP
125+
EXECUTE format('ALTER COLLATION %I.%I REFRESH VERSION', r.nspname, r.collname);
126+
END LOOP;
127+
END
128+
$$;
129+
SQL
130+
done <<< "$dbs"
131+
132+
"$NEW_BIN/pg_ctl" -D "$PGDATA" -w stop
133+
}
134+
135+
if ! refresh_collations; then
136+
echo "pg-auto-upgrade: collation refresh failed; the cluster is upgraded but" >&2
137+
echo "pg-auto-upgrade: you should manually REINDEX and REFRESH affected databases." >&2
138+
"$NEW_BIN/pg_ctl" -D "$PGDATA" -w stop 2>/dev/null || true
139+
fi
140+
141+
# Carry user-defined config and ALTER SYSTEM settings forward.
142+
for f in postgresql.conf postgresql.auto.conf pg_hba.conf pg_ident.conf; do
143+
if [ -f "$SUBDIR_OLD/$f" ]; then
144+
cp "$SUBDIR_OLD/$f" "$PGDATA/$f"
145+
fi
146+
done
147+
148+
# Re-apply image defaults that should survive an upgrade.
149+
sed -ri "s/^#?max_connections\s*=.*/max_connections = 1000/" "$PGDATA/postgresql.conf"
150+
151+
echo "pg-auto-upgrade: PG${OLD_VER} -> PG${NEW_VER} complete"
152+
echo "pg-auto-upgrade: pre-upgrade files kept at $SUBDIR_OLD — delete after verifying the new cluster"

0 commit comments

Comments
 (0)