fix: tell the tests where the database actually is
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:
+13
-7
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user