Repository navigation
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
341 lines (325 loc) · 10.5 KB
/
Copy pathdocker-compose.yml
File metadata and controls
341 lines (325 loc) · 10.5 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
# ⚠️ 开发阶段配置:所有服务端口绑定 0.0.0.0(局域网可访问)。
# 生产环境务必恢复为 127.0.0.1 绑定(仅本机),并前置 HTTPS 反向代理。
name: pg2meili
# 注:本锚点只保留「Docker 内部服务地址 / 端口」等无法从 .env.docker 直接取同名键的变量。
# 其余应用配置(PG_CONN_STRING、CORS_ALLOW_ORIGINS、LOG_*、KAFKA_API_KEY_TOPIC、
# 各类密钥等)一律由下方 env_file: ./.env.docker 注入,避免 environment 覆盖 env_file
# 导致「改 .env.docker 不生效」的历史问题(详见 docs/optimization-plan-2026-08-05.md 之环境变量单源化 I-1/P0-4)。
x-unidata-environment: &unidata-environment
SERVER_PORT: :8080
KAFKA_BOOTSTRAP_SERVERS: kafka:9093
KAFKA_MEILI_COMMAND_TOPIC: ${KAFKA_COMMAND_TOPIC:-meili.commands}
REDIS_URL: redis://redis:6379/0
services:
postgres:
image: postgres:16
restart: unless-stopped
ports:
- "${POSTGRES_PORT:-5432}:5432"
env_file:
- path: ./.env.docker
required: false
command:
- postgres
- -c
- wal_level=logical
- -c
- max_replication_slots=5
- -c
- max_wal_senders=5
volumes:
- pgdata:/var/lib/postgresql/data
- ./docker/postgres-init:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 12
zookeeper:
image: quay.io/debezium/zookeeper:2.4
restart: unless-stopped
ports:
- "${ZOOKEEPER_PORT:-2181}:2181"
kafka:
image: quay.io/debezium/kafka:2.4
restart: unless-stopped
ports:
- "${KAFKA_PORT:-9092}:9092"
environment:
ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
KAFKA_LISTENERS: INSIDE://0.0.0.0:9093,OUTSIDE://0.0.0.0:9092
KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9093,OUTSIDE://${KAFKA_EXTERNAL_HOST:-localhost}:${KAFKA_PORT:-9092}
KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
depends_on:
zookeeper:
condition: service_started
healthcheck:
test: ["CMD-SHELL", "/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9093 --list >/dev/null 2>&1"]
interval: 5s
timeout: 5s
retries: 24
start_period: 15s
kafka-init:
image: quay.io/debezium/kafka:2.4
restart: "no"
environment:
KAFKA_BOOTSTRAP_SERVER: kafka:9093
KAFKA_API_KEY_TOPIC: ${KAFKA_API_KEY_TOPIC:-api_keys.events}
KAFKA_COMMAND_TOPIC: ${KAFKA_COMMAND_TOPIC:-meili.commands}
KAFKA_DLQ_TOPIC: ${KAFKA_DLQ_TOPIC:-meili.dlq}
KAFKA_TOPIC_PARTITIONS: ${KAFKA_TOPIC_PARTITIONS:-3}
KAFKA_TOPIC_REPLICATION_FACTOR: ${KAFKA_TOPIC_REPLICATION_FACTOR:-1}
volumes:
- ./docker/kafka-init.sh:/opt/unidata/kafka-init.sh:ro
entrypoint: ["/bin/bash", "/opt/unidata/kafka-init.sh"]
depends_on:
kafka:
condition: service_healthy
connect:
image: quay.io/debezium/connect:2.4
restart: unless-stopped
ports:
- "${CONNECT_PORT:-8083}:8083"
environment:
BOOTSTRAP_SERVERS: kafka:9093
GROUP_ID: "1"
CONFIG_STORAGE_TOPIC: my_connect_configs
OFFSET_STORAGE_TOPIC: my_connect_offsets
STATUS_STORAGE_TOPIC: my_connect_statuses
extra_hosts:
- host.docker.internal:host-gateway
depends_on:
kafka-init:
condition: service_completed_successfully
kafka-ui:
# 纯调试工具,默认不启动;需要时 docker compose --profile debug up -d kafka-ui
image: provectuslabs/kafka-ui:v0.7.2
profiles: ["debug"]
restart: unless-stopped
ports:
- "${KAFKA_UI_PORT:-8085}:8080"
environment:
KAFKA_CLUSTERS_0_NAME: local
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9093
depends_on:
kafka-init:
condition: service_completed_successfully
# 一次性服务:向 Kafka Connect 注册 Debezium PostgreSQL CDC connector。
# 这是打通「PG → Kafka → Meilisearch」链路的关键一步,否则数据不会进入 Kafka。
connect-init:
image: curlimages/curl:8.10.0
restart: "no"
env_file:
- path: ./.env.docker
required: false
environment:
CONNECT_URL: http://connect:8083
POSTGRES_HOST: postgres
POSTGRES_PORT: 5432
CDC_TABLE_INCLUDE_LIST: ${CDC_TABLE_INCLUDE_LIST:-public.search_outbox}
CDC_SERVER_NAME: ${CDC_SERVER_NAME:-pg}
CDC_SLOT_NAME: ${CDC_SLOT_NAME:-unidata_search_outbox_slot}
CDC_PUBLICATION_NAME: ${CDC_PUBLICATION_NAME:-unidata_search_outbox_pub}
CDC_CONNECTOR_NAME: ${CDC_CONNECTOR_NAME:-pg-search-outbox-connector}
volumes:
- ./docker/register-connector.sh:/opt/unidata/register-connector.sh:ro
entrypoint: ["/bin/sh", "/opt/unidata/register-connector.sh"]
depends_on:
connect:
condition: service_started
postgres:
condition: service_healthy
postgres-cdc-init:
condition: service_completed_successfully
meilisearch:
image: getmeili/meilisearch:v1.8
restart: unless-stopped
ports:
- "${MEILI_PORT:-7700}:7700"
env_file:
- path: ./.env.docker
required: false
volumes:
- meili_data:/meili_data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:7700/health"]
interval: 10s
timeout: 5s
retries: 10
start_period: 10s
meilisearch-sync:
build:
context: ./meilisearch-sync-service
dockerfile: Dockerfile
args:
- HTTP_PROXY
- HTTPS_PROXY
- ALL_PROXY
- NO_PROXY
- http_proxy
- https_proxy
- all_proxy
- no_proxy
restart: unless-stopped
env_file:
- path: ./.env.docker
required: false
environment:
KAFKA_BROKERS: kafka:9093
KAFKA_TOPIC: ${CDC_TOPIC:-pg.public.search_outbox}
KAFKA_GROUP_PREFIX: meilisearch-sync-service
REGION_ID: local
MEILI_HOST: http://meilisearch:7700
HTTP_ADDR: :8091
UNIDATA_URL: http://unidata:8080
REDIS_ADDR: redis:6379
ports:
- "${MEILI_SYNC_PORT:-8091}:8091"
entrypoint:
- /bin/sh
- -ec
- export MEILI_API_KEY="$${MEILI_API_KEY:-$$MEILI_MASTER_KEY}"; exec /app/meilisearch-sync-service
depends_on:
kafka-init:
condition: service_completed_successfully
meilisearch:
condition: service_healthy
redis:
condition: service_healthy
unidata:
condition: service_healthy
redis:
image: redis:7-alpine
restart: unless-stopped
ports:
- "${REDIS_PORT:-16379}:6379"
volumes:
- redis_data:/data
command: ["redis-server", "--appendonly", "yes"]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 12
# PostgreSQL init scripts run only for new volumes. Reconcile credentials and
# grants on each deployment so existing volumes follow the current .env.docker.
postgres-role-init:
image: postgres:16
restart: "no"
env_file:
- path: ./.env.docker
required: false
environment:
PGHOST: postgres
PGPORT: 5432
volumes:
- ./docker/postgres-init/01-create-unidata-roles.sh:/docker-entrypoint-initdb.d/01-create-unidata-roles.sh:ro
- ./docker/reconcile-postgres-roles.sh:/opt/unidata/reconcile-postgres-roles.sh:ro
entrypoint: ["/bin/bash", "/opt/unidata/reconcile-postgres-roles.sh"]
depends_on:
postgres:
condition: service_healthy
unidata-migrate:
build:
context: .
dockerfile: Dockerfile
target: runtime
image: ${UNIDATA_IMAGE:-unidata:local}
restart: "no"
env_file:
- path: ./.env.docker
required: false
environment:
<<: *unidata-environment
command: ["python", "-m", "migrations.migrate_open_platform"]
depends_on:
postgres:
condition: service_healthy
postgres-role-init:
condition: service_completed_successfully
# The outbox table is created by the UniData migrations. Create the filtered
# publication only after that work is complete, before Debezium is registered.
postgres-cdc-init:
image: postgres:16
restart: "no"
env_file:
- path: ./.env.docker
required: false
environment:
PGHOST: postgres
PGPORT: 5432
volumes:
- ./docker/postgres-init/01-create-unidata-roles.sh:/docker-entrypoint-initdb.d/01-create-unidata-roles.sh:ro
- ./docker/reconcile-postgres-roles.sh:/opt/unidata/reconcile-postgres-roles.sh:ro
entrypoint: ["/bin/bash", "/opt/unidata/reconcile-postgres-roles.sh"]
depends_on:
postgres-role-init:
condition: service_completed_successfully
unidata-migrate:
condition: service_completed_successfully
unidata:
build:
context: .
dockerfile: Dockerfile
target: runtime
image: ${UNIDATA_IMAGE:-unidata:local}
restart: unless-stopped
init: true
env_file:
- path: ./.env.docker
required: false
environment:
<<: *unidata-environment
OPEN_PLATFORM_COOKIE_SECURE: ${OPEN_PLATFORM_COOKIE_SECURE:-false}
ports:
- "${UNIDATA_PORT:-8080}:8080"
depends_on:
postgres:
condition: service_healthy
postgres-role-init:
condition: service_completed_successfully
kafka-init:
condition: service_completed_successfully
unidata-migrate:
condition: service_completed_successfully
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/ready', timeout=3)"]
interval: 10s
timeout: 5s
retries: 12
start_period: 20s
develop:
watch:
- action: sync+restart
path: ./UniData/app
target: /opt/unidata/UniData/app
ignore:
- "**/__pycache__"
- "**/*.pyc"
- action: sync+restart
path: ./UniData/scripts
target: /opt/unidata/UniData/scripts
ignore:
- "**/__pycache__"
- action: sync+restart
path: ./UniData/migrations
target: /opt/unidata/UniData/migrations
ignore:
- "**/__pycache__"
- action: rebuild
path: ./UniData/pyproject.toml
- action: rebuild
path: ./UniData/uv.lock
- action: rebuild
path: ./python-sdk
ignore:
- .venv
- "**/__pycache__"
- action: rebuild
path: ./Dockerfile
volumes:
pgdata:
meili_data:
redis_data: