diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 607be30..2ae7dc1 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -19,6 +19,24 @@ 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. + # + # 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. + services: + docker: + image: docker:27-dind + options: --privileged + env: + DOCKER_TLS_CERTDIR: '' + + env: + DOCKER_HOST: tcp://docker:2375 + defaults: run: working-directory: backend @@ -42,8 +60,6 @@ jobs: - name: Lint run: uv run ruff check src/ tests/ - # pytest-databases starts a throwaway PostgreSQL container, so this needs a working - # Docker daemon on the runner — the same requirement the release workflow has. - name: Tests run: uv run pytest tests/ -q diff --git a/docs/ci-release-pipeline.md b/docs/ci-release-pipeline.md index bb9590c..f14c69a 100644 --- a/docs/ci-release-pipeline.md +++ b/docs/ci-release-pipeline.md @@ -99,12 +99,27 @@ the workflow. 1. **A registered `act_runner`.** Gitea Actions is enabled instance-side but does nothing without a runner. Register one against the repo or the instance with the label `ubuntu-latest`. -2. **The runner needs a Docker daemon.** This is the single most common failure for image-building - workflows on Gitea. `act_runner` in docker mode runs each job inside a container that has no - daemon of its own. Either run a `docker:dind` sidecar next to the runner and set - `DOCKER_HOST=tcp://docker:2376` (with TLS certs shared over a volume), or run the runner in host - mode with the socket mounted. The dind sidecar is the safer of the two — mounting the host socket - into job containers gives any workflow root on the runner host. +2. **The runner needs a Docker daemon, at an address the job can reach.** `act_runner` in docker + mode runs each job inside a container with no daemon of its own. Either run a `docker:dind` + sidecar next to the runner and set `DOCKER_HOST=tcp://docker:2376` (with TLS certs shared over a + 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. + + 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 + `--privileged`. The same treatment is still owed to `release.yml` — its `quality` job runs the + same tests, and its `smoke` job talks to compose, where the published ports would move to the + dind host too, so `curl http://localhost:3000` becomes `curl http://docker:3000`. Configuring + the runner once (option 1) avoids all of that. 3. **Action resolution.** A bare `uses: docker/build-push-action@v6` does not mean github.com here. Gitea resolves it against `[actions] DEFAULT_ACTIONS_URL`, which defaults to `https://gitea.com`. That is fine as it stands — `actions/checkout@v4`, `docker/setup-buildx-action@v3`,