-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompose.yml
More file actions
278 lines (268 loc) · 11.4 KB
/
Copy pathcompose.yml
File metadata and controls
278 lines (268 loc) · 11.4 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
# ASAREE's own compose file -- self-contained: `git clone` this repo and
# `docker compose up -d --build` is the whole setup. Motoro is a pinned git
# dependency (pyproject.toml, [tool.uv.sources]) that uv fetches during the
# build, so no checkout of that repo is needed here.
#
# This used to `include: ${MOTORO_DIR:-../Motoro}/compose.yml`, which made a
# sibling checkout a hard prerequisite purely to obtain three services. They are
# defined below instead, and the migrate one now runs out of ASAREE's own image
# -- the installed `motoro` wheel ships its Alembic chain and the CLI that
# applies it, so core's schema comes from the exact pinned version the app
# imports rather than from whatever commit a local checkout happened to be on.
# Service names, container names, ports and the volume name are unchanged from
# Motoro's file, so an existing dev environment keeps its data.
#
# Don't also run `docker compose up` inside a Motoro checkout while this is up
# -- same container names and ports, so the two would collide.
#
# Motoro's repo is public, so `--build` needs no credential. The gh_token build
# secret below is only for building against a private fork; an unset GH_TOKEN is
# fine (an empty password still fetches a public repo -- see Dockerfile). To use
# one:
#
# GH_TOKEN=$(gh auth token) docker compose up -d --build
services:
# Motoro's backing store, and ASAREE's: one server, two databases in one
# volume -- `motoro` (core's schema, created by POSTGRES_DB below) and
# `asaree` (this repo's, created on demand by asaree.migrations'
# _ensure_database_exists).
#
# pgvector rather than plain postgres:16, inherited from Motoro's own file:
# nothing uses the extension yet, semantic memory will, and swapping the image
# later would mean recreating the volume.
motoro-postgres:
image: pgvector/pgvector:pg16
container_name: motoro-postgres
environment:
POSTGRES_USER: agentic
POSTGRES_PASSWORD: agentic
POSTGRES_DB: motoro
ports:
# Host-side only -- the services below reach it at motoro-postgres:5432 on
# the compose network. 5453 is offset from the default so it can coexist
# with a local Postgres; override in .env if it's still taken.
- "${POSTGRES_PORT:-5453}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U agentic -d motoro"]
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
motoro-redis:
# Motoro's working memory, plus ASAREE's own use of it (rate limiting, the
# JWT deny list, and the arq queue the worker below reads).
image: redis:7-alpine
container_name: motoro-redis
ports:
- "${REDIS_PORT:-6381}:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
restart: unless-stopped
# Core's schema, applied from ASAREE's own image (see the header) -- the same
# build as asaree-app, so this costs one extra container, not an extra image.
# `deploy` = upgrade then sync-catalog (project the pattern registry into
# architectural_patterns); both idempotent, and the catalog step is why this
# needs the full runtime rather than Alembic alone.
#
# Runs to completion and exits 0 -- `Exited (0)` in `docker compose ps` is
# success, hence restart: "no". `--url` is passed explicitly because core's CLI
# otherwise reads a bare DATABASE_URL, which nothing here sets.
motoro-migrate:
build:
context: .
secrets:
- gh_token
additional_contexts:
gitdir: ./.git
container_name: motoro-migrate
depends_on:
# Not service_started: Postgres accepts connections briefly while still
# running initdb, which races the creation of the database being migrated.
motoro-postgres:
condition: service_healthy
entrypoint: ["python", "-m", "motoro.migrations"]
command:
- deploy
- --url
- postgresql+asyncpg://agentic:agentic@motoro-postgres:5432/motoro
restart: "no"
asaree-migrate:
build:
context: .
secrets:
- gh_token
# `asaree`'s version is derived from this repo's git tags at build time
# (hatch-vcs), so the final `uv sync` can't build the project without the
# git metadata. It arrives as its own named context rather than through
# the main one so .dockerignore can go on excluding .git/ — see Dockerfile.
additional_contexts:
gitdir: ./.git
container_name: asaree-migrate
depends_on:
# After core's, not merely after Postgres: no product table has an FK into
# a core one (they reference core rows by opaque UUID), but the deploy is
# sequenced core-first -- see asaree.migrations' module docstring.
motoro-migrate:
condition: service_completed_successfully
env_file: .env
environment:
# Internal container network, not the host-mapped ports in .env
# (which are wrong from inside a container on this network).
ASAREE_DATABASE_URL: postgresql+asyncpg://agentic:agentic@motoro-postgres:5432/motoro
ASAREE_PRODUCT_DATABASE_URL: postgresql+asyncpg://agentic:agentic@motoro-postgres:5432/asaree
entrypoint: ["python", "-m", "asaree.migrations"]
command: ["upgrade"]
restart: "no"
asaree-app:
build:
context: .
secrets:
- gh_token
# See asaree-migrate above: hatch-vcs needs the git metadata to derive a
# version, and .git/ stays out of the main context.
additional_contexts:
gitdir: ./.git
container_name: asaree-app
depends_on:
asaree-migrate:
condition: service_completed_successfully
motoro-redis:
condition: service_healthy
env_file: .env
environment:
ASAREE_DATABASE_URL: postgresql+asyncpg://agentic:agentic@motoro-postgres:5432/motoro
ASAREE_PRODUCT_DATABASE_URL: postgresql+asyncpg://agentic:agentic@motoro-postgres:5432/asaree
ASAREE_REDIS_URL: redis://motoro-redis:6379/0
# asaree-sklearn-eda's get_data_dictionary calls back into this API for a
# registered dataset's dictionary_json. Its own default is
# localhost:8000, which is nothing from inside the worker container that
# spawns it — hence the service name. Allowlisted for MCP subprocesses
# via ASAREE_MCP_ALLOWED_ENV_VARS in .env.
ASAREE_API_URL: http://asaree-app:8000
# The user-bundle browse/registration root (Knowledge connector). The
# .env default is a host path meaning nothing in here — inside the
# container the only host filesystem visible is the ./data mount below,
# so that mount IS the reachable universe. A user's bundle has to be
# placed under ./data on the host to be registrable at all.
ASAREE_OKF_BUNDLE_ROOT: /app/data
ports:
- "8000:8000"
volumes:
# Persists dataset workspaces and the OKF bundle across restarts —
# otherwise both live inside the container's own ephemeral filesystem.
# The only mount this service needs: every bundled MCP server is an
# installed dependency in the image (see pyproject.toml's mcp-servers/
# path sources), so their stored `command` is `uv run --directory /app
# python -m ...` with no host path to replay.
- ./data:/app/data
# Uvicorn starts accepting connections only after the FastAPI lifespan
# finishes reconnecting MCP servers, so this is a real readiness probe --
# not merely "the process exists". The frontend waits for it below.
healthcheck:
test:
- CMD
- python
- -c
- "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()"
interval: 2s
timeout: 3s
retries: 20
start_period: 5s
restart: unless-stopped
# Same built image as asaree-app, running the arq worker instead of
# uvicorn -- see Dockerfile's CMD, overridden here via `command:`. Deployed
# alongside the still-inline POST /runs for now (asaree.api.runs hasn't
# been switched to enqueue yet); this service exists so the worker path can
# be smoke-tested against real Redis/Postgres before that switch lands.
asaree-worker:
build:
context: .
secrets:
- gh_token
# See asaree-migrate above: hatch-vcs needs the git metadata to derive a
# version, and .git/ stays out of the main context.
additional_contexts:
gitdir: ./.git
container_name: asaree-worker
depends_on:
asaree-migrate:
condition: service_completed_successfully
motoro-redis:
condition: service_healthy
env_file: .env
environment:
ASAREE_DATABASE_URL: postgresql+asyncpg://agentic:agentic@motoro-postgres:5432/motoro
ASAREE_PRODUCT_DATABASE_URL: postgresql+asyncpg://agentic:agentic@motoro-postgres:5432/asaree
ASAREE_REDIS_URL: redis://motoro-redis:6379/0
ASAREE_API_URL: http://asaree-app:8000
# Must match asaree-app's: this is the process that actually spawns a
# bundle's MCP server, so a path the API accepted has to resolve here too.
ASAREE_OKF_BUNDLE_ROOT: /app/data
command: ["arq", "asaree.worker.settings.WorkerSettings"]
volumes:
# Same mount as asaree-app, and for the same reason: the dataset
# workspaces and OKF bundle need to survive a restart. The worker is the
# process that actually spawns the MCP subprocesses for a run, so it
# reads and writes the same workspace tree the API does.
- ./data:/app/data
restart: unless-stopped
# Integration-test runner on the Compose network. The tests intentionally
# use real Postgres (JSONB and core's vector schema rule out SQLite), so run
# them beside the database instead of relying on a host-side localhost port.
# The profile keeps this one-shot service out of ordinary `docker compose
# up`; targeting it explicitly activates it:
#
# docker compose run --rm --build asaree-tests
asaree-tests:
profiles: ["test"]
build:
context: .
target: test
secrets:
- gh_token
additional_contexts:
gitdir: ./.git
depends_on:
asaree-migrate:
condition: service_completed_successfully
environment:
DATABASE_URL: postgresql+asyncpg://agentic:agentic@motoro-postgres:5432/motoro
ASAREE_DATABASE_URL: postgresql+asyncpg://agentic:agentic@motoro-postgres:5432/motoro
ASAREE_PRODUCT_DATABASE_URL: postgresql+asyncpg://agentic:agentic@motoro-postgres:5432/asaree
ASAREE_REDIS_URL: redis://motoro-redis:6379/0
restart: "no"
asaree-frontend:
build:
context: ./frontend
container_name: asaree-frontend
depends_on:
asaree-app:
condition: service_healthy
environment:
# Service name on the compose network, not 127.0.0.1 (see
# frontend/vite.config.ts) — 127.0.0.1 inside this container is
# itself, not asaree-app.
VITE_API_PROXY_TARGET: http://asaree-app:8000
ports:
- "5173:5173"
volumes:
# Bind-mount for hot reload; node_modules stays the image's own
# (installed for Linux/the container's arch) rather than whatever's
# in the host checkout.
- ./frontend:/app
- /app/node_modules
restart: unless-stopped
volumes:
postgres_data:
# Explicit name, matching what Motoro's own compose.yml declared while this
# file included it -- renaming it would orphan every existing dev
# environment's data behind a new, empty volume.
name: motoro_postgres_data
secrets:
gh_token:
environment: GH_TOKEN