# Values for the BIG reference stack on Kubernetes. # # `workloads` is a near-literal transcription of infra/docker-compose.yml — same # service names, same images, same env, same one-shots — so the two stacks can be # diffed by eye. Read that file's comments for the *why* behind each setting; only # the deviations forced by Kubernetes are re-explained here. # # Every env value is rendered with Helm's `tpl`, so it may use: # {{ .Release.Namespace }} — for a cluster-internal FQDN # {{ .Values.host }} — the node address a browser reaches the cluster on # # Deviations from compose, all of them consequences of the platform: # * The compose stack hands the ACL and the seeds OpenZaak's *container IP*, # because OpenZaak and NRC validate URLs with Django's URLValidator and a # single-label host ("openzaak") is rejected. In Kubernetes the service FQDN # (openzaak..svc.cluster.local) is already multi-label, so the IP dance and # the `objecten.local` network alias both disappear. # * `depends_on: service_healthy` becomes a `waitFor` init container (TCP wait) # plus readiness probes. Ordering is otherwise not enforced: every bootstrap # job is idempotent and Kubernetes retries. # * The published ports are NodePorts (see `nodePorts`), not host ports. # The address a browser outside the cluster uses to reach the node: your Talos # VM's IP. It pins Keycloak's issuer and the portals' OIDC authority to one # string, so browser tokens and the BFF's discovered issuer agree. host: 192.168.122.100 # Set when pulling from a private registry (e.g. the Gitea Container Registry). imagePullSecrets: [] images: # Where the images built from THIS repo live. Empty = the bare # `register-referentie/:dev` names, which only works if the node already # has them. On Talos it never does — point this at a registry the node can # reach (see docs/runbooks/kubernetes-talos.md). registry: "" repositoryPrefix: register-referentie tag: dev # Applies to this repo's images only (see _helpers.tpl). Always, because `dev` # is a mutable tag: with IfNotPresent the node keeps the first image it pulled # and `make k8s-images` would appear to do nothing. The registry is in-cluster, # so a re-pull is local and cheap — but the pods do depend on it being up. pullPolicy: Always busybox: docker.io/library/busybox:stable persistence: # Empty = every database is an emptyDir, so the stack comes up on a bare # cluster with no CSI driver. Set to a StorageClass (e.g. `local-path`) to keep # the data across pod restarts. storageClass: "" # The public TLS edge (ADR-0035). Empty `domain` = no edge at all: nothing in # templates/edge.yaml is rendered and the stack is reached on the NodePorts below, # with `host` above pinning the OIDC origin. # # Set it and an in-cluster Caddy terminates TLS for `.`, gets its own # certificates from Let's Encrypt and proxies to the ClusterIP services. The node # only has to be reachable on the two NodePorts here — the Fedora host forwards # 80/443 to them (see docs/runbooks/kubernetes-talos.md). public: domain: "" # ACME registration address; Let's Encrypt uses it for expiry warnings. email: "" image: docker.io/library/caddy:2-alpine # : . `auth` is not free-form — big.keycloakUrl # builds the pinned issuer from it. routes: register: openbaar:80 mijn: self-service:80 behandel: behandel:80 beheer: beheer:80 auth: keycloak:8080 # Where the host's 80/443 forward lands. Not 30080/30443: 30080 is the BFF. nodePorts: http: 32080 https: 32443 # The only place a port is published outside the cluster. A workload listed here # gets a NodePort on its single port; everything else stays ClusterIP. nodePorts: openzaak: 30000 nrc-web: 30001 objecttypen: 30020 objecten: 30021 bff: 30080 flowable-rest: 30090 self-service: 30140 openbaar: 30141 behandel: 30142 beheer: 30143 keycloak: 30180 grafana: 30300 # ── Shared env blocks (the compose YAML anchors) ──────────────────────────────── envGroups: oz: UWSGI_PROCESSES: "1" UWSGI_THREADS: "2" DJANGO_SETTINGS_MODULE: openzaak.conf.docker SECRET_KEY: dev-only-not-for-production DB_HOST: oz-db DB_NAME: openzaak DB_USER: openzaak DB_PASSWORD: openzaak IS_HTTPS: "no" ALLOWED_HOSTS: "*" CACHE_DEFAULT: oz-redis:6379/0 CACHE_AXES: oz-redis:6379/0 CELERY_BROKER_URL: redis://oz-redis:6379/1 CELERY_RESULT_BACKEND: redis://oz-redis:6379/1 DISABLE_2FA: "true" NOTIFICATIONS_DISABLED: "false" OPENZAAK_SUPERUSER_USERNAME: admin DJANGO_SUPERUSER_PASSWORD: admin OPENZAAK_SUPERUSER_EMAIL: admin@localhost RUN_SETUP_CONFIG: "true" nrc: UWSGI_PROCESSES: "1" UWSGI_THREADS: "2" DJANGO_SETTINGS_MODULE: nrc.conf.docker SECRET_KEY: dev-only-not-for-production DB_HOST: nrc-db DB_NAME: opennotificaties DB_USER: opennotificaties DB_PASSWORD: opennotificaties IS_HTTPS: "no" ALLOWED_HOSTS: "*" CACHE_DEFAULT: nrc-redis:6379/0 CACHE_AXES: nrc-redis:6379/0 CELERY_BROKER_URL: redis://nrc-redis:6379/1 CELERY_RESULT_BACKEND: redis://nrc-redis:6379/1 DISABLE_2FA: "true" OPENNOTIFICATIES_SUPERUSER_USERNAME: admin DJANGO_SUPERUSER_PASSWORD: admin OPENNOTIFICATIES_SUPERUSER_EMAIL: admin@localhost RUN_SETUP_CONFIG: "true" NOTIFICATION_SEC_INTERVAL: "5" objecttypen: UWSGI_PROCESSES: "1" UWSGI_THREADS: "2" DJANGO_SETTINGS_MODULE: objecttypes.conf.docker SECRET_KEY: dev-only-not-for-production DB_HOST: objecttypen-db DB_NAME: objecttypes DB_USER: objecttypes DB_PASSWORD: objecttypes ALLOWED_HOSTS: "*" CACHE_DEFAULT: objecttypen-redis:6379/0 CACHE_AXES: objecttypen-redis:6379/0 DISABLE_2FA: "true" OTEL_SDK_DISABLED: "true" RUN_SETUP_CONFIG: "true" objecten: UWSGI_PROCESSES: "1" UWSGI_THREADS: "2" DJANGO_SETTINGS_MODULE: objects.conf.docker SECRET_KEY: dev-only-not-for-production DB_HOST: objecten-db DB_NAME: objects DB_USER: objects DB_PASSWORD: objects ALLOWED_HOSTS: "*" CACHE_DEFAULT: objecten-redis:6379/0 CACHE_AXES: objecten-redis:6379/0 DISABLE_2FA: "true" OTEL_SDK_DISABLED: "true" CELERY_BROKER_URL: redis://objecten-redis:6379/1 CELERY_RESULT_BACKEND: redis://objecten-redis:6379/1 NOTIFICATIONS_DISABLED: "false" RUN_SETUP_CONFIG: "true" # Traces for the .NET services. Always set, like compose: the exporter fails # harmlessly when Tempo is absent (services/*/Program.cs). otel: OTEL_EXPORTER_OTLP_ENDPOINT: http://tempo:4317 OTEL_EXPORTER_OTLP_PROTOCOL: grpc # ── Workloads ────────────────────────────────────────────────────────────────── # Per entry: image | own (built here) · args · envFrom (env groups) · env # ports · probe (a literal readinessProbe) · files (ConfigMap mounts) · data # (a database volume) · waitFor (host:port to wait for) · job · enabled # # `args` (never `command`) is the compose `command:` equivalent: compose replaces # the image's CMD, and so does Kubernetes' `args` — Kubernetes' `command` would # replace the ENTRYPOINT instead. The chart fails to render if you use `command`. workloads: # ── OpenZaak (S-01) ───────────────────────────────────────────────────────── oz-db: image: docker.io/postgis/postgis:17-3.5 args: [postgres, -c, max_connections=300] env: POSTGRES_USER: openzaak POSTGRES_PASSWORD: openzaak POSTGRES_DB: openzaak ports: [{ name: postgres, port: 5432 }] data: { mountPath: /var/lib/postgresql/data, size: 4Gi } probe: exec: command: [sh, -c, "pg_isready -U openzaak -d openzaak && psql -U openzaak -d openzaak -c 'SELECT PostGIS_Version();' -q"] periodSeconds: 5 oz-redis: image: docker.io/library/redis:7 ports: [{ name: redis, port: 6379 }] probe: { tcpSocket: { port: 6379 } } openzaak: image: docker.io/openzaak/open-zaak:1.28.2 # setup_configuration first, then the server — in ONE container, on purpose. # Both /setup_configuration.sh and /start.sh run `manage.py migrate`, so a # separate init Job (as compose has, ordered by depends_on) races this pod for # the same database and Django fails with "relation already exists". args: [sh, -c, "/setup_configuration.sh && exec /start.sh"] envFrom: [oz] ports: [{ name: http, port: 8000 }] # /admin/ answers 302 when Django is up — a redirect counts as ready. probe: httpGet: { path: /admin/, port: 8000 } initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 30 files: [{ configMap: rr-oz-config, mountPath: /app/setup_configuration }] waitFor: [oz-db:5432, oz-redis:6379] oz-celery: image: docker.io/openzaak/open-zaak:1.28.2 args: [/celery_worker.sh] envFrom: [oz] waitFor: [oz-db:5432, oz-redis:6379] # ── Open Notificaties / NRC (S-01-c) ──────────────────────────────────────── nrc-db: image: docker.io/postgis/postgis:17-3.5 args: [postgres, -c, max_connections=300] env: POSTGRES_USER: opennotificaties POSTGRES_PASSWORD: opennotificaties POSTGRES_DB: opennotificaties ports: [{ name: postgres, port: 5432 }] data: { mountPath: /var/lib/postgresql/data, size: 2Gi } probe: exec: { command: [pg_isready, -U, opennotificaties, -d, opennotificaties] } periodSeconds: 5 nrc-redis: image: docker.io/library/redis:7 ports: [{ name: redis, port: 6379 }] probe: { tcpSocket: { port: 6379 } } nrc-web: image: docker.io/openzaak/open-notificaties:1.16.1 # setup_configuration first, then the server — in ONE container, on purpose. # Both /setup_configuration.sh and /start.sh run `manage.py migrate`, so a # separate init Job (as compose has, ordered by depends_on) races this pod for # the same database and Django fails with "relation already exists". args: [sh, -c, "/setup_configuration.sh && exec /start.sh"] envFrom: [nrc] ports: [{ name: http, port: 8000 }] probe: httpGet: { path: /admin/, port: 8000 } initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 30 files: [{ configMap: rr-nrc-config, mountPath: /app/setup_configuration }] waitFor: [nrc-db:5432, nrc-redis:6379, openzaak:8000] nrc-celery: image: docker.io/openzaak/open-notificaties:1.16.1 args: [/celery_worker.sh] envFrom: [nrc] waitFor: [nrc-db:5432, nrc-redis:6379] # Without beat, notifications are accepted but never delivered (ADR-0007). nrc-beat: image: docker.io/openzaak/open-notificaties:1.16.1 args: [/celery_beat.sh] envFrom: [nrc] waitFor: [nrc-db:5432, nrc-redis:6379] # ── Keycloak (S-02) ───────────────────────────────────────────────────────── keycloak: image: quay.io/keycloak/keycloak:26.1 args: [start-dev, --import-realm] env: KC_BOOTSTRAP_ADMIN_USERNAME: admin KC_BOOTSTRAP_ADMIN_PASSWORD: admin KEYCLOAK_ADMIN: admin KEYCLOAK_ADMIN_PASSWORD: admin KC_HEALTH_ENABLED: "true" KC_HTTP_ENABLED: "true" # Pin the issuer to the address the browser uses, and let backchannel calls # keep using keycloak:8080 — the BFF discovers metadata in-cluster and gets # this issuer back, which is what browser tokens carry (infra/host-browser.yml). KC_HOSTNAME: '{{ include "big.keycloakUrl" . }}' KC_HOSTNAME_BACKCHANNEL_DYNAMIC: "true" ports: [{ name: http, port: 8080 }] # TCP, not /health/ready on the management port: nothing here gates on realm # import, and a wrong health path would leave the Service with no endpoints. probe: { tcpSocket: { port: 8080 }, initialDelaySeconds: 15 } files: [{ configMap: rr-kc-realms, mountPath: /opt/keycloak/data/import }] # ── Flowable (S-03) ───────────────────────────────────────────────────────── flowable-db: image: docker.io/library/postgres:16 env: POSTGRES_USER: flowable POSTGRES_PASSWORD: flowable POSTGRES_DB: flowable ports: [{ name: postgres, port: 5432 }] data: { mountPath: /var/lib/postgresql/data, size: 2Gi } probe: exec: { command: [pg_isready, -U, flowable, -d, flowable] } periodSeconds: 5 flowable-rest: image: docker.io/flowable/flowable-rest:latest env: SPRING_DATASOURCE_DRIVER-CLASS-NAME: org.postgresql.Driver SPRING_DATASOURCE_URL: jdbc:postgresql://flowable-db:5432/flowable SPRING_DATASOURCE_USERNAME: flowable SPRING_DATASOURCE_PASSWORD: flowable ports: [{ name: http, port: 8080 }] # Every REST path needs basic auth, so an httpGet probe would read 401 as # not-ready. TCP is the honest signal here. probe: { tcpSocket: { port: 8080 }, initialDelaySeconds: 20 } waitFor: [flowable-db:5432] # Deploys the BPMN to the process engine and the DMN to the DMN engine as two # separate deployments — flowable-rest does not cascade one into the other # (S-13, ADR-0016). Idempotent. flowable-init: job: true image: docker.io/curlimages/curl:latest args: - sh - -c - | svc=http://flowable-rest:8080/flowable-rest/service/repository/deployments dmn=http://flowable-rest:8080/flowable-rest/dmn-api/dmn-repository/deployments until curl -sf -u rest-admin:test "$svc" >/dev/null 2>&1; do echo "waiting for flowable-rest..."; sleep 3; done if curl -s -u rest-admin:test "$dmn" | grep -q '"name":"diploma-eligibility.dmn"'; then echo "diploma-eligibility DMN already deployed; skip" else curl -sf -u rest-admin:test -F 'file=@/work/diploma-eligibility.dmn;filename=diploma-eligibility.dmn' "$dmn" >/dev/null && echo "deployed diploma-eligibility DMN" fi if curl -s -u rest-admin:test "$svc?name=registratie" | grep -q '"name":"registratie"'; then echo "registratie BPMN already deployed; skip" else curl -sf -u rest-admin:test -F 'file=@/work/registratie.bpmn;filename=registratie.bpmn' "$svc" >/dev/null && echo "deployed registratie BPMN" fi files: [{ configMap: rr-fl-bpmn, mountPath: /work }] waitFor: [flowable-rest:8080] # ── ACL ───────────────────────────────────────────────────────────────────── acl: own: true envFrom: [otel] env: OTEL_SERVICE_NAME: acl # The FQDN, not `openzaak`: OpenZaak rejects a single-label host on # zaak-create. It must be the same host the zaaktype was seeded through # (see the seed-zaaktype job) so the URLs stay host-consistent (ADR-0009). Acl__OpenZaak__BaseUrl: "http://openzaak.{{ .Release.Namespace }}.svc.cluster.local:8000/" Acl__OpenZaak__ClientId: big-reference-seed Acl__OpenZaak__Secret: insecure-dev-secret-change-me Acl__Defaults__Bronorganisatie: "517439943" Acl__Defaults__VerantwoordelijkeOrganisatie: "517439943" Acl__Defaults__Vertrouwelijkheidaanduiding: openbaar Acl__Defaults__ZaaktypeIdentificatie: BIG-REGISTRATIE Acl__Defaults__InformatieobjecttypeOmschrijving: Diploma # Objecten reflects the request Host into the object url it returns, and # publishes that url to NRC — which rejects a single-label host. The FQDN # replaces compose's `objecten.local` alias (ADR-0029). Acl__Objecten__BaseUrl: "http://objecten.{{ .Release.Namespace }}.svc.cluster.local:8000/" Acl__Objecten__Token: 1234567890abcdef1234567890abcdef12345678 # Short name on purpose: Objecten only accepts an objecttype URL that # matches the one it was configured with (infra/objecten/setup_configuration # /data.yaml → http://objecttypen:8000/api/v2/). Acl__Objecten__ObjecttypenBaseUrl: http://objecttypen:8000/ Acl__Objecten__ObjecttypenToken: 0123456789abcdef0123456789abcdef01234567 Acl__Objecten__ObjecttypeName: RegisterRecord ports: [{ name: http, port: 8080 }] probe: { httpGet: { path: /health, port: 8080 }, periodSeconds: 5 } # ── BIG Domain Service (S-05) ─────────────────────────────────────────────── domain: own: true envFrom: [otel] env: OTEL_SERVICE_NAME: domain Flowable__BaseUrl: http://flowable-rest:8080/flowable-rest/ Flowable__Username: rest-admin Flowable__Password: test Acl__BaseUrl: http://acl:8080/ ports: [{ name: http, port: 8080 }] probe: { httpGet: { path: /health, port: 8080 }, periodSeconds: 5 } # ── BFF ───────────────────────────────────────────────────────────────────── bff: own: true envFrom: [otel] env: OTEL_SERVICE_NAME: bff # In-cluster authority: Keycloak's discovery document returns the pinned # KC_HOSTNAME issuer, which is what browser tokens carry (ADR-0010). Keycloak__Authority: http://keycloak:8080/realms/digid Keycloak__MedewerkerAuthority: http://keycloak:8080/realms/medewerker Downstream__Domain__BaseUrl: http://domain:8080/ Downstream__Projection__BaseUrl: http://projection-api:8080/ Downstream__Acl__BaseUrl: http://acl:8080/ ports: [{ name: http, port: 8080 }] probe: { httpGet: { path: /health, port: 8080 }, periodSeconds: 5 } # ── Read projection (S-06) ────────────────────────────────────────────────── projection-db: image: docker.io/library/postgres:16 env: POSTGRES_USER: projection POSTGRES_PASSWORD: projection POSTGRES_DB: projection ports: [{ name: postgres, port: 5432 }] data: { mountPath: /var/lib/postgresql/data, size: 2Gi } probe: exec: { command: [pg_isready, -U, projection, -d, projection] } periodSeconds: 5 event-subscriber: own: true envFrom: [otel] env: OTEL_SERVICE_NAME: event-subscriber ConnectionStrings__Projection: Host=projection-db;Database=projection;Username=projection;Password=projection Acl__BaseUrl: http://acl:8080/ EventSubscriber__Webhook__AuthToken: Bearer big-reference-notifications ports: [{ name: http, port: 8080 }] probe: { httpGet: { path: /health, port: 8080 }, periodSeconds: 5 } # It migrates the projection schema on start and throws if the DB is absent. waitFor: [projection-db:5432] projection-api: own: true envFrom: [otel] env: OTEL_SERVICE_NAME: projection-api ConnectionStrings__Projection: Host=projection-db;Database=projection;Username=projection;Password=projection ports: [{ name: http, port: 8080 }] probe: { httpGet: { path: /health, port: 8080 }, periodSeconds: 5 } waitFor: [projection-db:5432] # ── Portals (S-08/S-09/S-12/S-15) ─────────────────────────────────────────── # Caddy serves the Angular app and reverse-proxies its endpoint group to # http://bff:8080 — hence the Service must stay named `bff`. Caddy resolves that # name through the system resolver, so the DNS search domains apply and no # upstream rewriting is needed here (ADR-0034). self-service: own: true ports: [{ name: http, port: 80 }] probe: { httpGet: { path: /, port: 80 }, periodSeconds: 5 } files: - configMap: portal-config-digid mountPath: /usr/share/caddy/config.json subPath: config.json openbaar: own: true ports: [{ name: http, port: 80 }] probe: { httpGet: { path: /, port: 80 }, periodSeconds: 5 } behandel: own: true ports: [{ name: http, port: 80 }] probe: { httpGet: { path: /, port: 80 }, periodSeconds: 5 } files: - configMap: portal-config-medewerker mountPath: /usr/share/caddy/config.json subPath: config.json beheer: own: true ports: [{ name: http, port: 80 }] probe: { httpGet: { path: /, port: 80 }, periodSeconds: 5 } files: - configMap: portal-config-medewerker mountPath: /usr/share/caddy/config.json subPath: config.json # ── Objecttypen API (S-18a) ───────────────────────────────────────────────── objecttypen-db: image: docker.io/library/postgres:17-alpine env: POSTGRES_USER: objecttypes POSTGRES_PASSWORD: objecttypes POSTGRES_DB: objecttypes ports: [{ name: postgres, port: 5432 }] data: { mountPath: /var/lib/postgresql/data, size: 2Gi } probe: exec: { command: [pg_isready, -U, objecttypes] } periodSeconds: 5 objecttypen-redis: image: docker.io/library/redis:7 ports: [{ name: redis, port: 6379 }] probe: { tcpSocket: { port: 6379 } } objecttypen: image: docker.io/maykinmedia/objecttypes-api:3.4.2 # setup_configuration first, then the server — in ONE container, on purpose. # Both /setup_configuration.sh and /start.sh run `manage.py migrate`, so a # separate init Job (as compose has, ordered by depends_on) races this pod for # the same database and Django fails with "relation already exists". args: [sh, -c, "/setup_configuration.sh && exec /start.sh"] envFrom: [objecttypen] ports: [{ name: http, port: 8000 }] probe: httpGet: { path: /admin/, port: 8000 } initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 30 files: [{ configMap: rr-objecttypen-config, mountPath: /app/setup_configuration }] waitFor: [objecttypen-db:5432, objecttypen-redis:6379] # The RegisterRecord objecttype + published version, over the API (S-18c, # ADR-0020/ADR-0027). The uuid is pinned — Objecten identifies it by uuid. registerrecord-init: job: true image: docker.io/library/python:3-slim args: [python, /config/register.py] env: OBJECTTYPEN: http://objecttypen:8000 OBJECTTYPEN_TOKEN: 0123456789abcdef0123456789abcdef01234567 SCHEMA: /config/registerrecord.schema.json files: [{ configMap: rr-registerrecord-config, mountPath: /config }] waitFor: [objecttypen:8000] # ── Objecten API (S-18b) ──────────────────────────────────────────────────── objecten-db: image: docker.io/postgis/postgis:17-3.5 env: POSTGRES_USER: objects POSTGRES_PASSWORD: objects POSTGRES_DB: objects ports: [{ name: postgres, port: 5432 }] data: { mountPath: /var/lib/postgresql/data, size: 2Gi } probe: exec: { command: [pg_isready, -U, objects] } periodSeconds: 5 objecten-redis: image: docker.io/library/redis:7 ports: [{ name: redis, port: 6379 }] probe: { tcpSocket: { port: 6379 } } objecten: image: docker.io/maykinmedia/objects-api:3.4.0 # setup_configuration first, then the server — in ONE container, on purpose. # Both /setup_configuration.sh and /start.sh run `manage.py migrate`, so a # separate init Job (as compose has, ordered by depends_on) races this pod for # the same database and Django fails with "relation already exists". args: [sh, -c, "/setup_configuration.sh && exec /start.sh"] envFrom: [objecten] ports: [{ name: http, port: 8000 }] probe: httpGet: { path: /admin/, port: 8000 } initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 30 files: [{ configMap: rr-objecten-config, mountPath: /app/setup_configuration }] waitFor: [objecten-db:5432, objecten-redis:6379, objecttypen:8000] # Delivers Objecten's notifications to NRC; without it every register write is # silently undelivered (ADR-0029). objecten-celery: image: docker.io/maykinmedia/objects-api:3.4.0 args: [/celery_worker.sh] envFrom: [objecten] waitFor: [objecten-db:5432, objecten-redis:6379] # ── Bootstrap the flow, like the local compose stack does (S-B04, ADR-0020) ── # Seeds + publishes the BIG zaaktype through the same FQDN the ACL uses, so the # server-assigned URLs are host-consistent. The ACL then resolves them by # identificatie (S-27, ADR-0021) — nothing is injected back. # Publishing validates the resultaattype against the external Selectielijst # API, so the node needs outbound internet for this one job (ADR-0006). seed-zaaktype: job: true image: docker.io/library/python:3-slim args: [python, /seed/seed_catalogus.py] env: OZ_BASE: "http://openzaak.{{ .Release.Namespace }}.svc.cluster.local:8000" OZ_PUBLISH: "1" files: [{ configMap: rr-seed-scripts, mountPath: /seed }] waitFor: [openzaak:8000] # Registers the NRC abonnement on the `objecten` kanaal pointing at the # event-subscriber, so register writes reach the projection (ADR-0030). # Without it the openbaar register stays empty. Restart-safe and idempotent. nrc-subscribe: job: true image: docker.io/library/python:3-slim args: [python, /seed/register-abonnement.py] env: NRC_BASE: http://nrc-web:8000 # The script resolves this to an address for the callback URL; the FQDN # resolves to the Service's (stable) ClusterIP, which NRC's URLValidator # accepts — the compose stack uses the container IP for the same reason. SINK_HOST: "event-subscriber.{{ .Release.Namespace }}.svc.cluster.local" SINK_PORT: "8080" SINK_AUTH: Bearer big-reference-notifications files: [{ configMap: rr-seed-scripts, mountPath: /seed }] waitFor: [nrc-web:8000, event-subscriber:8080] # ── Observability backplane (S-16a, ADR-0023) ─────────────────────────────── # Off by default: these are built images too (config baked in), so switching # them on also means pushing three more images. Enable all three together. tempo: enabled: false own: true args: ["-config.file=/etc/tempo.yaml"] ports: [{ name: otlp, port: 4317 }, { name: http, port: 3200 }] prometheus: enabled: false own: true ports: [{ name: http, port: 9090 }] grafana: enabled: false own: true env: GF_SECURITY_ADMIN_USER: admin GF_SECURITY_ADMIN_PASSWORD: admin GF_AUTH_ANONYMOUS_ENABLED: "true" ports: [{ name: http, port: 3000 }]