CI: reach Postgres through the gateway instead of a shared namespace
CI / verify (push) Failing after 5s

Second attempt failed differently: /etc/hostname inside the job reports the
HOST's name rather than the container id, so `--network container:$HOSTNAME`
found no such container.

Rather than hunt for our own container id through /proc, publish the port on
the host and connect through the job container's default gateway. That needs
no container identity at all. The port is derived from the run id so two
concurrent runs cannot collide, and DATABASE_URL is exported through GITHUB_ENV
once Postgres is actually accepting connections.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 20:30:24 -07:00
parent 40f6fd993d
commit e6b4c1618e
+25 -9
View File
@@ -32,14 +32,20 @@ jobs:
# Postgres is started as a step rather than through `services:`. # Postgres is started as a step rather than through `services:`.
# #
# The runner here does not put service containers on the job's network, so # Two approaches were tried and rejected before this one:
# `services:` yields "getaddrinfo EAI_AGAIN postgres". Sharing the job #
# container's own network namespace (`--network container:$HOSTNAME`) puts # `services:` — this runner does not attach service
# Postgres on 127.0.0.1 and works regardless of how the runner is # containers to the job network, giving
# configured — which matters because this runner is shared with other # "getaddrinfo EAI_AGAIN postgres".
# repositories and should not have to be reconfigured to suit this one. # `--network container:$HOSTNAME` — /etc/hostname inside the job reports
# the HOST's name, not the container id,
# so the namespace join finds no such
# container.
#
# What works without needing to know our own container id: publish the port
# on the host and reach it through the job container's default gateway. The
# port is derived from the run id so concurrent runs cannot collide.
env: env:
DATABASE_URL: postgres://pig:pig@127.0.0.1:5432/pig
PG_CONTAINER: pig-ci-pg-${{ github.run_id }} PG_CONTAINER: pig-ci-pg-${{ github.run_id }}
steps: steps:
@@ -51,14 +57,24 @@ jobs:
- name: Start Postgres - name: Start Postgres
run: | run: |
# A per-run port in the ephemeral range, so two runs never collide.
PG_PORT=$(( 45000 + (${{ github.run_id }} % 15000) ))
GATEWAY=$(ip route | awk '/^default/ {print $3; exit}')
if [ -z "$GATEWAY" ]; then echo "Could not determine the gateway"; exit 1; fi
echo "Postgres will be published on ${GATEWAY}:${PG_PORT}"
docker rm -f "$PG_CONTAINER" 2>/dev/null || true docker rm -f "$PG_CONTAINER" 2>/dev/null || true
docker run -d --name "$PG_CONTAINER" \ docker run -d --name "$PG_CONTAINER" \
--network "container:$(cat /etc/hostname)" \ -p "${PG_PORT}:5432" \
-e POSTGRES_USER=pig -e POSTGRES_PASSWORD=pig -e POSTGRES_DB=pig \ -e POSTGRES_USER=pig -e POSTGRES_PASSWORD=pig -e POSTGRES_DB=pig \
postgres:16-alpine postgres:16-alpine
for i in $(seq 1 60); do for i in $(seq 1 60); do
if docker exec "$PG_CONTAINER" pg_isready -U pig -q; then if docker exec "$PG_CONTAINER" pg_isready -U pig -q; then
echo "Postgres ready after ${i}s"; exit 0 echo "Postgres ready after ${i}s"
# Export for every later step.
echo "DATABASE_URL=postgres://pig:pig@${GATEWAY}:${PG_PORT}/pig" >> "$GITHUB_ENV"
exit 0
fi fi
sleep 1 sleep 1
done done