fix: tell the tests where the database actually is
ci / backend (push) Failing after 1m16s
ci / frontend (push) Successful in 1m58s

DOCKER_HOST only decides which daemon creates the container; the address the
test dials comes from POSTGRES_HOST, which defaults to the job container's own
loopback. Setting one without the other still times out.
This commit is contained in:
2026-08-18 00:49:41 -04:00
parent 5176dfcb77
commit 412a73cedf
2 changed files with 31 additions and 15 deletions
+13 -7
View File
@@ -19,14 +19,19 @@ jobs:
backend:
runs-on: ubuntu-latest
# pytest-databases starts PostgreSQL in a container and then connects to it. Which address
# it connects to is decided by DOCKER_HOST: unset or unix:// means 127.0.0.1, which is wrong
# here because the job is itself a container and the database is a sibling, published on
# another network namespace. Pointing at a dind service instead makes pytest-databases
# resolve the host to `docker`, where the port really is.
# pytest-databases starts PostgreSQL in a container and then connects to it, and those are
# two different addresses that have to be set separately:
#
# If the runner is ever configured with its own dind sidecar, delete this block and the
# DOCKER_HOST below: every job gets a daemon then, including the ones in release.yml.
# DOCKER_HOST which daemon to create the container on (_service.py get_docker_host)
# POSTGRES_HOST where the test then connects (docker/postgres.py, default
# 127.0.0.1 -- the job container's own loopback, where nothing listens,
# because the database is a sibling container on another namespace)
#
# Setting only the first leaves the tests dialling 127.0.0.1 and timing out with
# "Service 'pytest_databases_postgres' failed to come online".
#
# If the runner is ever given its own dind sidecar, drop this services block and keep the
# two env vars pointed at whatever host it exposes.
services:
docker:
image: docker:27-dind
@@ -36,6 +41,7 @@ jobs:
env:
DOCKER_HOST: tcp://docker:2375
POSTGRES_HOST: docker
defaults:
run:
+18 -8
View File
@@ -105,14 +105,24 @@ the workflow.
volume), or run the runner in host mode. The dind sidecar is the safer of the two — mounting the
host socket into job containers gives any workflow root on the runner host.
**Reachability is a separate question from availability, and it bit us.** Mounting the host
socket into a containerised job gives it a working daemon, and `pytest tests/` still fails with
`Service 'pytest_databases_postgres' failed to come online`: the container starts fine, but its
published port lands on the *host's* network namespace while the test process looks for it on
the job container's loopback. `pytest_databases/docker/__init__.py` picks the address from
`DOCKER_HOST` — `127.0.0.1` when it is unset or `unix://`, otherwise the hostname out of
`tcp://host:port`. So a TCP `DOCKER_HOST` is what makes the sibling container addressable, and
the value must include the port or it raises rather than falling back.
**Reachability is a separate question from availability, and it bit us.** A containerised job
with a working daemon still fails `pytest tests/` with
`Service 'pytest_databases_postgres' failed to come online`: the database container starts
fine, but its published port lands on the daemon's network namespace while the test process
looks for it on the job container's loopback.
Two variables control two different things, and both must be set:
| Variable | Decides | Read by |
| --- | --- | --- |
| `DOCKER_HOST` | which daemon the container is created on | `_service.py` `get_docker_host()` |
| `POSTGRES_HOST` | the address the test then connects to | `docker/postgres.py` `postgres_host`, default `127.0.0.1` |
Setting only `DOCKER_HOST` is not enough — `DockerService.run()` takes `container_host` as a
plain argument defaulting to `127.0.0.1`, and the postgres fixture fills it from
`POSTGRES_HOST`. (There *is* a `DOCKER_HOST`-parsing helper in `pytest_databases`, but it is
`_get_docker_ip()` on the docker-compose class in `docker/__init__.py` and no part of this
path uses it. Do not be misled by it, as I was.)
Until the runner grows its own sidecar, `ci.yml`'s backend job carries a `docker:dind` service
of its own with `DOCKER_HOST: tcp://docker:2375`. That needs the runner to permit