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: backend:
runs-on: ubuntu-latest runs-on: ubuntu-latest
# pytest-databases starts PostgreSQL in a container and then connects to it. Which address # pytest-databases starts PostgreSQL in a container and then connects to it, and those are
# it connects to is decided by DOCKER_HOST: unset or unix:// means 127.0.0.1, which is wrong # two different addresses that have to be set separately:
# 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.
# #
# If the runner is ever configured with its own dind sidecar, delete this block and the # DOCKER_HOST which daemon to create the container on (_service.py get_docker_host)
# DOCKER_HOST below: every job gets a daemon then, including the ones in release.yml. # 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: services:
docker: docker:
image: docker:27-dind image: docker:27-dind
@@ -36,6 +41,7 @@ jobs:
env: env:
DOCKER_HOST: tcp://docker:2375 DOCKER_HOST: tcp://docker:2375
POSTGRES_HOST: docker
defaults: defaults:
run: 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 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. 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 **Reachability is a separate question from availability, and it bit us.** A containerised job
socket into a containerised job gives it a working daemon, and `pytest tests/` still fails with with a working daemon still fails `pytest tests/` with
`Service 'pytest_databases_postgres' failed to come online`: the container starts fine, but its `Service 'pytest_databases_postgres' failed to come online`: the database container starts
published port lands on the *host's* network namespace while the test process looks for it on fine, but its published port lands on the daemon's network namespace while the test process
the job container's loopback. `pytest_databases/docker/__init__.py` picks the address from looks for it on the job container's loopback.
`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 Two variables control two different things, and both must be set:
the value must include the port or it raises rather than falling back.
| 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 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 of its own with `DOCKER_HOST: tcp://docker:2375`. That needs the runner to permit