refactor(infra): use upstream images verbatim, seed config via docker cp (refs #30)
All checks were successful
CI / lint (pull_request) Successful in 49s
CI / build (pull_request) Successful in 44s
CI / unit (pull_request) Successful in 44s
CI / compose-smoke (pull_request) Successful in 4m15s

Drops the inline-build images for the upstream services. The compose now
references the published images directly (openzaak/open-zaak,
openzaak/open-notificaties, keycloak, curl, flowable-rest) with no build for
them, and the config they need is streamed into external named volumes by
infra/seed-config.sh:

  rr-oz-config  -> oz-init     /app/setup_configuration   (data.yaml)
  rr-kc-realms  -> keycloak    /opt/keycloak/data/import   (realm exports)
  rr-fl-bpmn    -> flowable-init /work                     (registratie.bpmn)

How: the seeder creates each volume, `docker create`s a throwaway helper that
mounts it, `docker cp`s the files in, and removes it. docker cp streams over the
Docker API, so it works in Docker-in-Docker (the CI runner) where bind mounts
mount empty. It uses plain `docker create`/`cp` — NOT `docker compose create`,
which podman-compose (local dev) lacks. `external: true` fixed names keep the
volumes identical across docker compose and podman-compose.

Consequence: bare `docker compose up` no longer self-seeds, so use `make up`
(seeds then starts). Every `*-up` target seeds first; `*-down` removes the
external volume. acl/bff are still built (they're our apps, not upstream images).

Verified end-to-end on podman-compose: `make keycloak-up` seeds rr-kc-realms,
the upstream Keycloak mounts it, and --import-realm imports all four realms
(digid realm returns 200). Seeder runs in ~2s.

Docs updated: gitea-actions-gotchas.md, ci.md, openzaak.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-25 10:22:14 +02:00
parent 6d8e1d0830
commit b349dff496
9 changed files with 182 additions and 100 deletions

View File

@@ -12,6 +12,14 @@ COMPOSE := infra/docker-compose.yml
# a one-shot with no `service_completed_successfully` dependant exits (flowable-init),
# so we wait on the durable services instead. See docs/runbooks/gitea-actions-gotchas.md.
WAIT_SVCS := openzaak nrc-web acl bff
# Config files (OpenZaak data.yaml, Keycloak realms, Flowable BPMN) are streamed
# into external named volumes via `docker cp` (infra/seed-config.sh) instead of
# bind-mounted, because bind mounts don't reach sibling containers on the
# containerized CI runner. SEED populates them; run it before every `up`. The
# volumes are `external`, so compose won't remove them — CFG_VOLS lists them for
# explicit teardown. See docs/runbooks/gitea-actions-gotchas.md.
SEED := bash infra/seed-config.sh
CFG_VOLS := rr-oz-config rr-kc-realms rr-fl-bpmn
OZ_COMPOSE := infra/openzaak/docker-compose.yml
OZ_BASE := http://localhost:8000
NRC_COMPOSE := infra/opennotificaties/docker-compose.yml
@@ -32,7 +40,7 @@ export DOCKER_HOST := unix://$(PODMAN_SOCK)
endif
endif
.PHONY: ci lint build unit smoke down changelog openzaak-up openzaak-smoke openzaak-seed openzaak-down stack-up stack-smoke stack-down keycloak-up keycloak-smoke keycloak-down flowable-up flowable-smoke flowable-down help
.PHONY: ci lint build unit smoke up down changelog openzaak-up openzaak-smoke openzaak-seed openzaak-down stack-up stack-smoke stack-down keycloak-up keycloak-smoke keycloak-down flowable-up flowable-smoke flowable-down help
## ci: run the full pipeline — lint, build, unit, smoke (mirrors Gitea Actions)
ci: lint build unit smoke
@@ -49,19 +57,28 @@ build:
unit:
dotnet test $(SLN) -c Release
## smoke: bring the whole stack up, wait for the health-checked services, tear down
# Step 1 starts EVERYTHING (incl. one-shot init jobs that deploy and exit 0).
# Step 2 waits only for the durable, health-checked services ($(WAIT_SVCS)) — see
# WAIT_SVCS above for why the one-shots are excluded. The healthchecks run inside
# the containers, so this needs no host port access (the CI runner can't reach
# published ports anyway).
## smoke: seed config, bring the whole stack up, wait for health-checked services, tear down
# SEED populates the external config volumes first (the upstream images are used
# verbatim — no build for them). `up -d --build` then starts EVERYTHING (building
# only our acl/bff). The second `up --wait` waits for the durable, health-checked
# services ($(WAIT_SVCS)); the one-shots are excluded because `--wait` fails when a
# one-shot with no `service_completed_successfully` dependant exits (flowable-init).
# Healthchecks run inside the containers, so no host port access is needed.
smoke:
$(SEED) oz kc fl
docker compose -f $(COMPOSE) up -d --build
bash -c 'docker compose -f $(COMPOSE) up -d --wait --wait-timeout 420 $(WAIT_SVCS); rc=$$?; docker compose -f $(COMPOSE) down --volumes; exit $$rc'
bash -c 'docker compose -f $(COMPOSE) up -d --wait --wait-timeout 420 $(WAIT_SVCS); rc=$$?; docker compose -f $(COMPOSE) down --volumes; docker volume rm -f $(CFG_VOLS) >/dev/null 2>&1; exit $$rc'
## down: stop and remove the local stack
## up: seed config volumes and start the full stack (use instead of bare
## `docker compose up`, which can't self-seed the external config volumes)
up:
$(SEED) oz kc fl
docker compose -f $(COMPOSE) up -d --build
## down: stop and remove the local stack (incl. the external config volumes)
down:
docker compose -f $(COMPOSE) down --volumes
-docker volume rm -f $(CFG_VOLS)
## changelog: regenerate CHANGELOG.md from Conventional Commits (git-cliff)
changelog:
@@ -69,11 +86,11 @@ changelog:
## openzaak-up: start the OpenZaak stack (migrations run on first start)
openzaak-up:
$(SEED) oz
docker compose -f $(OZ_COMPOSE) up -d
## openzaak-smoke: start OpenZaak, then assert it is up with auth enforced
openzaak-smoke:
docker compose -f $(OZ_COMPOSE) up -d
openzaak-smoke: openzaak-up
@bash -c 'set -e; \
echo "waiting for OpenZaak to respond..."; \
for i in $$(seq 1 60); do \
@@ -97,9 +114,11 @@ openzaak-seed: openzaak-up
## openzaak-down: stop and remove the OpenZaak stack (wipes data)
openzaak-down:
docker compose -f $(OZ_COMPOSE) down --volumes
-docker volume rm -f rr-oz-config
## stack-up: start OpenZaak + Open Notificaties together (shared network)
stack-up:
$(SEED) oz
docker compose $(STACK_FILES) up -d
## stack-smoke: start both, assert OpenZaak (403/302/200) and NRC (302) are reachable
@@ -119,9 +138,11 @@ stack-smoke: stack-up
## stack-down: stop and remove both stacks (wipes data)
stack-down:
docker compose $(STACK_FILES) down --volumes
-docker volume rm -f rr-oz-config
## keycloak-up: start Keycloak with the four imported realms
keycloak-up:
$(SEED) kc
docker compose -f $(KC_COMPOSE) up -d
## keycloak-smoke: start Keycloak, then verify each realm logs in + returns its claim
@@ -134,9 +155,11 @@ keycloak-smoke: keycloak-up
## keycloak-down: stop and remove Keycloak
keycloak-down:
docker compose -f $(KC_COMPOSE) down --volumes
-docker volume rm -f rr-kc-realms
## flowable-up: start Flowable (deploys registratie.bpmn on boot)
flowable-up:
$(SEED) fl
docker compose -f $(FL_COMPOSE) up -d
## flowable-smoke: start Flowable, then verify a started instance waits on the external task
@@ -149,6 +172,7 @@ flowable-smoke: flowable-up
## flowable-down: stop and remove Flowable
flowable-down:
docker compose -f $(FL_COMPOSE) down --volumes
-docker volume rm -f rr-fl-bpmn
## help: list available targets
help: