-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
235 lines (224 loc) · 9.11 KB
/
docker-compose.yml
File metadata and controls
235 lines (224 loc) · 9.11 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
# Shared backend config (DRY)
x-backend-common: &backend-common
image: ${DOCKER_REGISTRY:-docker.io/}xjh1994/opencli-admin-api:${IMAGE_TAG:-0.3.6}
env_file:
- path: .env
required: false
volumes:
- db_data:/data
- ./backend:/app/backend
restart: unless-stopped
services:
# ── Infrastructure (only needed for TASK_EXECUTOR=celery) ─────────────────
redis:
profiles: ["celery"]
image: ${DOCKER_REGISTRY:-}redis:7-alpine
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
postgres:
image: ${DOCKER_REGISTRY:-}postgres:16-alpine
profiles: ["postgres"]
ports:
- "5432:5432"
environment:
POSTGRES_DB: ${POSTGRES_DB:-opencli_admin}
POSTGRES_USER: ${POSTGRES_USER:-opencli}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-opencli_secret}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-opencli}"]
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
# ── Backend API ───────────────────────────────────────────────────────────
api:
<<: *backend-common
# Run as root so the API can manage Docker containers (agent pool) via
# the mounted socket. Acceptable for a self-hosted admin panel.
user: root
environment:
DATABASE_URL: ${DATABASE_URL:-sqlite+aiosqlite:////data/opencli_admin.db}
CELERY_BROKER_URL: redis://redis:6379/0
CELERY_RESULT_BACKEND: redis://redis:6379/1
REDIS_URL: redis://redis:6379/0
DEBUG: ${DEBUG:-false}
SECRET_KEY: ${SECRET_KEY:-change-me-in-production}
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
# Built-in sidecar agent URL (Chrome + agent_server in one container).
# For COLLECTION_MODE=local this is pre-loaded into the browser pool.
OPENCLI_CDP_ENDPOINT: ${OPENCLI_CDP_ENDPOINT:-http://agent-1:19823}
# Multi-instance pool: overrides OPENCLI_CDP_ENDPOINT when set
AGENT_POOL_ENDPOINTS: ${AGENT_POOL_ENDPOINTS:-}
# Collection mode: "local" (default, built-in agent-1) or "agent" (distributed edge nodes)
COLLECTION_MODE: ${COLLECTION_MODE:-local}
# Public-facing URL for install scripts and agent registration links.
# Set to the URL remote agents will use to reach this center (e.g. http://192.168.1.1:8031).
PUBLIC_URL: ${PUBLIC_URL:-}
# Passed to the agent pool manager so it can name containers/networks correctly
COMPOSE_PROJECT_NAME: ${COMPOSE_PROJECT_NAME:-opencli-admin}
volumes:
- db_data:/data
- ./backend:/app/backend
# Docker socket: lets the API start/stop agent pool containers
- /var/run/docker.sock:/var/run/docker.sock
# .env mount: lets the API persist AGENT_POOL_ENDPOINTS after pool changes
- ./.env:/app/.env:rw
ports:
- "${API_PORT:-8031}:8000"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 20s
# ── Celery Worker (only needed for TASK_EXECUTOR=celery) ─────────────────
worker:
profiles: ["celery"]
<<: *backend-common
command: celery -A backend.worker.celery_app worker --loglevel=info --concurrency=4
environment:
DATABASE_URL: ${DATABASE_URL:-sqlite+aiosqlite:////data/opencli_admin.db}
CELERY_BROKER_URL: redis://redis:6379/0
CELERY_RESULT_BACKEND: redis://redis:6379/1
REDIS_URL: redis://redis:6379/0
RUN_MIGRATIONS: "false"
SECRET_KEY: ${SECRET_KEY:-change-me-in-production}
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
OPENCLI_CDP_ENDPOINT: ${OPENCLI_CDP_ENDPOINT:-http://agent-1:19823}
AGENT_POOL_ENDPOINTS: ${AGENT_POOL_ENDPOINTS:-}
depends_on:
redis:
condition: service_healthy
api:
condition: service_healthy
# ── Celery Beat (only needed for TASK_EXECUTOR=celery) ───────────────────
beat:
profiles: ["celery"]
<<: *backend-common
command: celery -A backend.worker.celery_app beat --loglevel=info
environment:
DATABASE_URL: ${DATABASE_URL:-sqlite+aiosqlite:////data/opencli_admin.db}
CELERY_BROKER_URL: redis://redis:6379/0
CELERY_RESULT_BACKEND: redis://redis:6379/1
REDIS_URL: redis://redis:6379/0
RUN_MIGRATIONS: "false"
SECRET_KEY: ${SECRET_KEY:-change-me-in-production}
depends_on:
redis:
condition: service_healthy
api:
condition: service_healthy
# ── Built-in agent sidecar ────────────────────────────────────────────────────
# Default single instance — always started (local collection mode uses this).
# Chrome is NOT embedded in the image (~200 MB). The agent connects to Chrome
# running on the Docker host via host.docker.internal.
#
# Before starting, ensure Chrome is running on the host with CDP enabled:
# • macOS/Linux: open -a "Google Chrome" --args --remote-debugging-port=9222
# • Or start the Bridge daemon: node $(npm root -g)/@jackwener/opencli/dist/daemon.js
agent-1:
container_name: agent-1
image: ${DOCKER_REGISTRY:-docker.io/}xjh1994/opencli-admin-agent:${IMAGE_TAG:-0.3.6}${CHROME_SUFFIX:-}
environment:
CENTRAL_API_URL: http://api:8000
# Use container name so the API can reach this agent by DNS within the Docker network
AGENT_ADVERTISE_URL: http://agent-1:19823
AGENT_PORT: 19823
# Chrome connection mode: bridge | cdp (override in .env)
AGENT_MODE: ${AGENT_MODE:-bridge}
AGENT_DEPLOY_TYPE: docker
AGENT_LABEL: agent-1
# Host Chrome endpoints — agent connects to Chrome running on the Docker host
# bridge mode: daemon on host
OPENCLI_DAEMON_HOST: host.docker.internal
OPENCLI_DAEMON_PORT: ${OPENCLI_DAEMON_PORT:-19825}
# cdp mode: Chrome DevTools Protocol on host
OPENCLI_CDP_ENDPOINT: ${OPENCLI_CDP_ENDPOINT:-http://host.docker.internal:9222}
OPENCLI_TIMEOUT: ${OPENCLI_TIMEOUT:-120}
HTTP_PROXY: ${HTTP_PROXY:-}
HTTPS_PROXY: ${HTTPS_PROXY:-}
extra_hosts:
# Make host.docker.internal resolve to the host on Linux (already works on macOS/Windows)
- "host.docker.internal:host-gateway"
volumes:
- agent_profile_1:/home/agent/.config/chromium
ports:
- "${AGENT1_PORT:-19823}:19823" # agent_server HTTP API
depends_on:
api:
condition: service_healthy
restart: unless-stopped
# Additional agent instances are managed dynamically via the API
# (节点管理 → 新增实例)
# ── Remote agent (all-in-one: Chrome + agent server) ─────────────────────
# For deploying on a REMOTE node that should register with the center.
# Usage:
# On the remote machine:
# docker run -d --restart=unless-stopped \
# -e CENTRAL_API_URL=http://<center-ip>:8031 \
# -e AGENT_REGISTER=ws \
# -p 19823:19823 \
# xjh1994/opencli-admin-agent:0.1.0
#
# Or start the bundled agent profile (local network):
# docker compose --profile agent up agent
agent:
profiles: ["agent"]
image: ${DOCKER_REGISTRY:-docker.io/}xjh1994/opencli-admin-agent:${IMAGE_TAG:-0.3.6}${CHROME_SUFFIX:-}
environment:
CENTRAL_API_URL: ${CENTRAL_API_URL:-}
AGENT_ADVERTISE_URL: ${AGENT_ADVERTISE_URL:-}
AGENT_PORT: ${AGENT_PORT:-19823}
AGENT_MODE: ${AGENT_MODE:-cdp}
AGENT_LABEL: ${AGENT_LABEL:-}
AGENT_REGISTER: ${AGENT_REGISTER:-http}
OPENCLI_TIMEOUT: ${OPENCLI_TIMEOUT:-120}
HTTP_PROXY: ${HTTP_PROXY:-}
HTTPS_PROXY: ${HTTPS_PROXY:-}
volumes:
- agent_profile:/home/agent/.config/chromium
ports:
- "${AGENT_PORT:-19823}:19823"
restart: unless-stopped
# ── Frontend (nginx + built React) — production ───────────────────────────
frontend:
image: ${DOCKER_REGISTRY:-docker.io/}xjh1994/opencli-admin-frontend:${IMAGE_TAG:-0.3.6}
ports:
- "${FRONTEND_PORT:-8030}:80"
depends_on:
api:
condition: service_healthy
restart: unless-stopped
# ── Frontend dev server (Vite HMR) — run with: docker compose --profile dev up frontend-dev
frontend-dev:
profiles: ["dev"]
image: ${DOCKER_REGISTRY:-}node:22-alpine
working_dir: /app
command: sh -c "npm ci --legacy-peer-deps && npm run dev -- --host"
volumes:
- ./frontend:/app
- /app/node_modules
ports:
- "${FRONTEND_PORT:-8030}:5173"
environment:
VITE_API_PROXY_TARGET: "http://api:8000"
depends_on:
api:
condition: service_healthy
restart: unless-stopped
volumes:
redis_data:
postgres_data:
db_data:
agent_profile_1:
agent_profile: