Repository navigation
Expand file tree
/
Copy pathdocker-compose.observability.yml
More file actions
251 lines (241 loc) · 13 KB
/
Copy pathdocker-compose.observability.yml
File metadata and controls
251 lines (241 loc) · 13 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
# Local telemetry/observability stack for Kairo (KAI-126, Phase 1 — local only).
#
# ONE shared ClickHouse server (`clickhouse` service) for both products, in
# separate databases — mirrors the intended end-state where both eventually
# point at a single ClickHouse Cloud service:
# - Langfuse (self-hosted, adapted from docker.langfuse.com/langfuse/langfuse-*:4's
# official docker-compose.yml) — LLM/AI tracing, database `langfuse`.
# - ClickStack (individual-services compose from github.com/ClickHouse/clickstack,
# not the all-in-one image — that one bundles its own unreachable ClickHouse) —
# general app observability via OpenTelemetry, database `default`.
#
# Ports are remapped to avoid the Supabase CLI (54320-54329, 8083) and app dev ports
# (landing/kelan :3000, api :3001, dashboard :5173).
#
# Usage: docker compose -f docker-compose.observability.yml up -d
# See docs/observability.md for first-run setup (API keys, .env.local wiring).
services:
# ---------------------------------------------------------------------------
# Shared ClickHouse — one server, two databases (langfuse / default)
# ---------------------------------------------------------------------------
clickhouse:
image: docker.io/clickhouse/clickhouse-server:25.12
restart: unless-stopped
user: "101:101"
environment:
CLICKHOUSE_DB: default
CLICKHOUSE_USER: clickhouse
CLICKHOUSE_PASSWORD: ${LANGFUSE_CLICKHOUSE_PASSWORD:-clickhouse} # CHANGEME
volumes:
- observability_clickhouse_data:/var/lib/clickhouse
- observability_clickhouse_logs:/var/log/clickhouse-server
- ./docker/clickhouse-init:/docker-entrypoint-initdb.d:ro
ports:
- "127.0.0.1:8124:8123"
- "127.0.0.1:9001:9000"
healthcheck:
test: wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1
interval: 5s
timeout: 5s
retries: 10
start_period: 1s
# ---------------------------------------------------------------------------
# Langfuse (self-hosted) — LLM telemetry, database `langfuse` on `clickhouse`
# ---------------------------------------------------------------------------
langfuse-worker:
image: docker.langfuse.com/langfuse/langfuse-worker:4
restart: unless-stopped
depends_on: &langfuse-depends-on
langfuse-postgres:
condition: service_healthy
langfuse-minio:
condition: service_healthy
langfuse-redis:
condition: service_healthy
clickhouse:
condition: service_healthy
environment: &langfuse-worker-env
NEXTAUTH_URL: ${LANGFUSE_NEXTAUTH_URL:-http://localhost:3003}
DATABASE_URL: postgresql://postgres:${LANGFUSE_POSTGRES_PASSWORD:-postgres}@langfuse-postgres:5432/postgres
SALT: ${LANGFUSE_SALT:?set LANGFUSE_SALT in .env.local, see docs/observability.md} # CHANGEME
ENCRYPTION_KEY: ${LANGFUSE_ENCRYPTION_KEY:?set LANGFUSE_ENCRYPTION_KEY in .env.local, see docs/observability.md} # CHANGEME
TELEMETRY_ENABLED: "false"
CLICKHOUSE_MIGRATION_URL: clickhouse://clickhouse:9000
CLICKHOUSE_URL: http://clickhouse:8123
CLICKHOUSE_USER: clickhouse
CLICKHOUSE_PASSWORD: ${LANGFUSE_CLICKHOUSE_PASSWORD:-clickhouse} # CHANGEME
# Own database on the shared server — keeps Langfuse's schema
# (traces/observations/scores) out of ClickStack's `default` database.
CLICKHOUSE_DB: langfuse
# Single-node ClickHouse, no Zookeeper — must stay false or migrations
# try `ON CLUSTER` / ReplicatedMergeTree and fail to start.
CLICKHOUSE_CLUSTER_ENABLED: "false"
LANGFUSE_S3_EVENT_UPLOAD_BUCKET: langfuse
LANGFUSE_S3_EVENT_UPLOAD_REGION: auto
LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID: minio
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_MINIO_SECRET:-miniosecret} # CHANGEME
LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT: http://langfuse-minio:9000
LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE: "true"
LANGFUSE_S3_EVENT_UPLOAD_PREFIX: events/
LANGFUSE_S3_MEDIA_UPLOAD_BUCKET: langfuse
LANGFUSE_S3_MEDIA_UPLOAD_REGION: auto
LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID: minio
LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_MINIO_SECRET:-miniosecret} # CHANGEME
LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT: http://langfuse-minio:9000
LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: "true"
LANGFUSE_S3_MEDIA_UPLOAD_PREFIX: media/
REDIS_HOST: langfuse-redis
REDIS_PORT: "6379"
REDIS_AUTH: ${LANGFUSE_REDIS_PASSWORD:-myredissecret} # CHANGEME
langfuse-web:
image: docker.langfuse.com/langfuse/langfuse:4
restart: unless-stopped
depends_on: *langfuse-depends-on
ports:
- "3003:3000"
environment:
<<: *langfuse-worker-env
NEXTAUTH_SECRET: ${LANGFUSE_NEXTAUTH_SECRET:?set LANGFUSE_NEXTAUTH_SECRET in .env.local, see docs/observability.md} # CHANGEME
LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT: http://localhost:9090
LANGFUSE_S3_MEDIA_UPLOAD_INTERNAL_ENDPOINT: http://langfuse-minio:9000
# Headless init (KAI-189) — auto-provisions org/project/user/API-key pair
# on first boot, so local dev/scripts never need the manual UI signup.
LANGFUSE_INIT_ORG_ID: kairo
LANGFUSE_INIT_ORG_NAME: Kairo
LANGFUSE_INIT_PROJECT_ID: kairo-local
LANGFUSE_INIT_PROJECT_NAME: Kairo (local)
LANGFUSE_INIT_PROJECT_PUBLIC_KEY: ${LANGFUSE_INIT_PROJECT_PUBLIC_KEY:?set LANGFUSE_INIT_PROJECT_PUBLIC_KEY in .env.local, see docs/observability.md}
LANGFUSE_INIT_PROJECT_SECRET_KEY: ${LANGFUSE_INIT_PROJECT_SECRET_KEY:?set LANGFUSE_INIT_PROJECT_SECRET_KEY in .env.local, see docs/observability.md}
LANGFUSE_INIT_USER_EMAIL: ${LANGFUSE_INIT_USER_EMAIL:-local@kairo.dev}
LANGFUSE_INIT_USER_NAME: Kairo Local
LANGFUSE_INIT_USER_PASSWORD: ${LANGFUSE_INIT_USER_PASSWORD:-changeme-local-only}
langfuse-minio:
image: cgr.dev/chainguard/minio
restart: unless-stopped
entrypoint: sh
command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
environment:
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: ${LANGFUSE_MINIO_SECRET:-miniosecret} # CHANGEME
ports:
- "9090:9000"
- "127.0.0.1:9091:9001"
volumes:
- langfuse_minio_data:/data
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 1s
timeout: 5s
retries: 5
start_period: 1s
langfuse-redis:
image: docker.io/redis:7
restart: unless-stopped
command: >
--requirepass ${LANGFUSE_REDIS_PASSWORD:-myredissecret}
--maxmemory-policy noeviction
ports:
- "127.0.0.1:6380:6379"
volumes:
- langfuse_redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 3s
timeout: 10s
retries: 10
langfuse-postgres:
image: docker.io/postgres:17
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 3s
timeout: 3s
retries: 10
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${LANGFUSE_POSTGRES_PASSWORD:-postgres} # CHANGEME
POSTGRES_DB: postgres
TZ: UTC
PGTZ: UTC
ports:
- "127.0.0.1:5433:5432"
volumes:
- langfuse_postgres_data:/var/lib/postgresql/data
# ---------------------------------------------------------------------------
# ClickStack (individual services) — app observability via OpenTelemetry,
# database `default` on the shared `clickhouse` server. Image names/tags
# from github.com/ClickHouse/clickstack's own .env (CODE_VERSION 2.19.0).
# ---------------------------------------------------------------------------
clickstack-otel-collector:
image: docker.clickhouse.com/clickhouse/clickstack-otel-collector:2
restart: unless-stopped
depends_on:
clickhouse:
condition: service_healthy
environment:
CLICKHOUSE_ENDPOINT: "tcp://clickhouse:${LANGFUSE_CLICKHOUSE_PASSWORD:-clickhouse}@clickhouse:9000?dial_timeout=10s"
# The schema-seed step (separate from ingestion) authenticates as this
# user/password pair rather than parsing CLICKHOUSE_ENDPOINT's DSN.
CLICKHOUSE_USER: clickhouse
CLICKHOUSE_PASSWORD: ${LANGFUSE_CLICKHOUSE_PASSWORD:-clickhouse}
HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE: default
HYPERDX_LOG_LEVEL: info
OPAMP_SERVER_URL: http://clickstack-app:4320
# KAI-189: must stay false — DEFAULT_SOURCES below (copied verbatim
# from ClickStack's own compose) references `TimestampTime`, a column
# that only exists in the non-legacy schema. Legacy schema only has
# `Timestamp`, and the UI errors with "Unknown expression or function
# identifier TimestampTime" on every log/session query if this is true.
HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA: "false"
ports:
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
clickstack-app:
image: docker.hyperdx.io/hyperdx/hyperdx:2
restart: unless-stopped
depends_on:
clickhouse:
condition: service_healthy
clickstack-mongo:
condition: service_started
ports:
- "8080:8080" # HyperDX UI
- "8000:8000" # HyperDX API
environment:
FRONTEND_URL: http://localhost:8080
HYPERDX_API_PORT: "8000"
HYPERDX_APP_PORT: "8080"
HYPERDX_APP_URL: http://localhost
HYPERDX_LOG_LEVEL: info
MONGO_URI: mongodb://clickstack-mongo:27017/hyperdx
SERVER_URL: http://127.0.0.1:8000
OPAMP_PORT: "4320"
# KAI-189: fixed key so provisioning scripts don't depend on a manually
# created Personal API Key. See scripts/observability/ for whether this
# works as the dashboards/alerts API Bearer token too.
HYPERDX_API_KEY: ${HYPERDX_API_KEY:?set HYPERDX_API_KEY in .env.local, see docs/observability.md}
OTEL_EXPORTER_OTLP_ENDPOINT: http://clickstack-otel-collector:4318
OTEL_SERVICE_NAME: hdx-oss-app
USAGE_STATS_ENABLED: "false"
DEFAULT_CONNECTIONS: >-
[{"name":"Local ClickHouse","host":"http://clickhouse:8123","username":"clickhouse","password":"${LANGFUSE_CLICKHOUSE_PASSWORD:-clickhouse}"}]
DEFAULT_SOURCES: >-
[{"from":{"databaseName":"default","tableName":"otel_logs"},"kind":"log","timestampValueExpression":"Timestamp","name":"Logs","displayedTimestampValueExpression":"Timestamp","implicitColumnExpression":"Body","serviceNameExpression":"ServiceName","bodyExpression":"Body","eventAttributesExpression":"LogAttributes","resourceAttributesExpression":"ResourceAttributes","defaultTableSelectExpression":"Timestamp,ServiceName,SeverityText,Body","severityTextExpression":"SeverityText","traceIdExpression":"TraceId","spanIdExpression":"SpanId","connection":"Local ClickHouse","traceSourceId":"Traces","sessionSourceId":"Sessions","metricSourceId":"Metrics"},{"from":{"databaseName":"default","tableName":"otel_traces"},"kind":"trace","timestampValueExpression":"Timestamp","name":"Traces","displayedTimestampValueExpression":"Timestamp","implicitColumnExpression":"SpanName","serviceNameExpression":"ServiceName","eventAttributesExpression":"SpanAttributes","resourceAttributesExpression":"ResourceAttributes","defaultTableSelectExpression":"Timestamp,ServiceName,StatusCode,round(Duration/1e6),SpanName","traceIdExpression":"TraceId","spanIdExpression":"SpanId","durationExpression":"Duration","durationPrecision":9,"parentSpanIdExpression":"ParentSpanId","spanNameExpression":"SpanName","spanKindExpression":"SpanKind","statusCodeExpression":"StatusCode","statusMessageExpression":"StatusMessage","connection":"Local ClickHouse","logSourceId":"Logs","sessionSourceId":"Sessions","metricSourceId":"Metrics"},{"from":{"databaseName":"default","tableName":""},"kind":"metric","timestampValueExpression":"TimeUnix","name":"Metrics","resourceAttributesExpression":"ResourceAttributes","metricTables":{"gauge":"otel_metrics_gauge","histogram":"otel_metrics_histogram","sum":"otel_metrics_sum"},"connection":"Local ClickHouse","logSourceId":"Logs","traceSourceId":"Traces","sessionSourceId":"Sessions"},{"from":{"databaseName":"default","tableName":"hyperdx_sessions"},"kind":"session","timestampValueExpression":"Timestamp","name":"Sessions","displayedTimestampValueExpression":"Timestamp","implicitColumnExpression":"Body","serviceNameExpression":"ServiceName","bodyExpression":"Body","eventAttributesExpression":"LogAttributes","resourceAttributesExpression":"ResourceAttributes","defaultTableSelectExpression":"Timestamp,ServiceName,SeverityText,Body","severityTextExpression":"SeverityText","traceIdExpression":"TraceId","spanIdExpression":"SpanId","connection":"Local ClickHouse","logSourceId":"Logs","traceSourceId":"Traces","metricSourceId":"Metrics"}]
clickstack-mongo:
image: docker.io/mongo:5.0.32-focal
restart: unless-stopped
volumes:
- observability_mongo_data:/data/db
volumes:
langfuse_postgres_data:
driver: local
observability_clickhouse_data:
driver: local
observability_clickhouse_logs:
driver: local
langfuse_minio_data:
driver: local
langfuse_redis_data:
driver: local
observability_mongo_data:
driver: local