build(infra): run ClamAV in compose and on the cluster (closes #191) #193

Merged
not merged 5 commits from build/191-clamav into main 2026-10-02 07:53:17 +00:00
4 changed files with 41 additions and 2 deletions
Showing only changes of commit 39bc6ee0c5 - Show all commits
+1 -1
View File
@@ -333,7 +333,7 @@ jobs:
# Log dump must precede teardown (which removes the containers).
- name: Dump container logs on failure
if: failure()
run: docker compose -f infra/docker-compose.yml logs --no-color --tail=100 oz-init openzaak nrc-init nrc-web nrc-celery nrc-beat flowable-db flowable-rest flowable-init keycloak acl bff domain projection-db event-subscriber projection-api self-service openbaar behandel beheer objecttypen-db objecttypen-redis objecttypen-init objecttypen objecten-db objecten-redis objecten-init objecten objecten-celery registerrecord-init tempo prometheus grafana 2>&1 || true
run: docker compose -f infra/docker-compose.yml logs --no-color --tail=100 oz-init openzaak nrc-init nrc-web nrc-celery nrc-beat flowable-db flowable-rest flowable-init keycloak acl bff domain projection-db event-subscriber projection-api self-service openbaar behandel beheer objecttypen-db objecttypen-redis objecttypen-init objecttypen objecten-db objecten-redis objecten-init objecten objecten-celery registerrecord-init clamav tempo prometheus grafana 2>&1 || true
- name: Tear down
if: always()
run: make down
+1 -1
View File
@@ -10,7 +10,7 @@ COMPOSE := infra/docker-compose.yml
# Long-running services with a healthcheck — the smoke polls these for readiness
# (infra/wait-healthy.sh). One-shot init jobs (oz-init, nrc-init, flowable-init)
# are not polled; they only need to have run. See docs/runbooks/gitea-actions-gotchas.md.
WAIT_SVCS := openzaak nrc-web acl bff domain event-subscriber projection-api self-service openbaar behandel beheer objecttypen objecten
WAIT_SVCS := openzaak nrc-web acl bff domain event-subscriber projection-api self-service openbaar behandel beheer objecttypen objecten clamav
# 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
+21
View File
@@ -785,6 +785,26 @@ services:
condition: service_completed_successfully
networks: [cg]
# ClamAV daemon (S-28, ADR-0036): the domain scans uploaded diplomas over clamd's INSTREAM
# protocol on :3310 before they reach OpenZaak (S-29). The first start downloads ~300 MB of
# signatures with freshclam; the volume keeps them across restarts. clamd holds them in memory
# (~1.2 GB), and a reload would briefly hold two copies — ConcurrentDatabaseReload off prevents
# that, at the cost of clamd pausing scans during a signature reload.
clamav:
image: docker.io/clamav/clamav:1.4.6
environment:
CLAMD_CONF_ConcurrentDatabaseReload: "no"
# The image's own healthcheck (clamdcheck.sh: PING → PONG) polls every 30s; poll faster so
# wait-healthy sees it as soon as the signatures are loaded.
healthcheck:
test: ["CMD-SHELL", "clamdcheck.sh"]
interval: 5s
start_period: 360s
mem_limit: 2g
volumes:
- clamav-db:/var/lib/clamav
networks: [cg]
# ── Observability backplane (S-16a, ADR-0023) ──────────────────────────────
# Grafana-native stack: Tempo ingests OTLP traces (the .NET services export
# straight to it — no collector hop, S-16b), Prometheus scrapes service
@@ -836,6 +856,7 @@ volumes:
projection-db:
objecttypen-db:
objecten-db:
clamav-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.
+18
View File
@@ -588,6 +588,24 @@ workloads:
envFrom: [objecten]
waitFor: [objecten-db:5432, objecten-redis:6379]
# ── ClamAV (S-28, ADR-0036) ─────────────────────────────────────────────────
# The domain scans uploaded diplomas over clamd's INSTREAM protocol (S-29).
# First start pulls ~300 MB of signatures, so the node needs outbound internet
# (like seed-zaaktype); the data volume keeps them when persistence is on.
clamav:
image: docker.io/clamav/clamav:1.4.6
env:
CLAMD_CONF_ConcurrentDatabaseReload: "no"
ports: [{ name: clamd, port: 3310 }]
data: { mountPath: /var/lib/clamav, size: 1Gi }
probe:
exec: { command: [clamdcheck.sh] }
periodSeconds: 5
failureThreshold: 72
resources:
requests: { memory: 1200Mi }
limits: { memory: 2Gi }
# ── 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