From 1ed2d3a61147d9137db9248ea10a800de006826f Mon Sep 17 00:00:00 2001
From: hsiegeln <37154749+hsiegeln@users.noreply.github.com>
Date: Mon, 20 Apr 2026 15:52:24 +0200
Subject: [PATCH] chore(docker): full-stack docker-compose mirroring deploy/
k8s manifests
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Mirrors the k8s manifests in deploy/ as a local dev stack:
- cameleer-postgres (matches deploy/cameleer-postgres.yaml)
- cameleer-clickhouse (matches deploy/cameleer-clickhouse.yaml, default CLICKHOUSE_DB=cameleer)
- cameleer-server (built from Dockerfile, env mirrors deploy/base/server.yaml)
- cameleer-ui (built from ui/Dockerfile, served on host :8080 to leave :5173 free for Vite dev)
Dockerfile + ui/Dockerfile: REGISTRY_TOKEN is now optional (empty → skip Maven/npm auth).
cameleer-common package is public, so anonymous pulls succeed; private packages still require the token.
Backend defaults tuned for local E2E:
- RUNTIME_ENABLED=false (no Docker-in-Docker deployments in dev stack)
- OUTBOUND_HTTP_ALLOW_PRIVATE_TARGETS=true (so webhook tests can target host.docker.internal etc.)
- UIUSER/UIPASSWORD=admin/admin (matches Playwright E2E_ADMIN_USER/PASS defaults)
- CORS includes both :5173 (Vite) and :8080 (nginx)
---
Dockerfile | 12 +++--
docker-compose.yml | 123 ++++++++++++++++++++++++++++++++++++++++++++-
ui/Dockerfile | 10 ++--
3 files changed, 137 insertions(+), 8 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index aebfba83..3336cbf0 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,10 +1,14 @@
FROM --platform=$BUILDPLATFORM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /build
-# Configure Gitea Maven Registry for cameleer-common dependency
-ARG REGISTRY_TOKEN
-RUN mkdir -p ~/.m2 && \
- echo 'giteacameleer'${REGISTRY_TOKEN}'' > ~/.m2/settings.xml
+# Optional auth for Gitea Maven Registry. The `cameleer/cameleer-common` package
+# is published publicly, so empty token → anonymous pull (no settings.xml).
+# Private packages require a non-empty token.
+ARG REGISTRY_TOKEN=""
+RUN if [ -n "$REGISTRY_TOKEN" ]; then \
+ mkdir -p ~/.m2 && \
+ printf 'giteacameleer%s\n' "$REGISTRY_TOKEN" > ~/.m2/settings.xml; \
+ fi
COPY pom.xml .
COPY cameleer-server-core/pom.xml cameleer-server-core/
diff --git a/docker-compose.yml b/docker-compose.yml
index 5439cb51..2b4420da 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,6 +1,24 @@
+##
+## Local development + E2E stack. Mirrors the k8s manifests in deploy/ :
+## - cameleer-postgres (PG for RBAC/config/audit/alerting — Flyway migrates on server start)
+## - cameleer-clickhouse (OLAP for executions/logs/metrics/stats/diagrams)
+## - cameleer-server (Spring Boot backend; built from this repo's Dockerfile)
+## - cameleer-ui (nginx-served SPA; built from ui/Dockerfile)
+##
+## Usage:
+## docker compose up -d --build # full stack, detached
+## docker compose up -d cameleer-postgres cameleer-clickhouse # infra only (dev via mvn/vite)
+## docker compose down -v # stop + remove volumes
+##
+## Defaults match `application.yml` and the k8s base manifests. Production
+## k8s still owns the source of truth; this compose is for local iteration
+## and Playwright E2E. Secrets are non-sensitive dev placeholders.
+##
+
services:
cameleer-postgres:
image: postgres:16
+ container_name: cameleer-postgres
ports:
- "5432:5432"
environment:
@@ -8,7 +26,110 @@ services:
POSTGRES_USER: cameleer
POSTGRES_PASSWORD: cameleer_dev
volumes:
- - cameleer-pgdata:/home/postgres/pgdata/data
+ - cameleer-pgdata:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U cameleer -d cameleer"]
+ interval: 5s
+ timeout: 3s
+ retries: 20
+ restart: unless-stopped
+
+ cameleer-clickhouse:
+ image: clickhouse/clickhouse-server:24.12
+ container_name: cameleer-clickhouse
+ ports:
+ - "8123:8123"
+ - "9000:9000"
+ environment:
+ CLICKHOUSE_DB: cameleer
+ CLICKHOUSE_USER: default
+ CLICKHOUSE_PASSWORD: ""
+ # Allow the default user to manage access (matches k8s StatefulSet env)
+ CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: "1"
+ ulimits:
+ nofile:
+ soft: 262144
+ hard: 262144
+ volumes:
+ - cameleer-chdata:/var/lib/clickhouse
+ healthcheck:
+ # wget-less image: use clickhouse-client's ping equivalent
+ test: ["CMD-SHELL", "clickhouse-client --query 'SELECT 1' || exit 1"]
+ interval: 5s
+ timeout: 3s
+ retries: 20
+ restart: unless-stopped
+
+ cameleer-server:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ args:
+ # Public cameleer-common package — token optional. Override with
+ # REGISTRY_TOKEN=... in the shell env if you need a private package.
+ REGISTRY_TOKEN: ${REGISTRY_TOKEN:-}
+ container_name: cameleer-server
+ ports:
+ - "8081:8081"
+ environment:
+ SPRING_DATASOURCE_URL: jdbc:postgresql://cameleer-postgres:5432/cameleer?currentSchema=tenant_default&ApplicationName=tenant_default
+ SPRING_DATASOURCE_USERNAME: cameleer
+ SPRING_DATASOURCE_PASSWORD: cameleer_dev
+ SPRING_FLYWAY_USER: cameleer
+ SPRING_FLYWAY_PASSWORD: cameleer_dev
+ CAMELEER_SERVER_CLICKHOUSE_URL: jdbc:clickhouse://cameleer-clickhouse:8123/cameleer
+ CAMELEER_SERVER_CLICKHOUSE_USERNAME: default
+ CAMELEER_SERVER_CLICKHOUSE_PASSWORD: ""
+ # Auth / UI credentials — dev defaults; change before exposing the port.
+ CAMELEER_SERVER_SECURITY_UIUSER: admin
+ CAMELEER_SERVER_SECURITY_UIPASSWORD: admin
+ CAMELEER_SERVER_SECURITY_UIORIGIN: http://localhost:5173
+ CAMELEER_SERVER_SECURITY_CORSALLOWEDORIGINS: http://localhost:5173,http://localhost:8080
+ CAMELEER_SERVER_SECURITY_BOOTSTRAPTOKEN: dev-bootstrap-token-for-local-agent-registration
+ CAMELEER_SERVER_SECURITY_JWTSECRET: dev-jwt-secret-32-bytes-min-0123456789abcdef0123456789abcdef
+ # Runtime (Docker-in-Docker deployment) disabled for local stack
+ CAMELEER_SERVER_RUNTIME_ENABLED: "false"
+ CAMELEER_SERVER_TENANT_ID: default
+ # SSRF guard: allow private targets for dev (Playwright + local webhooks)
+ CAMELEER_SERVER_OUTBOUND_HTTP_ALLOW_PRIVATE_TARGETS: "true"
+ depends_on:
+ cameleer-postgres:
+ condition: service_healthy
+ cameleer-clickhouse:
+ condition: service_healthy
+ healthcheck:
+ # JRE image has wget; /api/v1/health is Actuator + Spring managed endpoint
+ test: ["CMD-SHELL", "wget -qO- http://localhost:8081/api/v1/health > /dev/null || exit 1"]
+ interval: 10s
+ timeout: 5s
+ retries: 12
+ start_period: 90s
+ restart: unless-stopped
+
+ cameleer-ui:
+ build:
+ context: ./ui
+ dockerfile: Dockerfile
+ args:
+ REGISTRY_TOKEN: ${REGISTRY_TOKEN:-}
+ container_name: cameleer-ui
+ # Host :8080 — Vite dev server (npm run dev:local) keeps :5173 for local iteration.
+ ports:
+ - "8080:80"
+ environment:
+ # nginx proxies /api → CAMELEER_API_URL
+ CAMELEER_API_URL: http://cameleer-server:8081
+ BASE_PATH: /
+ depends_on:
+ cameleer-server:
+ condition: service_healthy
+ healthcheck:
+ test: ["CMD-SHELL", "wget -qO- http://localhost/healthz > /dev/null || exit 1"]
+ interval: 5s
+ timeout: 3s
+ retries: 10
+ restart: unless-stopped
volumes:
cameleer-pgdata:
+ cameleer-chdata:
diff --git a/ui/Dockerfile b/ui/Dockerfile
index 132afbe9..a7bd7ada 100644
--- a/ui/Dockerfile
+++ b/ui/Dockerfile
@@ -1,15 +1,19 @@
FROM --platform=$BUILDPLATFORM node:22-alpine AS build
WORKDIR /app
-ARG REGISTRY_TOKEN
+ARG REGISTRY_TOKEN=""
COPY package.json package-lock.json .npmrc ./
-RUN echo "//gitea.siegeln.net/api/packages/cameleer/npm/:_authToken=${REGISTRY_TOKEN}" >> .npmrc && \
+RUN if [ -n "$REGISTRY_TOKEN" ]; then \
+ echo "//gitea.siegeln.net/api/packages/cameleer/npm/:_authToken=${REGISTRY_TOKEN}" >> .npmrc; \
+ fi && \
npm ci
COPY . .
# Upgrade design system to latest dev snapshot (after COPY to bust Docker cache)
-RUN echo "//gitea.siegeln.net/api/packages/cameleer/npm/:_authToken=${REGISTRY_TOKEN}" >> .npmrc && \
+RUN if [ -n "$REGISTRY_TOKEN" ]; then \
+ echo "//gitea.siegeln.net/api/packages/cameleer/npm/:_authToken=${REGISTRY_TOKEN}" >> .npmrc; \
+ fi && \
npm install @cameleer/design-system@dev && \
rm -f .npmrc