forked from Suncrest-Labs/nester
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
276 lines (265 loc) · 9.85 KB
/
Copy pathdocker-compose.yml
File metadata and controls
276 lines (265 loc) · 9.85 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
services:
redis:
image: redis:7-alpine
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
postgres:
image: postgres:16-alpine
ports:
- "5432:5432"
environment:
POSTGRES_DB: nester_dev
POSTGRES_USER: nester
POSTGRES_PASSWORD: nester_dev_password
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U nester"]
interval: 5s
timeout: 5s
retries: 10
api:
build:
context: ./apps/api
dockerfile: Dockerfile.dev
ports:
- "8080:8080"
environment:
APP_ENV: development
DATABASE_DSN: postgres://nester:nester_dev_password@postgres:5432/nester_dev?sslmode=disable
REDIS_ADDR: redis:6379
STELLAR_NETWORK_PASSPHRASE: "Test SDF Network ; September 2015"
STELLAR_RPC_URL: https://soroban-testnet.stellar.org
STELLAR_HORIZON_URL: https://horizon-testnet.stellar.org
# DO NOT use in production — this is a development-only placeholder
AUTH_JWT_SECRET: dev-nester-jwt-secret-change-in-production
LOG_LEVEL: info
LOG_FORMAT: text
RUN_MIGRATIONS: "true"
ALLOWED_ORIGINS: http://localhost:3001
# Tracing (nester#1054). Off unless TRACING_ENABLED is exported, so the
# default compose workflow is unchanged. The endpoint targets the
# collector over the compose network — localhost:4317 would resolve to
# this container, not the collector.
TRACING_ENABLED: ${TRACING_ENABLED:-false}
OTEL_EXPORTER_OTLP_ENDPOINT: otel-collector:4317
OTEL_EXPORTER_OTLP_INSECURE: "true"
# 1.0 because the collector applies tail sampling: a trace the head
# drops never reaches it. See deploy/observability/otel-collector.yaml.
TRACING_SAMPLE_RATIO: ${TRACING_SAMPLE_RATIO:-1.0}
# Bound to all interfaces inside the container so Prometheus can reach
# it over the compose network. Deliberately NOT published under `ports`
# below: the metrics endpoint stays reachable only from inside the
# compose network, never from the host's public interface.
METRICS_ADDR: 0.0.0.0:9090
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- ./apps/api:/app
- go_mod_cache:/go/pkg/mod
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:8080/health || exit 1"]
interval: 10s
timeout: 5s
retries: 5
start_period: 15s
seed:
image: postgres:16-alpine
depends_on:
api:
condition: service_healthy
environment:
PGPASSWORD: nester_dev_password
volumes:
- ./scripts/seed.sql:/seed.sql:ro
command: ["psql", "-h", "postgres", "-U", "nester", "-d", "nester_dev", "-v", "ON_ERROR_STOP=1", "-f", "/seed.sql"]
frontend:
build:
context: ./apps/dapp/frontend
dockerfile: Dockerfile.dev
ports:
- "3001:3001"
environment:
NEXT_PUBLIC_API_URL: http://localhost:8080/api/v1
NEXT_PUBLIC_WS_URL: ws://localhost:8080/ws
NEXT_PUBLIC_NETWORK: testnet
INTELLIGENCE_SERVICE_URL: http://intelligence:8000
volumes:
- ./apps/dapp/frontend:/app
- /app/node_modules
- /app/.next
intelligence:
build:
context: ./apps/intelligence
ports:
- "8000:8000"
env_file:
# Optional: a fresh clone has no .env yet, and a hard requirement here
# makes every `docker compose` command fail to parse — even ones that
# never start this service.
- path: ./apps/intelligence/.env
required: false
environment:
INTELLIGENCE_REDIS_URL: redis://redis:6379/0
# See the api service above for why the endpoint is not localhost and
# why the sample ratio is 1.0 under the collector.
INTELLIGENCE_TRACING_ENABLED: ${INTELLIGENCE_TRACING_ENABLED:-false}
INTELLIGENCE_OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317
INTELLIGENCE_OTEL_EXPORTER_OTLP_INSECURE: "true"
INTELLIGENCE_TRACING_SAMPLE_RATIO: ${INTELLIGENCE_TRACING_SAMPLE_RATIO:-1.0}
# SLI exposition (nester#1056). Enabled by default because these are the
# unsampled counters an error budget is computed from; a service whose
# SLI stops being recorded reports a perfect success rate rather than an
# outage. The token is empty locally, which disables the scrape auth
# check — set it in any environment where the port is reachable.
INTELLIGENCE_METRICS_ENABLED: ${INTELLIGENCE_METRICS_ENABLED:-true}
INTELLIGENCE_METRICS_TOKEN: ${INTELLIGENCE_METRICS_TOKEN:-}
depends_on:
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
# --- Local observability: tracing (nester#1054) -----------------------
#
# Note for whoever merges second: PR #1065 (#1043, metrics) adds
# `prometheus` and `grafana` under this same profile. The two stacks are
# complementary and share no ports or volume names, so a conflict here is
# textual only — keep both blocks and both sets of volumes.
#
# Started only with an explicit profile:
# docker compose --profile observability up
#
# Both services are profile-gated, so a normal `docker compose up` is
# unchanged and tracing infrastructure is never a startup dependency for
# ordinary development.
#
# To send traces, run the app services with tracing switched on:
# TRACING_ENABLED=true INTELLIGENCE_TRACING_ENABLED=true # docker compose --profile observability up
#
# Then open the Jaeger UI at http://localhost:16686 and pick the
# "nester-api" or "nester-intelligence" service.
jaeger:
image: jaegertracing/all-in-one:1.62.0
profiles: ["observability"]
ports:
# Jaeger UI.
- "16686:16686"
environment:
# Jaeger accepts OTLP directly; the collector forwards to it here.
COLLECTOR_OTLP_ENABLED: "true"
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:16686/"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
otel-collector:
image: otel/opentelemetry-collector-contrib:0.115.1
profiles: ["observability"]
command: ["--config=/etc/otel/config.yaml"]
volumes:
- ./deploy/observability/otel-collector.yaml:/etc/otel/config.yaml:ro
ports:
# OTLP gRPC — what both services export to by default.
- "4317:4317"
# OTLP HTTP, for tools that cannot speak gRPC.
- "4318:4318"
depends_on:
# Restored in nester#1056: the #1065/#1067 merge left this key with an
# empty body, which makes the whole compose file fail to parse — every
# `docker compose` command, not only the observability profile.
jaeger:
condition: service_healthy
# Local observability stack. Started only with:
# docker compose --profile observability up
# Services without a profile keep starting as before, so the default
# developer workflow is unchanged.
prometheus:
image: prom/prometheus:v3.1.0
profiles: ["observability"]
ports:
- "9091:9090"
volumes:
- ./docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
# SLO recording and alerting rules (nester#1056). Mounted read-only from
# the repo so the rules Prometheus loads locally are byte-identical to
# the ones CI validates with promtool.
- ./docker/prometheus/rules:/etc/prometheus/rules:ro
- prometheus_data:/prometheus
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus
- --storage.tsdb.retention.time=24h
# The local stack is for looking at graphs, not for storing history;
# 24h keeps the volume small.
depends_on:
api:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:9090/-/healthy"]
interval: 10s
timeout: 5s
retries: 5
# Alertmanager (nester#1056). Receives the burn-rate alerts and applies the
# routing and inhibition policy in docker/alertmanager/alertmanager.yml.
#
# Its receivers are deliberately empty: a local stack must not be able to
# page anyone. Alerts are still inspectable in the UI at
# http://localhost:9093, which is what makes the routing testable.
alertmanager:
image: prom/alertmanager:v0.28.0
profiles: ["observability"]
ports:
- "9093:9093"
volumes:
- ./docker/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
- alertmanager_data:/alertmanager
command:
- --config.file=/etc/alertmanager/alertmanager.yml
- --storage.path=/alertmanager
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:9093/-/healthy"]
interval: 10s
timeout: 5s
retries: 5
grafana:
image: grafana/grafana:11.4.0
profiles: ["observability"]
ports:
- "3002:3000"
environment:
# Local-only convenience: anonymous viewer access so a developer does
# not have to log in to look at a graph. Never mirror this in a
# deployed environment.
GF_AUTH_ANONYMOUS_ENABLED: "true"
GF_AUTH_ANONYMOUS_ORG_ROLE: Admin
GF_SECURITY_ALLOW_EMBEDDING: "true"
volumes:
- ./docker/grafana/provisioning:/etc/grafana/provisioning:ro
# SLO dashboards (nester#1056), generated by
# scripts/build_slo_dashboards.py and committed. Every panel reads the
# recorded series the alerts fire on, so a dashboard cannot disagree
# with the pager during an incident.
- ./docker/grafana/dashboards:/etc/grafana/dashboards:ro
- grafana_data:/var/lib/grafana
depends_on:
prometheus:
condition: service_healthy
volumes:
postgres_data:
go_mod_cache:
prometheus_data:
alertmanager_data:
grafana_data: