-
Notifications
You must be signed in to change notification settings - Fork 25
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
435 lines (409 loc) · 19 KB
/
Copy pathdocker-compose.yml
File metadata and controls
435 lines (409 loc) · 19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
# =============================================================================
# WKS Platform — LOCAL DEVELOPMENT ONLY. This stack is NOT production-ready:
# it runs Keycloak in `start-dev`, uses demo/admin credentials, and validates
# no secrets. For production see docker/docker-compose.prod.yml (separate path).
#
# ONE FILE, driven by Compose profiles + env. Each concern is its own profile;
# the app services are env-driven so ANY combination min->max loads from one file.
#
# docker compose up -d --build # FULL stack (default profiles+env in .env)
# docker compose down # stop (keeps data volumes)
#
# # MINIMAL: zero-dependency backend (embedded H2 + dev-token, no infra):
# COMPOSE_PROFILES=app,portal \
# WKS_SPRING_PROFILES=db-h2 WKS_AUTH_MODE=dev-token WKS_AUTHZ_OPA_ENABLED=false \
# WKS_BPM_ENGINE=none WKS_TENANCY_MULTI_TENANT=false WKS_SEED_ENABLED=true \
# docker compose up -d --build
#
# Infra profiles (concern -> profile): mongodb, keycloak, opa, camunda
# (camunda + c7-external-tasks), storage (minio + storage-api), storage-fs
# (storage-api alone, MinIO-free). App/aux profiles: app (case-engine-rest-api),
# portal, notifications, proxy, demo.
# Document storage mode (REACT_APP_STORAGE_MODE, default minio): minio needs the
# `storage` profile, filesystem needs `storage-fs`. `inline` needs NEITHER — bytes
# ride on the case document as base64 (minimal app,portal deploy; small docs/demos).
# Concern env knobs (defaults = full/secure): WKS_AUTH_MODE, WKS_AUTHZ_OPA_ENABLED,
# WKS_BPM_ENGINE, WKS_TENANCY_MULTI_TENANT, WKS_SEED_ENABLED, DRIVER_STORAGE_FACTORYCLASS;
# WKS_SPRING_PROFILES carries the jpa datasource (db-h2 / db-postgres). Any point on
# the spectrum = COMPOSE_PROFILES=<infra subset> + matching env.
# App images are pulled from GHCR (public) by default; --build compiles locally
# (required for minimal/filesystem — the published image predates these).
# Camunda 8 is experimental/outdated — see experimental/camunda8/.
# =============================================================================
name: wks-platform
# Image/build/port for the single env-driven case-engine-rest-api service.
x-case-engine-rest-api: &case-engine-rest-api
image: ${WKS_REGISTRY:-ghcr.io/wkspower}/case-engine-rest-api:${WKS_VERSION:-develop}
build:
context: apps/java
dockerfile: services/case-engine-rest-api/Dockerfile
ports:
- 8081:8081
# Image/build/port for the single env-driven storage-api service.
x-storage-api: &storage-api
image: ${WKS_REGISTRY:-ghcr.io/wkspower}/storage-api:${WKS_VERSION:-develop}
build:
context: apps/java
dockerfile: services/storage-api/Dockerfile
ports:
- 8085:8085
services:
# ------------------------------------------------------------------ core
# (no profile → always started)
minio:
image: quay.io/minio/minio
profiles: [storage]
command: server /data --console-address ":9090"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
ports:
- 9000:9000
- 9090:9090
environment:
- MINIO_ROOT_USER=${MINIO_ROOT_USER}
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
volumes:
- minio:/data:rw
mongodb:
image: mongo:6.0.14
profiles: [mongodb]
ports:
- 27017:27017
healthcheck:
test: mongosh --eval 'db.stats().ok' --quiet
interval: 10s
retries: 3
start_period: 5s
timeout: 10s
volumes:
- mongo:/data/db:rw
opa:
# Upstream OPA with rules live-mounted from ./opa (no build needed).
image: openpolicyagent/opa:0.49.2-static
profiles: [opa]
ports:
- 8181:8181
command:
- run
- --server
- /etc/rules/wks_policy_rules.rego
volumes:
- ./opa:/etc/rules:ro
keycloak:
image: quay.io/keycloak/keycloak:26.6.1
profiles: [keycloak]
command: start-dev
environment:
KC_HEALTH_ENABLED: "true"
# KC 26 renamed the bootstrap-admin vars; the old KEYCLOAK_ADMIN[_PASSWORD]
# still work but log a deprecation warning.
KC_BOOTSTRAP_ADMIN_USERNAME: ${KEYCLOAK_ADMIN}
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
# KC 25+ serves health/metrics on a dedicated management port (9000), not
# the main HTTP port. The 26.x image also ships no curl/wget, so probe the
# readiness endpoint over bash's /dev/tcp instead.
healthcheck:
test:
- CMD
- bash
- -c
- 'exec 3<>/dev/tcp/localhost/9000 && printf "GET /health/ready HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n" >&3 && grep -q "200 OK" <&3'
interval: 10s
retries: 10
start_period: 5s
timeout: 20s
ports:
- 8082:8080
volumes:
- keycloak:/opt/keycloak/data/
# One env-driven storage-api (started by the `storage` or `storage-fs` profile).
# Defaults to the MinIO driver + Keycloak/OPA (full). For MinIO-free local-disk:
# DRIVER_STORAGE_FACTORYCLASS=filesystem WKS_AUTH_MODE=dev-token
# WKS_AUTHZ_OPA_ENABLED=false COMPOSE_PROFILES=...,storage-fs
# In dev-token mode no extra wiring is needed: WKS_DEVTOKEN_ISSUER_URL below
# defaults to the engine's service name, so storage-api fetches the dev-issuer
# JWKS from the engine over the Docker network (not from its own localhost).
# The MinIO container is only pulled in under the `storage` profile, and the
# dependency is required:false so storage-fs runs without it. Build from source
# for the filesystem driver (the GHCR image predates it).
storage-api:
<<: *storage-api
profiles: [storage, storage-fs]
environment:
- DRIVER_STORAGE_FACTORYCLASS=${DRIVER_STORAGE_FACTORYCLASS:-minio}
- WKS_AUTH_MODE=${WKS_AUTH_MODE:-keycloak}
- WKS_AUTHZ_OPA_ENABLED=${WKS_AUTHZ_OPA_ENABLED:-true}
- OPA_URL=${OPA_URL}
- KEYCLOAK_URL=${KEYCLOAK_URL}
# dev-token validation issuer — defaults to the engine's service name so
# storage-api reaches the issuing engine over the Docker network (used
# only when WKS_AUTH_MODE=dev-token; ignored in keycloak mode).
- WKS_DEVTOKEN_ISSUER_URL=${WKS_DEVTOKEN_ISSUER_URL:-http://case-engine-rest-api:8081/dev-auth}
- WKS_CORS_ALLOWED_ORIGINS=${WKS_CORS_ALLOWED_ORIGINS}
- MINIO_HOST_INTERNAL=${MINIO_HOST_INTERNAL}
- MINIO_HOST_EXTERNAL=${MINIO_HOST_EXTERNAL}
- MINIO_ROOT_USER=${MINIO_ROOT_USER}
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
- STORAGE_FS_BASEPATH=${STORAGE_FS_BASEPATH:-/data/storage}
- DRIVER_STORAGE_UPLOADS_BACKEND_PROTOCOL=${DRIVER_STORAGE_UPLOADS_BACKEND_PROTOCOL:-http}
- DRIVER_STORAGE_UPLOADS_BACKEND_URL=${DRIVER_STORAGE_UPLOADS_BACKEND_URL:-localhost}
- DRIVER_STORAGE_UPLOADS_BACKEND_PORT=${DRIVER_STORAGE_UPLOADS_BACKEND_PORT:-9000}
depends_on:
minio:
condition: service_healthy
required: false
volumes:
- storage-fs:/data/storage
camunda:
image: ${CAMUNDA_DOCKER_IMAGE}:${CAMUNDA7_VERSION}
profiles: [camunda]
command: ./camunda.sh --rest --webapps
ports:
- 8080:8080
healthcheck:
test: curl --fail http://localhost:8080/engine-rest/version || exit 1
interval: 10s
retries: 3
start_period: 5s
timeout: 10s
# One env-driven case-engine-rest-api (profile: app). Every concern defaults to
# the full, secure stack and is overridable by env: WKS_AUTH_MODE, WKS_BPM_ENGINE,
# WKS_AUTHZ_OPA_ENABLED, WKS_TENANCY_MULTI_TENANT, WKS_SEED_ENABLED. Datastore
# selection that needs a datasource (jpa) is carried by a Spring profile via
# WKS_SPRING_PROFILES (db-h2 or db-postgres); mongo is the default, no profile.
# Optional infra is depends_on ... required:false, so the SAME service runs
# minimal (no infra) or full (mongodb+camunda enabled via COMPOSE_PROFILES).
# Minimal recipe: WKS_SPRING_PROFILES=db-h2 WKS_AUTH_MODE=dev-token
# WKS_AUTHZ_OPA_ENABLED=false WKS_BPM_ENGINE=none WKS_TENANCY_MULTI_TENANT=false
# WKS_SEED_ENABLED=true COMPOSE_PROFILES=app[,portal]
# (build from source: the GHCR image is older)
case-engine-rest-api:
<<: *case-engine-rest-api
profiles: [app]
environment:
# Datastore profile (datasource-carrying); empty = mongo default.
- SPRING_PROFILES_ACTIVE=${WKS_SPRING_PROFILES:-}
# Per-concern flags (defaults reproduce the full, secure stack).
- WKS_AUTH_MODE=${WKS_AUTH_MODE:-keycloak}
- WKS_AUTHZ_OPA_ENABLED=${WKS_AUTHZ_OPA_ENABLED:-true}
- WKS_BPM_ENGINE=${WKS_BPM_ENGINE:-camunda7}
- WKS_TENANCY_MULTI_TENANT=${WKS_TENANCY_MULTI_TENANT:-true}
- WKS_SEED_ENABLED=${WKS_SEED_ENABLED:-false}
# Swagger/OpenAPI toggles. springdoc-openapi is incompatible with Spring
# Boot 4 and CRASHES context startup (issue #541), so the API docs are
# disabled by default to keep the engine bootable. Set these to true once
# the springdoc/SB4 fix lands to restore Swagger UI.
- SPRINGDOC_API_DOCS_ENABLED=${SPRINGDOC_API_DOCS_ENABLED:-false}
- SPRINGDOC_SWAGGER_UI_ENABLED=${SPRINGDOC_SWAGGER_UI_ENABLED:-false}
# Infra connection coordinates (used by whichever concerns are active).
- CAMUNDA_VERSION=${CAMUNDA_VERSION:-camunda7}
- CAMUNDA_BASE_URL=${CAMUNDA_BASE_URL}
- MONGO_DATABASE=${MONGO_WKS_DATABASE}
- MONGO_CONN=${MONGO_CONNECTION_URL}
- KEYCLOAK_URL=${KEYCLOAK_URL}
# dev-token validation issuer — service-name default so it resolves the
# same from any container (used only when WKS_AUTH_MODE=dev-token).
- WKS_DEVTOKEN_ISSUER_URL=${WKS_DEVTOKEN_ISSUER_URL:-http://case-engine-rest-api:8081/dev-auth}
- OPA_URL=${OPA_URL}
- WKS_CORS_ALLOWED_ORIGINS=${WKS_CORS_ALLOWED_ORIGINS}
# Legacy released images (the Camunda 8 era, e.g. v1.4.x) bundle a
# Zeebe client that can't reach a broker in Camunda 7 mode and reports
# health DOWN; the client is mandatory there, so we drop its health
# contributor. Harmless on develop/source-built images (no Zeebe).
- MANAGEMENT_HEALTH_ZEEBE_ENABLED=false
depends_on:
# Optional: only enforced when the infra profile is also active.
mongodb:
condition: service_healthy
required: false
camunda:
condition: service_healthy
required: false
c7-external-tasks:
image: ${WKS_REGISTRY:-ghcr.io/wkspower}/c7-external-tasks:${WKS_VERSION:-develop}
profiles: [camunda]
build:
context: apps/java
dockerfile: services/c7-external-tasks/Dockerfile
environment:
- CAMUNDA_BASE_URL=${CAMUNDA_BASE_URL}
- CAMUNDA_USERNAME=${CAMUNDA_USERNAME}
- CAMUNDA_PASSWORD=${CAMUNDA_PASSWORD}
- KEYCLOAK_TOKEN_URL=${KEYCLOAK_TOKEN_URL}
- WKS_CASE_API_URL=${WKS_CASE_API_URL}
- WEBSOCKET_ENABLED=${WEBSOCKET_ENABLED}
- DISABLE_BACKOFF_STRATEGY=${DISABLE_BACKOFF_STRATEGY}
# Kafka publishing — baked in but inert unless KAFKA_ENABLED=true
# (activate together with the `notifications` profile).
- KAFKA_ENABLED=${KAFKA_ENABLED:-false}
- KAFKA_URL=${KAFKA_URL}
- KAFKA_TOPIC_CASE_CREATE=${KAFKA_TOPIC_CASE_CREATE}
- KAFKA_TOPIC_CASE_EMAIL_OUTBOUND=${KAFKA_TOPIC_CASE_EMAIL_OUTBOUND}
depends_on:
camunda:
condition: service_healthy
# ------------------------------------------------------------- portal
# profile: portal (enabled by default via COMPOSE_PROFILES in .env)
case-portal:
image: ${WKS_REGISTRY:-ghcr.io/wkspower}/case-portal:${WKS_VERSION:-develop}
profiles: [portal]
build:
# Repo-root context so the portal's internal dependency
# @wkspower/case-config-schema (packages/case-config-schema) resolves.
context: .
dockerfile: apps/react/case-portal/Dockerfile
args:
GENERATE_SOURCEMAP: "false"
environment:
__SERVER_AUTH_MODE__: ${REACT_APP_AUTH_MODE:-keycloak}
__SERVER_AUTH_ISSUER_URL__: ${REACT_APP_AUTH_ISSUER_URL:-}
__SERVER_API_URL__: ${REACT_APP_API_URL}
__SERVER_STORAGE_URL__: ${REACT_APP_STORAGE_URL}
__SERVER_STORAGE_MODE__: ${REACT_APP_STORAGE_MODE:-minio}
__SERVER_WEBSOCKETS_ENABLED__: ${REACT_APP_WEBSOCKETS_ENABLED}
__SERVER_WEBSOCKETS_URL__: ${REACT_APP_WEBSOCKETS_URL}
__SERVER_WEBSOCKETS_CASE_CREATED__: ${REACT_APP_WEBSOCKETS_CASE_CREATED}
__SERVER_WEBSOCKETS_HUMAN_TASK_CREATED__: ${REACT_APP_WEBSOCKETS_HUMAN_TASK_CREATED}
__SERVER_NOVU_ENABLED__: ${REACT_APP_NOVU_ENABLED}
__SERVER_NOVU_PUBLISHER_API_URL__: ${REACT_APP_NOVU_PUBLISHER_API_URL}
ports:
- 3001:80
# ------------------------------------------------------ notifications
# profile: notifications — Kafka event bus + the consumers that act on it.
# Set KAFKA_ENABLED=true so the engine side actually publishes.
zookeeper:
image: confluentinc/cp-zookeeper:latest
profiles: [notifications]
container_name: zookeeper
ports:
- "2181:2181"
environment:
ZOOKEEPER_CLIENT_PORT: 2181
kafka:
image: wurstmeister/kafka:latest
profiles: [notifications]
container_name: kafka
ports:
- "9092:9092"
- "9093:9093"
environment:
KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9093,OUTSIDE://localhost:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
KAFKA_LISTENERS: INSIDE://kafka:9093,OUTSIDE://kafka:9092
KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
depends_on:
- zookeeper
email-sender:
image: ${WKS_REGISTRY:-ghcr.io/wkspower}/email-sender:${WKS_VERSION:-develop}
profiles: [notifications]
build:
context: apps/node/email-sender
environment:
- LOG_LEVEL=${EMAIL_SENDER_LOG_LEVEL}
- KAFKA_URL=${KAFKA_URL}
- KAFKA_TOPIC=${KAFKA_TOPIC_CASE_EMAIL_OUTBOUND}
- WKS_CASE_API_URL=${WKS_CASE_API_URL}
- JWT_TOKEN_URL=${KEYCLOAK_TOKEN_URL}
- JWT_TOKEN_CLIENT_ID=${MAIL_TO_CASE_JWT_TOKEN_CLIENT_ID}
- JWT_TOKEN_CLIENT_SECRET=${MAIL_TO_CASE_JWT_TOKEN_CLIENT_SECRET}
- JWT_TOKEN_GRANT_TYPE=${MAIL_TO_CASE_JWT_TOKEN_GRANT_TYPE}
depends_on:
- kafka
websocket-publisher:
image: ${WKS_REGISTRY:-ghcr.io/wkspower}/websocket-publisher:${WKS_VERSION:-develop}
profiles: [notifications]
build:
context: apps/node/websocket-publisher
ports:
- "8484:8484"
environment:
- LOG_LEVEL=${WEBSOCKET_LOG_LEVEL}
- WEBSOCKET_PORT=8484
- KAFKA_URL=${KAFKA_URL}
depends_on:
- kafka
novu-publisher:
image: ${WKS_REGISTRY:-ghcr.io/wkspower}/novu-publisher:${WKS_VERSION:-develop}
profiles: [notifications]
build:
context: apps/node/novu-publisher
ports:
- 3002:3002
environment:
- LOG_LEVEL=${NOVU_LOG_LEVEL}
- KAFKA_URL=${KAFKA_URL}
- NOVU_TRIGGER_URL=${NOVU_TRIGGER_URL}
- NOVU_API_KEY=${NOVU_API_KEY}
- NOVU_APP_ID=${NOVU_APP_ID}
- NOVU_CASE_CREATE_WORKFLOW=${KAFKA_TOPIC_CASE_CREATE}
- NOVU_HUMAN_TASK_CREATE_WORKFLOW=${KAFKA_TOPIC_CREATE_HUMAN_TASK}
depends_on:
- kafka
# --------------------------------------------------------------- proxy
# profile: proxy — Traefik reverse proxy / dashboard (optional).
traefik:
image: traefik:v2.8
profiles: [proxy]
command:
- --log.level=debug
- --api.insecure=true
- --api.dashboard=true
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.docker=true
- --experimental.hub=true
- --providers.docker.exposedbydefault=false
- --serversTransport.insecureSkipVerify=true
- --providers.file.watch=true
- --providers.file.directory=/traefik
ports:
- 80:80
- 443:443
- 8888:8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./configs/traefik:/traefik:ro
# ---------------------------------------------------------------- demo
# profile: demo (on by default) — one-shot loader that BOOTSTRAPS the
# Keycloak realm/clients/`demo` user required to log in AND seeds sample
# cases/forms/processes, then exits 0. Idempotent: safe to re-run (logs
# 409/"already exists" and continues). Drop it with COMPOSE_PROFILES=portal,
# but then the portal has no realm/user to log in against.
demo-data-loader:
image: ${WKS_REGISTRY:-ghcr.io/wkspower}/demo-data-loader:${WKS_VERSION:-develop}
profiles: [demo]
build:
context: apps/java
dockerfile: services/demo-data-loader/Dockerfile
environment:
- CAMUNDA7_DATA_IMPORT_ENABLED=true
- CAMUNDA8_DATA_IMPORT_ENABLED=false
- CAMUNDA_URL=${CAMUNDA_BASE_URL}
- MONGO_DATABASE=${MONGO_DEMO_DATA_LOADER_DATABASE}
- MONGO_CONN=${MONGO_CONNECTION_URL}
- KEYCLOAK_URL=${KEYCLOAK_URL}
- KEYCLOAK_DEFAULT_USER=${KEYCLOAK_DEFAULT_USER}
- KEYCLOAK_DEFAULT_USER_PASSWORD=${KEYCLOAK_DEFAULT_USER_PASSWORD}
- KEYCLOAK_DEFAULT_USER_EMAIL=${KEYCLOAK_DEFAULT_USER_EMAIL}
- KEYCLOAK_DEFAULT_USER_FIRST_NAME=${KEYCLOAK_DEFAULT_USER_FIRST_NAME}
- KEYCLOAK_DEFAULT_USER_LAST_NAME=${KEYCLOAK_DEFAULT_USER_LAST_NAME}
depends_on:
mongodb:
condition: service_healthy
camunda:
condition: service_healthy
keycloak:
condition: service_healthy
volumes:
mongo:
driver: local
minio:
driver: local
keycloak:
driver: local
storage-fs:
driver: local