Replaces the three standalone Dockerfiles (openzaak, opennotificaties, keycloak) with `build.dockerfile_inline` recipes in the compose files, so the config bake has no separate Dockerfile artifacts to maintain. Behaviour is identical: each derived image still COPYies its config in. - oz-init / keycloak / flowable-init: 2-line inline Dockerfiles. - Open Notificaties needs no bake at all now — nrc-init runs migrations only, so all NRC services use the plain base image (removes a whole derived image). Why dockerfile_inline and not `docker cp` into named volumes: docker cp avoids images entirely but needs `docker compose create`, which podman-compose (the local dev runtime) does not implement — it would break `make openzaak-up` etc. locally. dockerfile_inline works on both podman-compose and the CI runner (verified both: oz-init + keycloak inline builds locally; flowable-init inline has been green on CI since run 27). Docs updated: gitea-actions-gotchas.md and openzaak.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
114 lines
5.6 KiB
Markdown
114 lines
5.6 KiB
Markdown
# Gitea Actions gotchas
|
|
|
|
Known differences between Gitea Actions (our CI) and a plain local run, and the
|
|
workarounds we adopted. Referenced by `CLAUDE.md` §8.7 and §15.
|
|
|
|
## Bind mounts don't reach Compose services on the hosted runner
|
|
|
|
**Symptom.** `make smoke` is green locally but the `compose-smoke` CI job fails
|
|
with the OpenZaak init container exiting 1:
|
|
|
|
```
|
|
oz-init-1 | CommandError: Yaml file `/app/setup_configuration/data.yaml` does not exist.
|
|
```
|
|
|
|
Migrations run fine; only the step that reads a **mounted** file fails. The same
|
|
class of failure hits any service that bind-mounts a workspace path —
|
|
`nrc-init` (its `data.yaml`), `flowable-init` (the BPMN), `keycloak` (the realm
|
|
import dir).
|
|
|
|
**Cause.** The `ubuntu-latest` runner executes the whole job **inside a
|
|
container** (`docker.gitea.com/runner-images:ubuntu-latest`). When the job then
|
|
runs `docker compose ... up`, Compose talks to the host's Docker daemon and
|
|
starts the stack as **sibling containers**. A relative bind mount such as
|
|
|
|
```yaml
|
|
volumes:
|
|
- ./openzaak/setup_configuration:/app/setup_configuration:ro
|
|
```
|
|
|
|
is resolved by Compose to an absolute path **inside the job container**
|
|
(`/workspace/eho/register-referentie/infra/openzaak/setup_configuration`). The
|
|
daemon then looks for that path on **its own host**, doesn't find it, and
|
|
auto-creates an **empty directory** to mount. The container starts with an empty
|
|
mount point, so the file appears "missing".
|
|
|
|
This is the classic Docker-in-Docker / sibling-container bind-mount trap. It does
|
|
not happen on a runner that executes jobs directly on the host (the previous
|
|
self-hosted `respellion-linux` setup), which is why switching to `ubuntu-latest`
|
|
exposed it.
|
|
|
|
**Fix: bake assets into derived images instead of bind-mounting them.** Anything
|
|
a Compose service needs at runtime that lives in the repo is `COPY`-ed into a
|
|
small derived image, so it is present regardless of where the daemon runs. We use
|
|
**`build.dockerfile_inline`** — the 2-line recipe lives in the compose file, so
|
|
there are no standalone `Dockerfile` artifacts to maintain:
|
|
|
|
| Asset | Derived image | Built by |
|
|
|---|---|---|
|
|
| OpenZaak `setup_configuration/data.yaml` | `register-referentie/openzaak:dev` | `oz-init` `dockerfile_inline` |
|
|
| Keycloak realm exports | `register-referentie/keycloak:dev` | `keycloak` `dockerfile_inline` |
|
|
| `workflows/registratie.bpmn` | `register-referentie/flowable-init:dev` | `flowable-init` `dockerfile_inline` |
|
|
|
|
The base image tag is interpolated by Compose (`${OPENZAAK_TAG}`) so pinning is
|
|
unchanged. OpenZaak's `openzaak`/`oz-celery` reuse the one image `oz-init` builds.
|
|
Open Notificaties needs **no** bake — `nrc-init` runs migrations only, so all NRC
|
|
services use the plain base image.
|
|
|
|
`dockerfile_inline` works on both the CI runner (docker compose) and local
|
|
**podman-compose**, unlike `docker cp`-into-volumes (which needs `docker compose
|
|
create`, a subcommand podman-compose lacks).
|
|
|
|
**Why not the alternatives.**
|
|
|
|
- *Compose `configs:` with inline `content`* — Compose materialises these as a
|
|
temp file on the **client** side and bind-mounts it, so it hits the exact same
|
|
daemon-can't-see-the-path problem.
|
|
- *A self-hosted runner that runs jobs on the host* — works, but reintroduces a
|
|
bespoke runner and undoes the move to the hosted `ubuntu-latest` label.
|
|
|
|
**Consequence for local dev.** There is now no bind mount of these config files,
|
|
so the SELinux `:z`/`:Z` relabel flag is no longer needed anywhere in `infra/`,
|
|
and rootless Podman no longer needs the files to be world-readable. One mechanism
|
|
(build) works on both Podman locally and Docker-in-Docker in CI.
|
|
|
|
## `--wait` fails on one-shot containers with no dependant
|
|
|
|
`docker compose up --wait` treats a service that **exits** as a failure of the
|
|
"stay up" condition — **unless** another service depends on it with
|
|
`condition: service_completed_successfully`. Our init jobs `oz-init` and
|
|
`nrc-init` are fine (`openzaak`/`nrc-web` depend on their completion), but
|
|
`flowable-init` deploys the BPMN and exits 0 with **no dependant**, so a
|
|
whole-project `--wait` fails the moment it exits — even with everything else
|
|
healthy. The symptom is a `compose-smoke` failure whose last compose line is:
|
|
|
|
```
|
|
container infra-flowable-init-1 exited (0)
|
|
```
|
|
|
|
**Fix.** The smoke does **not** `--wait` on the whole project. It starts
|
|
everything with `up -d`, then `up -d --wait <services>` only for the durable,
|
|
health-checked services (`openzaak nrc-web acl bff` — see `WAIT_SVCS` in the
|
|
`Makefile`). One-shots still run (and deploy), they just don't gate `--wait`.
|
|
|
|
This also removed the old external `curl http://localhost:8080/health` check:
|
|
the CI job runs in a container and **can't reach published host ports** at
|
|
`localhost`, and the per-service healthchecks (which run *inside* the
|
|
containers) already prove readiness, so `--wait` succeeding *is* the smoke.
|
|
|
|
## `--wait` needs an explicit timeout
|
|
|
|
`docker compose up --wait` defaults to a 60-second timeout in some Compose v2
|
|
releases. A cold OpenZaak migrate alone takes ~50 s, so the smoke target passes
|
|
`--wait-timeout 300` (see `Makefile`). The 3-minute Definition-of-Done budget
|
|
still holds — this just stops `--wait` giving up before the stack is healthy.
|
|
|
|
## PostGIS readiness vs. `pg_isready`
|
|
|
|
`pg_isready` reports the server is accepting connections as soon as the TCP port
|
|
is open — **before** the `postgis/postgis` image has finished running its
|
|
`CREATE EXTENSION postgis` init scripts. An init container that starts migrating
|
|
in that window can fail on a missing PostGIS. The db healthchecks therefore add a
|
|
`SELECT PostGIS_Version()` probe so dependents wait for the extension, not just
|
|
the port.
|