ci(infra): Gitea Actions CI pipeline + full-stack compose smoke (closes #30) #50
46
Makefile
46
Makefile
@@ -12,6 +12,14 @@ COMPOSE := infra/docker-compose.yml
|
|||||||
# a one-shot with no `service_completed_successfully` dependant exits (flowable-init),
|
# 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.
|
# so we wait on the durable services instead. See docs/runbooks/gitea-actions-gotchas.md.
|
||||||
WAIT_SVCS := openzaak nrc-web acl bff
|
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_COMPOSE := infra/openzaak/docker-compose.yml
|
||||||
OZ_BASE := http://localhost:8000
|
OZ_BASE := http://localhost:8000
|
||||||
NRC_COMPOSE := infra/opennotificaties/docker-compose.yml
|
NRC_COMPOSE := infra/opennotificaties/docker-compose.yml
|
||||||
@@ -32,7 +40,7 @@ export DOCKER_HOST := unix://$(PODMAN_SOCK)
|
|||||||
endif
|
endif
|
||||||
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: run the full pipeline — lint, build, unit, smoke (mirrors Gitea Actions)
|
||||||
ci: lint build unit smoke
|
ci: lint build unit smoke
|
||||||
@@ -49,19 +57,28 @@ build:
|
|||||||
unit:
|
unit:
|
||||||
dotnet test $(SLN) -c Release
|
dotnet test $(SLN) -c Release
|
||||||
|
|
||||||
## smoke: bring the whole stack up, wait for the health-checked services, tear down
|
## smoke: seed config, bring the whole stack up, wait for health-checked services, tear down
|
||||||
# Step 1 starts EVERYTHING (incl. one-shot init jobs that deploy and exit 0).
|
# SEED populates the external config volumes first (the upstream images are used
|
||||||
# Step 2 waits only for the durable, health-checked services ($(WAIT_SVCS)) — see
|
# verbatim — no build for them). `up -d --build` then starts EVERYTHING (building
|
||||||
# WAIT_SVCS above for why the one-shots are excluded. The healthchecks run inside
|
# only our acl/bff). The second `up --wait` waits for the durable, health-checked
|
||||||
# the containers, so this needs no host port access (the CI runner can't reach
|
# services ($(WAIT_SVCS)); the one-shots are excluded because `--wait` fails when a
|
||||||
# published ports anyway).
|
# one-shot with no `service_completed_successfully` dependant exits (flowable-init).
|
||||||
|
# Healthchecks run inside the containers, so no host port access is needed.
|
||||||
smoke:
|
smoke:
|
||||||
|
$(SEED) oz kc fl
|
||||||
docker compose -f $(COMPOSE) up -d --build
|
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:
|
down:
|
||||||
docker compose -f $(COMPOSE) down --volumes
|
docker compose -f $(COMPOSE) down --volumes
|
||||||
|
-docker volume rm -f $(CFG_VOLS)
|
||||||
|
|
||||||
## changelog: regenerate CHANGELOG.md from Conventional Commits (git-cliff)
|
## changelog: regenerate CHANGELOG.md from Conventional Commits (git-cliff)
|
||||||
changelog:
|
changelog:
|
||||||
@@ -69,11 +86,11 @@ changelog:
|
|||||||
|
|
||||||
## openzaak-up: start the OpenZaak stack (migrations run on first start)
|
## openzaak-up: start the OpenZaak stack (migrations run on first start)
|
||||||
openzaak-up:
|
openzaak-up:
|
||||||
|
$(SEED) oz
|
||||||
docker compose -f $(OZ_COMPOSE) up -d
|
docker compose -f $(OZ_COMPOSE) up -d
|
||||||
|
|
||||||
## openzaak-smoke: start OpenZaak, then assert it is up with auth enforced
|
## openzaak-smoke: start OpenZaak, then assert it is up with auth enforced
|
||||||
openzaak-smoke:
|
openzaak-smoke: openzaak-up
|
||||||
docker compose -f $(OZ_COMPOSE) up -d
|
|
||||||
@bash -c 'set -e; \
|
@bash -c 'set -e; \
|
||||||
echo "waiting for OpenZaak to respond..."; \
|
echo "waiting for OpenZaak to respond..."; \
|
||||||
for i in $$(seq 1 60); do \
|
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: stop and remove the OpenZaak stack (wipes data)
|
||||||
openzaak-down:
|
openzaak-down:
|
||||||
docker compose -f $(OZ_COMPOSE) down --volumes
|
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: start OpenZaak + Open Notificaties together (shared network)
|
||||||
stack-up:
|
stack-up:
|
||||||
|
$(SEED) oz
|
||||||
docker compose $(STACK_FILES) up -d
|
docker compose $(STACK_FILES) up -d
|
||||||
|
|
||||||
## stack-smoke: start both, assert OpenZaak (403/302/200) and NRC (302) are reachable
|
## 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: stop and remove both stacks (wipes data)
|
||||||
stack-down:
|
stack-down:
|
||||||
docker compose $(STACK_FILES) down --volumes
|
docker compose $(STACK_FILES) down --volumes
|
||||||
|
-docker volume rm -f rr-oz-config
|
||||||
|
|
||||||
## keycloak-up: start Keycloak with the four imported realms
|
## keycloak-up: start Keycloak with the four imported realms
|
||||||
keycloak-up:
|
keycloak-up:
|
||||||
|
$(SEED) kc
|
||||||
docker compose -f $(KC_COMPOSE) up -d
|
docker compose -f $(KC_COMPOSE) up -d
|
||||||
|
|
||||||
## keycloak-smoke: start Keycloak, then verify each realm logs in + returns its claim
|
## 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: stop and remove Keycloak
|
||||||
keycloak-down:
|
keycloak-down:
|
||||||
docker compose -f $(KC_COMPOSE) down --volumes
|
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: start Flowable (deploys registratie.bpmn on boot)
|
||||||
flowable-up:
|
flowable-up:
|
||||||
|
$(SEED) fl
|
||||||
docker compose -f $(FL_COMPOSE) up -d
|
docker compose -f $(FL_COMPOSE) up -d
|
||||||
|
|
||||||
## flowable-smoke: start Flowable, then verify a started instance waits on the external task
|
## 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: stop and remove Flowable
|
||||||
flowable-down:
|
flowable-down:
|
||||||
docker compose -f $(FL_COMPOSE) down --volumes
|
docker compose -f $(FL_COMPOSE) down --volumes
|
||||||
|
-docker volume rm -f rr-fl-bpmn
|
||||||
|
|
||||||
## help: list available targets
|
## help: list available targets
|
||||||
help:
|
help:
|
||||||
|
|||||||
@@ -16,16 +16,18 @@ and CI cannot drift:
|
|||||||
| `lint` | `make lint` → `dotnet format … --verify-no-changes` | .NET 10 SDK |
|
| `lint` | `make lint` → `dotnet format … --verify-no-changes` | .NET 10 SDK |
|
||||||
| `build` | `make build` → `dotnet build … -c Release` | .NET 10 SDK |
|
| `build` | `make build` → `dotnet build … -c Release` | .NET 10 SDK |
|
||||||
| `unit` | `make unit` → `dotnet test … -c Release` | .NET 10 SDK |
|
| `unit` | `make unit` → `dotnet test … -c Release` | .NET 10 SDK |
|
||||||
| `compose-smoke` | `make smoke` → `up -d` (full stack) → `up --wait` durable services → `down` | container engine + compose v2 |
|
| `compose-smoke` | `make smoke` → seed config volumes → `up -d` (full stack) → `up --wait` durable services → `down` | container engine + compose v2 |
|
||||||
|
|
||||||
All `uses:` references are absolute, tag-pinned URLs (`https://github.com/actions/checkout@v4`,
|
All `uses:` references are absolute, tag-pinned URLs (`https://github.com/actions/checkout@v4`,
|
||||||
`https://github.com/actions/setup-dotnet@v4`) per CLAUDE.md §8.7 and §15 — Gitea
|
`https://github.com/actions/setup-dotnet@v4`) per CLAUDE.md §8.7 and §15 — Gitea
|
||||||
Actions resolves them from GitHub.
|
Actions resolves them from GitHub.
|
||||||
|
|
||||||
> **`compose-smoke` runs on a containerized runner.** Workspace bind mounts do
|
> **`compose-smoke` runs on a containerized runner.** Workspace bind mounts do
|
||||||
> **not** reach the sibling containers Compose starts, so config/assets are baked
|
> **not** reach the sibling containers Compose starts, so config/assets are
|
||||||
> into derived images instead of being mounted. If you add a service that needs a
|
> streamed into external named volumes via `docker cp` (`infra/seed-config.sh`),
|
||||||
> repo file at runtime, bake it — don't bind-mount it. See
|
> and the upstream images are used verbatim (no build). If you add a service that
|
||||||
|
> needs a repo file at runtime, seed it the same way — don't bind-mount it. Note:
|
||||||
|
> bare `docker compose up` no longer self-seeds; use `make up`. See
|
||||||
> [gitea-actions-gotchas.md](gitea-actions-gotchas.md).
|
> [gitea-actions-gotchas.md](gitea-actions-gotchas.md).
|
||||||
|
|
||||||
## Running CI locally (`make ci`)
|
## Running CI locally (`make ci`)
|
||||||
|
|||||||
@@ -38,39 +38,50 @@ 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`
|
self-hosted `respellion-linux` setup), which is why switching to `ubuntu-latest`
|
||||||
exposed it.
|
exposed it.
|
||||||
|
|
||||||
**Fix: bake assets into derived images instead of bind-mounting them.** Anything
|
**Fix: the upstream images are used verbatim (no build); config is streamed into
|
||||||
a Compose service needs at runtime that lives in the repo is `COPY`-ed into a
|
external named volumes with `docker cp`.** `infra/seed-config.sh` creates a fixed-
|
||||||
small derived image, so it is present regardless of where the daemon runs. We use
|
name volume per asset, runs a throwaway helper container that mounts it, and
|
||||||
**`build.dockerfile_inline`** — the 2-line recipe lives in the compose file, so
|
`docker cp`s the files in. `docker cp` streams bytes over the Docker API, so it
|
||||||
there are no standalone `Dockerfile` artifacts to maintain:
|
works no matter where the daemon runs (including Docker-in-Docker). The services
|
||||||
|
then mount those volumes:
|
||||||
|
|
||||||
| Asset | Derived image | Built by |
|
| Asset | External volume | Mounted by → at |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| OpenZaak `setup_configuration/data.yaml` | `register-referentie/openzaak:dev` | `oz-init` `dockerfile_inline` |
|
| OpenZaak `setup_configuration/data.yaml` | `rr-oz-config` | `oz-init` → `/app/setup_configuration` |
|
||||||
| Keycloak realm exports | `register-referentie/keycloak:dev` | `keycloak` `dockerfile_inline` |
|
| Keycloak realm exports | `rr-kc-realms` | `keycloak` → `/opt/keycloak/data/import` |
|
||||||
| `workflows/registratie.bpmn` | `register-referentie/flowable-init:dev` | `flowable-init` `dockerfile_inline` |
|
| `workflows/registratie.bpmn` | `rr-fl-bpmn` | `flowable-init` → `/work` |
|
||||||
|
|
||||||
The base image tag is interpolated by Compose (`${OPENZAAK_TAG}`) so pinning is
|
The volumes are declared `external: true` with fixed `name:`s so they resolve
|
||||||
unchanged. OpenZaak's `openzaak`/`oz-celery` reuse the one image `oz-init` builds.
|
identically under docker compose and podman-compose. The seed step (`make` runs
|
||||||
Open Notificaties needs **no** bake — `nrc-init` runs migrations only, so all NRC
|
it before every `up`) recreates them fresh each time; `make down` / the
|
||||||
services use the plain base image.
|
per-service `*-down` targets remove them. Open Notificaties needs no config at all
|
||||||
|
— `nrc-init` runs migrations only.
|
||||||
|
|
||||||
`dockerfile_inline` works on both the CI runner (docker compose) and local
|
**Two hard constraints drove this design:**
|
||||||
**podman-compose**, unlike `docker cp`-into-volumes (which needs `docker compose
|
|
||||||
create`, a subcommand podman-compose lacks).
|
- Use plain `docker volume create` / `docker run` / `docker cp` — **not**
|
||||||
|
`docker compose create`, which **podman-compose** (the local dev runtime) does
|
||||||
|
not implement.
|
||||||
|
- `docker cp` rather than a bind mount of the source dir, because that bind mount
|
||||||
|
is exactly what fails on the containerized runner.
|
||||||
|
|
||||||
|
**Consequence: bare `docker compose up` no longer self-seeds** — the `external`
|
||||||
|
volumes must be populated first, so use **`make up`** (or `make <svc>-up`), which
|
||||||
|
seeds then starts. CI uses `make smoke`, which does the same.
|
||||||
|
|
||||||
**Why not the alternatives.**
|
**Why not the alternatives.**
|
||||||
|
|
||||||
|
- *Bake into a (possibly inline) image* — clean and portable, but it's a build;
|
||||||
|
rejected here because the goal was to use the upstream images verbatim.
|
||||||
- *Compose `configs:` with inline `content`* — Compose materialises these as a
|
- *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
|
temp file on the **client** side and bind-mounts it → same daemon-can't-see-it
|
||||||
daemon-can't-see-the-path problem.
|
problem.
|
||||||
- *A self-hosted runner that runs jobs on the host* — works, but reintroduces a
|
- *A self-hosted runner that runs jobs on the host* — bind mounts would then work
|
||||||
bespoke runner and undoes the move to the hosted `ubuntu-latest` label.
|
with zero seeding, but it 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,
|
No bind mounts of these config files remain, so the SELinux `:z`/`:Z` relabel flag
|
||||||
so the SELinux `:z`/`:Z` relabel flag is no longer needed anywhere in `infra/`,
|
is no longer needed anywhere in `infra/` (named volumes don't need relabeling).
|
||||||
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
|
## `--wait` fails on one-shot containers with no dependant
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,10 @@ The Makefile auto-points `DOCKER_HOST` at the Podman socket when it exists, so t
|
|||||||
resultaattypen — beyond the lean seed). List with `?status=alles`.
|
resultaattypen — beyond the lean seed). List with `?status=alles`.
|
||||||
- **Image tag.** Pinned to `openzaak/open-zaak:1.28.2` via `${OPENZAAK_TAG}` (bump
|
- **Image tag.** Pinned to `openzaak/open-zaak:1.28.2` via `${OPENZAAK_TAG}` (bump
|
||||||
deliberately, not via `:latest`).
|
deliberately, not via `:latest`).
|
||||||
- **Config is baked, not mounted.** `setup_configuration/data.yaml` is `COPY`-ed into
|
- **Config arrives via a volume, not a bind mount.** `setup_configuration/data.yaml`
|
||||||
a derived image via `oz-init`'s inline Dockerfile (`build.dockerfile_inline` in
|
is streamed into the external `rr-oz-config` volume by `infra/seed-config.sh`
|
||||||
the compose) rather than bind-mounted, so the init container finds it on Gitea's
|
(`docker cp`) and mounted at `/app/setup_configuration`, so the init container
|
||||||
containerized CI runner too. See [gitea-actions-gotchas.md](gitea-actions-gotchas.md).
|
finds it on Gitea's containerized CI runner too (bind mounts don't reach sibling
|
||||||
|
containers there). The image is the upstream `openzaak/open-zaak` verbatim — no
|
||||||
|
build. Run via `make openzaak-up` (seeds first). See
|
||||||
|
[gitea-actions-gotchas.md](gitea-actions-gotchas.md).
|
||||||
|
|||||||
@@ -47,17 +47,7 @@ services:
|
|||||||
networks: [cg]
|
networks: [cg]
|
||||||
|
|
||||||
oz-init:
|
oz-init:
|
||||||
# Derived image: base OpenZaak + the setup_configuration YAML baked in. We use
|
image: docker.io/openzaak/open-zaak:${OPENZAAK_TAG:-1.28.2}
|
||||||
# an inline Dockerfile (not a separate file, not a bind mount) because bind
|
|
||||||
# mounts don't reach sibling containers on the containerized CI runner.
|
|
||||||
# The ${OPENZAAK_TAG} below is interpolated by Compose. See
|
|
||||||
# docs/runbooks/gitea-actions-gotchas.md.
|
|
||||||
build:
|
|
||||||
context: ./openzaak
|
|
||||||
dockerfile_inline: |
|
|
||||||
FROM docker.io/openzaak/open-zaak:${OPENZAAK_TAG:-1.28.2}
|
|
||||||
COPY setup_configuration /app/setup_configuration
|
|
||||||
image: register-referentie/openzaak:dev
|
|
||||||
environment: &oz-env
|
environment: &oz-env
|
||||||
DJANGO_SETTINGS_MODULE: openzaak.conf.docker
|
DJANGO_SETTINGS_MODULE: openzaak.conf.docker
|
||||||
SECRET_KEY: ${OZ_SECRET_KEY:-dev-only-not-for-production}
|
SECRET_KEY: ${OZ_SECRET_KEY:-dev-only-not-for-production}
|
||||||
@@ -78,6 +68,10 @@ services:
|
|||||||
OPENZAAK_SUPERUSER_EMAIL: admin@localhost
|
OPENZAAK_SUPERUSER_EMAIL: admin@localhost
|
||||||
RUN_SETUP_CONFIG: "true"
|
RUN_SETUP_CONFIG: "true"
|
||||||
command: /setup_configuration.sh
|
command: /setup_configuration.sh
|
||||||
|
# data.yaml is streamed into this external volume by infra/seed-config.sh
|
||||||
|
# before start (bind mounts don't reach sibling containers on the CI runner).
|
||||||
|
volumes:
|
||||||
|
- oz-config:/app/setup_configuration:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
oz-db:
|
oz-db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
@@ -86,7 +80,7 @@ services:
|
|||||||
networks: [cg]
|
networks: [cg]
|
||||||
|
|
||||||
openzaak:
|
openzaak:
|
||||||
image: register-referentie/openzaak:dev
|
image: docker.io/openzaak/open-zaak:${OPENZAAK_TAG:-1.28.2}
|
||||||
environment: *oz-env
|
environment: *oz-env
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "python", "-c", "import requests,sys; sys.exit(0 if requests.head('http://localhost:8000/admin/').status_code in (200,302) else 1)"]
|
test: ["CMD", "python", "-c", "import requests,sys; sys.exit(0 if requests.head('http://localhost:8000/admin/').status_code in (200,302) else 1)"]
|
||||||
@@ -102,7 +96,7 @@ services:
|
|||||||
networks: [cg]
|
networks: [cg]
|
||||||
|
|
||||||
oz-celery:
|
oz-celery:
|
||||||
image: register-referentie/openzaak:dev
|
image: docker.io/openzaak/open-zaak:${OPENZAAK_TAG:-1.28.2}
|
||||||
environment: *oz-env
|
environment: *oz-env
|
||||||
command: /celery_worker.sh
|
command: /celery_worker.sh
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -193,14 +187,7 @@ services:
|
|||||||
|
|
||||||
# ── Keycloak (S-02) ──────────────────────────────────────────────────────
|
# ── Keycloak (S-02) ──────────────────────────────────────────────────────
|
||||||
keycloak:
|
keycloak:
|
||||||
# Derived image: base Keycloak + the realm exports baked into the import dir
|
image: quay.io/keycloak/keycloak:26.1
|
||||||
# (inline Dockerfile, no bind mount — see docs/runbooks/gitea-actions-gotchas.md).
|
|
||||||
build:
|
|
||||||
context: ./keycloak
|
|
||||||
dockerfile_inline: |
|
|
||||||
FROM quay.io/keycloak/keycloak:26.1
|
|
||||||
COPY realms /opt/keycloak/data/import
|
|
||||||
image: register-referentie/keycloak:dev
|
|
||||||
command: ["start-dev", "--import-realm"]
|
command: ["start-dev", "--import-realm"]
|
||||||
environment:
|
environment:
|
||||||
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
||||||
@@ -211,6 +198,9 @@ services:
|
|||||||
KC_HTTP_ENABLED: "true"
|
KC_HTTP_ENABLED: "true"
|
||||||
ports:
|
ports:
|
||||||
- "8180:8080"
|
- "8180:8080"
|
||||||
|
# realm exports are streamed into this external volume by infra/seed-config.sh.
|
||||||
|
volumes:
|
||||||
|
- kc-realms:/opt/keycloak/data/import:ro
|
||||||
networks: [cg]
|
networks: [cg]
|
||||||
|
|
||||||
# ── Flowable (S-03) ──────────────────────────────────────────────────────
|
# ── Flowable (S-03) ──────────────────────────────────────────────────────
|
||||||
@@ -244,16 +234,11 @@ services:
|
|||||||
networks: [cg]
|
networks: [cg]
|
||||||
|
|
||||||
flowable-init:
|
flowable-init:
|
||||||
# The BPMN is baked into a tiny curl image (build context = repo-root
|
image: docker.io/curlimages/curl:latest
|
||||||
# workflows/) instead of bind-mounted, so the deploy works on Gitea's
|
|
||||||
# containerized runner too. See docs/runbooks/gitea-actions-gotchas.md.
|
|
||||||
build:
|
|
||||||
context: ../workflows
|
|
||||||
dockerfile_inline: |
|
|
||||||
FROM docker.io/curlimages/curl:latest
|
|
||||||
COPY registratie.bpmn /work/registratie.bpmn
|
|
||||||
image: register-referentie/flowable-init:dev
|
|
||||||
restart: "no"
|
restart: "no"
|
||||||
|
# registratie.bpmn is streamed into this external volume by infra/seed-config.sh.
|
||||||
|
volumes:
|
||||||
|
- fl-bpmn:/work:ro
|
||||||
command:
|
command:
|
||||||
- sh
|
- sh
|
||||||
- -c
|
- -c
|
||||||
@@ -318,6 +303,18 @@ volumes:
|
|||||||
oz-db:
|
oz-db:
|
||||||
nrc-db:
|
nrc-db:
|
||||||
flowable-db:
|
flowable-db:
|
||||||
|
# Config volumes — created and populated out-of-band by infra/seed-config.sh
|
||||||
|
# (docker cp), because bind mounts don't reach sibling containers on the CI
|
||||||
|
# runner. `external` keeps the names deterministic; the seed step manages them.
|
||||||
|
oz-config:
|
||||||
|
external: true
|
||||||
|
name: rr-oz-config
|
||||||
|
kc-realms:
|
||||||
|
external: true
|
||||||
|
name: rr-kc-realms
|
||||||
|
fl-bpmn:
|
||||||
|
external: true
|
||||||
|
name: rr-fl-bpmn
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
cg:
|
cg:
|
||||||
|
|||||||
@@ -38,16 +38,11 @@ services:
|
|||||||
# Deploys workflows/registratie.bpmn via the REST API once flowable-rest is up.
|
# Deploys workflows/registratie.bpmn via the REST API once flowable-rest is up.
|
||||||
# Idempotent: skips if a deployment named "registratie" already exists.
|
# Idempotent: skips if a deployment named "registratie" already exists.
|
||||||
flowable-init:
|
flowable-init:
|
||||||
# The BPMN is baked into a tiny curl image (build context = repo-root
|
image: docker.io/curlimages/curl:latest
|
||||||
# workflows/) instead of bind-mounted, so the deploy works on Gitea's
|
|
||||||
# containerized runner too. See docs/runbooks/gitea-actions-gotchas.md.
|
|
||||||
build:
|
|
||||||
context: ../../workflows
|
|
||||||
dockerfile_inline: |
|
|
||||||
FROM docker.io/curlimages/curl:latest
|
|
||||||
COPY registratie.bpmn /work/registratie.bpmn
|
|
||||||
image: register-referentie/flowable-init:dev
|
|
||||||
restart: "no"
|
restart: "no"
|
||||||
|
# registratie.bpmn is streamed into this external volume by infra/seed-config.sh.
|
||||||
|
volumes:
|
||||||
|
- fl-bpmn:/work:ro
|
||||||
command:
|
command:
|
||||||
- sh
|
- sh
|
||||||
- -c
|
- -c
|
||||||
@@ -66,6 +61,10 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
flowable-db:
|
flowable-db:
|
||||||
|
# populated out-of-band by infra/seed-config.sh (docker cp) — see that script.
|
||||||
|
fl-bpmn:
|
||||||
|
external: true
|
||||||
|
name: rr-fl-bpmn
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
cg:
|
cg:
|
||||||
|
|||||||
@@ -9,14 +9,7 @@
|
|||||||
# Admin console: http://localhost:8180/ (admin / admin — dev only)
|
# Admin console: http://localhost:8180/ (admin / admin — dev only)
|
||||||
services:
|
services:
|
||||||
keycloak:
|
keycloak:
|
||||||
# Derived image: base Keycloak + realm exports baked into the import dir via an
|
image: quay.io/keycloak/keycloak:26.1
|
||||||
# inline Dockerfile. See docs/runbooks/gitea-actions-gotchas.md.
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile_inline: |
|
|
||||||
FROM quay.io/keycloak/keycloak:26.1
|
|
||||||
COPY realms /opt/keycloak/data/import
|
|
||||||
image: register-referentie/keycloak:dev
|
|
||||||
command: ["start-dev", "--import-realm"]
|
command: ["start-dev", "--import-realm"]
|
||||||
environment:
|
environment:
|
||||||
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
||||||
@@ -28,7 +21,15 @@ services:
|
|||||||
KC_HTTP_ENABLED: "true"
|
KC_HTTP_ENABLED: "true"
|
||||||
ports:
|
ports:
|
||||||
- "8180:8080"
|
- "8180:8080"
|
||||||
|
# realm exports are streamed into this external volume by infra/seed-config.sh.
|
||||||
|
volumes:
|
||||||
|
- kc-realms:/opt/keycloak/data/import:ro
|
||||||
networks: [cg]
|
networks: [cg]
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
kc-realms:
|
||||||
|
external: true
|
||||||
|
name: rr-kc-realms
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
cg:
|
cg:
|
||||||
|
|||||||
@@ -32,14 +32,7 @@ services:
|
|||||||
networks: [cg]
|
networks: [cg]
|
||||||
|
|
||||||
oz-init:
|
oz-init:
|
||||||
# Derived image: base OpenZaak + setup_configuration baked in via an inline
|
image: docker.io/openzaak/open-zaak:${OPENZAAK_TAG:-1.28.2}
|
||||||
# Dockerfile. See docs/runbooks/gitea-actions-gotchas.md for why not a mount.
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile_inline: |
|
|
||||||
FROM docker.io/openzaak/open-zaak:${OPENZAAK_TAG:-1.28.2}
|
|
||||||
COPY setup_configuration /app/setup_configuration
|
|
||||||
image: register-referentie/openzaak:dev
|
|
||||||
environment: &oz-env
|
environment: &oz-env
|
||||||
DJANGO_SETTINGS_MODULE: openzaak.conf.docker
|
DJANGO_SETTINGS_MODULE: openzaak.conf.docker
|
||||||
SECRET_KEY: ${OZ_SECRET_KEY:-dev-only-not-for-production}
|
SECRET_KEY: ${OZ_SECRET_KEY:-dev-only-not-for-production}
|
||||||
@@ -62,6 +55,9 @@ services:
|
|||||||
OPENZAAK_SUPERUSER_EMAIL: admin@localhost
|
OPENZAAK_SUPERUSER_EMAIL: admin@localhost
|
||||||
RUN_SETUP_CONFIG: "true"
|
RUN_SETUP_CONFIG: "true"
|
||||||
command: /setup_configuration.sh
|
command: /setup_configuration.sh
|
||||||
|
# data.yaml is streamed into this external volume by infra/seed-config.sh.
|
||||||
|
volumes:
|
||||||
|
- oz-config:/app/setup_configuration:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
oz-db:
|
oz-db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
@@ -70,7 +66,7 @@ services:
|
|||||||
networks: [cg]
|
networks: [cg]
|
||||||
|
|
||||||
openzaak:
|
openzaak:
|
||||||
image: register-referentie/openzaak:dev
|
image: docker.io/openzaak/open-zaak:${OPENZAAK_TAG:-1.28.2}
|
||||||
environment: *oz-env
|
environment: *oz-env
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "python", "-c", "import requests,sys; sys.exit(0 if requests.head('http://localhost:8000/admin/').status_code in (200,302) else 1)"]
|
test: ["CMD", "python", "-c", "import requests,sys; sys.exit(0 if requests.head('http://localhost:8000/admin/').status_code in (200,302) else 1)"]
|
||||||
@@ -86,7 +82,7 @@ services:
|
|||||||
networks: [cg]
|
networks: [cg]
|
||||||
|
|
||||||
oz-celery:
|
oz-celery:
|
||||||
image: register-referentie/openzaak:dev
|
image: docker.io/openzaak/open-zaak:${OPENZAAK_TAG:-1.28.2}
|
||||||
environment: *oz-env
|
environment: *oz-env
|
||||||
command: /celery_worker.sh
|
command: /celery_worker.sh
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -96,6 +92,10 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
oz-db:
|
oz-db:
|
||||||
|
# populated out-of-band by infra/seed-config.sh (docker cp) — see that script.
|
||||||
|
oz-config:
|
||||||
|
external: true
|
||||||
|
name: rr-oz-config
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
cg:
|
cg:
|
||||||
|
|||||||
45
infra/seed-config.sh
Executable file
45
infra/seed-config.sh
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Populate the external named *config* volumes that the upstream services mount,
|
||||||
|
# by `docker cp`-ing files into a throwaway helper container that mounts each one.
|
||||||
|
#
|
||||||
|
# Why: the compose stack uses the upstream images verbatim (no build). On Gitea's
|
||||||
|
# containerized runner, `docker compose` starts the stack as SIBLING containers
|
||||||
|
# via the host daemon, so a workspace bind mount resolves to a path the daemon
|
||||||
|
# can't see and is mounted empty. `docker cp` instead streams bytes over the
|
||||||
|
# Docker API, so the files reach the volume regardless of where the daemon runs.
|
||||||
|
# We use plain docker primitives (volume create / run / cp / rm) rather than
|
||||||
|
# `docker compose create`, because podman-compose (local dev) lacks that
|
||||||
|
# subcommand. Fixed-name `external` volumes keep the names deterministic across
|
||||||
|
# both runtimes. See docs/runbooks/gitea-actions-gotchas.md.
|
||||||
|
#
|
||||||
|
# Usage: seed-config.sh <key> [<key> ...] where key ∈ { oz, kc, fl }
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
HELPER="${SEED_HELPER_IMAGE:-docker.io/library/busybox:stable}"
|
||||||
|
|
||||||
|
populate() { # volume source(file or dir/.)
|
||||||
|
local vol="$1" src="$2" cid
|
||||||
|
docker volume rm -f "$vol" >/dev/null 2>&1 || true
|
||||||
|
docker volume create "$vol" >/dev/null
|
||||||
|
# A *created* (never started) helper is enough: the volume is attached at create
|
||||||
|
# time, `docker cp` writes through to it, and `docker rm` is instant (nothing to
|
||||||
|
# stop). `docker create` is a container subcommand both docker and podman have —
|
||||||
|
# unlike `docker compose create`, which podman-compose lacks.
|
||||||
|
cid="$(docker create -v "$vol:/dest" "$HELPER" true)"
|
||||||
|
docker cp "$src" "$cid:/dest/"
|
||||||
|
docker rm "$cid" >/dev/null
|
||||||
|
echo " seeded $vol"
|
||||||
|
}
|
||||||
|
|
||||||
|
[ "$#" -gt 0 ] || { echo "usage: seed-config.sh <oz|kc|fl> ..." >&2; exit 2; }
|
||||||
|
|
||||||
|
for key in "$@"; do
|
||||||
|
case "$key" in
|
||||||
|
oz) populate rr-oz-config "$here/openzaak/setup_configuration/." ;;
|
||||||
|
kc) populate rr-kc-realms "$here/keycloak/realms/." ;;
|
||||||
|
fl) populate rr-fl-bpmn "$here/../workflows/registratie.bpmn" ;;
|
||||||
|
*) echo "unknown seed key: $key" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
Reference in New Issue
Block a user