Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ test/smoke.sh <image> # smoke-test any image, e.g. one pulled from GHCR
- **The health check is TCP on purpose** (`pg_isready -h 127.0.0.1`). During first start the
entrypoint runs a socket-only server, and the smoke test relies on the same distinction to wait for
the real one.
- **The health check names its role and database** (`-U "${POSTGRES_USER:-postgres}" -d postgres`,
shell form so the variable expands in the container). Without them pg_isready connects as root,
still reports healthy, and the server logs `FATAL: role "root" does not exist` every 10 s.
`test/smoke.sh` runs the same line and fails on that FATAL, so change both together.
- **Release pushes what was tested.** The release job builds with `load: true`, smoke-tests that
image, then runs build-push again on the same builder, so every layer comes from that build's
cache. Don't add a step between them that changes the build context.
Expand Down
6 changes: 5 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,9 @@ COPY --chmod=755 scripts/update-extensions.sh /usr/local/bin/update-extensions.s

# TCP on purpose: during first-start initialisation the entrypoint runs a
# socket-only server, so this stays unhealthy until the real one is up.
# -U and -d because pg_isready otherwise connects as the OS user (root) to a
# database of the same name: it still reports healthy, but the server logs
# `FATAL: role "root" does not exist` on every probe. Shell form, so
# POSTGRES_USER expands inside the container. test/smoke.sh runs the same line.
HEALTHCHECK --interval=10s --timeout=5s --start-period=60s --retries=5 \
CMD ["pg_isready", "-q", "-h", "127.0.0.1"]
CMD pg_isready -q -h 127.0.0.1 -U "${POSTGRES_USER:-postgres}" -d postgres
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,11 @@ Restart=always
WantedBy=multi-user.target
```

The image ships a `HEALTHCHECK` (`pg_isready -h 127.0.0.1`). It turns healthy only once the real
server is listening on TCP, not while the first-start initialisation is still running.
The image ships a `HEALTHCHECK`
(`pg_isready -h 127.0.0.1 -U "${POSTGRES_USER:-postgres}" -d postgres`). It turns healthy only once
the real server is listening on TCP, not while the first-start initialisation is still running. It
names the role and database so that probes don't fill the server log with
`FATAL: role "root" does not exist`.

Every variable and behaviour of the official `postgres` image applies unchanged, including
`POSTGRES_USER`, `POSTGRES_INITDB_ARGS` and extra scripts in `/docker-entrypoint-initdb.d`. Name your
Expand Down
10 changes: 9 additions & 1 deletion test/smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,15 @@ if [ -z "${ready:-}" ]; then
fi

"${psql[@]}" -q <"$here/smoke.sql"
"$docker" exec "$name" pg_isready -q -h 127.0.0.1
# The Dockerfile's HEALTHCHECK, verbatim. pg_isready exits 0 even when the
# server rejects its role, so also make sure the probe left no FATAL behind.
# The single quotes are deliberate: POSTGRES_USER expands in the container.
# shellcheck disable=SC2016
"$docker" exec "$name" sh -c 'pg_isready -q -h 127.0.0.1 -U "${POSTGRES_USER:-postgres}" -d postgres'
if "$docker" logs "$name" 2>&1 | grep -E 'FATAL: +(role|database) .* does not exist'; then
echo "the health check makes the server log a FATAL on every probe" >&2
exit 1
fi
"$docker" exec -u postgres "$name" update-extensions.sh

versions="$("${psql[@]}" -qAt -F ' | ' <<'SQL'
Expand Down
Loading