Repository navigation
Expand file tree
/
Copy pathdocker-compose.local-dev.yml
More file actions
208 lines (202 loc) · 8.16 KB
/
Copy pathdocker-compose.local-dev.yml
File metadata and controls
208 lines (202 loc) · 8.16 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
# Local Development Stack - No authentication required
# Usage: docker compose -f docker-compose.local-dev.yml up
#
# This uses the combined service (API + Workers) for local development simplicity.
# For scalable production deployment, see docker-compose.scalable.yml
#
# The sandbox runs inside a libkrun microVM with its own guest kernel.
# Requires /dev/kvm (WSL2 with nested virt, or bare metal Linux).
services:
# MicroVM Sandbox API (libkrun + NsJail code execution)
sandbox:
build:
context: .
dockerfile: api/Dockerfile
target: sandbox-runner-${KVM_ENABLED:-true}
container_name: sandbox
restart: unless-stopped
privileged: false
devices:
- ${KVM_DEVICE_PATH:-/dev/kvm}:/dev/kvm
ports:
- 2000:2000
volumes:
- ${SANDBOX_PACKAGES_PATH:-./data/pkgs}:/host-packages:ro
environment:
- KVM_ENABLED=${KVM_ENABLED:-true}
- LAUNCHER_PACKAGES_HOST=/disabled-host-packages
- LAUNCHER_VCPUS=2
- LAUNCHER_RAM_MIB=2048
- LAUNCHER_LOG_LEVEL=3
- SANDBOX_LOG_LEVEL=DEBUG
- SANDBOX_PACKAGES_DIRECTORY=/pkgs
- SANDBOX_MAX_PROCESS_COUNT=100
- SANDBOX_PER_JOB_UIDS=true
- SANDBOX_JOB_UID_BASE=200000
- SANDBOX_JOB_GID_BASE=200000
- SANDBOX_WORKSPACE_REAPER_MAX_AGE_SECONDS=3600
- SANDBOX_RUN_CPU_TIME=60000
- SANDBOX_RUN_TIMEOUT=300000
- SANDBOX_OUTPUT_MAX_SIZE=65536
- SANDBOX_DISABLE_NETWORKING=true
- FILE_SERVER_URL=http://file_server:3000
# Left unset on purpose: this file's own header says "no authentication
# required", but a non-empty token here switches internal-service auth
# ON — and the sandbox's actual runtime (Bun) doesn't attach
# X-CodeAPI-Internal-Token to its file_server requests (confirmed by
# capturing the raw traffic), so every request 401s. Empty token =
# requireInternalServiceAuth skips the check entirely, matching what
# this file already claims to be. Set a real CODEAPI_INTERNAL_SERVICE_TOKEN
# again once/if that header-propagation gap is fixed upstream.
- CODEAPI_INTERNAL_SERVICE_TOKEN=${CODEAPI_INTERNAL_SERVICE_TOKEN:-}
- SANDBOX_ALLOWED_LOCAL_NETWORK_PORT=3033
- SANDBOX_FORWARD_TARGET=tool_call_server:3033
# Syntato addition — see SYNTATO_CHANGES.md. lab-agent-preview-server
# runs directly on the host (systemd, port 8012), not in this compose
# network — host.docker.internal is how a container reaches it, same
# address librechat.yaml's own preview-server MCP entry already uses.
# Empty/unset makes job.ts's forward-to-preview-server step a no-op.
- PREVIEW_SERVER_URL=http://host.docker.internal:8012
healthcheck:
test: ["CMD", "/usr/local/bin/sandbox-runner-healthcheck.sh"]
interval: 10s
timeout: 5s
retries: 6
depends_on:
- tool_call_server
# Syntato addition — see SYNTATO_CHANGES.md. Required for the
# PREVIEW_SERVER_URL host.docker.internal address above to resolve at
# all: unlike Docker Desktop, plain Linux Docker does not add this
# mapping automatically. Matches the equivalent entry already needed
# (and present) in lab-agent/docker-compose.yml for the same reason.
extra_hosts:
- "host.docker.internal:host-gateway"
# File Server (MinIO integration) - Stateless, scales independently
file_server:
build:
context: .
dockerfile: service/Dockerfile
target: production
container_name: file_server
restart: unless-stopped
ports:
# host 3000 is already owned by lab-agent's admin-panel; container-internal
# port stays 3000 for the other code-interpreter services to reach it.
- 3010:3000
environment:
- MINIO_BUCKET=test-bucket
- MINIO_ENDPOINT=minio
- MINIO_PORT=9000
- MINIO_USE_SSL=false
- MINIO_ACCESS_KEY=minioadmin
- MINIO_SECRET_KEY=minioadmin
- FILE_SERVER_PORT=3000
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_PASSWORD=localdev
# Left unset on purpose: this file's own header says "no authentication
# required", but a non-empty token here switches internal-service auth
# ON — and the sandbox's actual runtime (Bun) doesn't attach
# X-CodeAPI-Internal-Token to its file_server requests (confirmed by
# capturing the raw traffic), so every request 401s. Empty token =
# requireInternalServiceAuth skips the check entirely, matching what
# this file already claims to be. Set a real CODEAPI_INTERNAL_SERVICE_TOKEN
# again once/if that header-propagation gap is fixed upstream.
- CODEAPI_INTERNAL_SERVICE_TOKEN=${CODEAPI_INTERNAL_SERVICE_TOKEN:-}
depends_on:
- minio
- redis
# Tool Call Server (programmatic tool calling) - Stateless, scales independently
tool_call_server:
build:
context: .
dockerfile: service/Dockerfile.tool-call-server
target: production
container_name: tool_call_server
restart: unless-stopped
ports:
- 3033:3033
environment:
- TOOL_CALL_SERVER_PORT=3033
- TOOL_CALL_REQUEST_TIMEOUT=300000
- TOOL_CALL_SESSION_EXPIRY=600
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_PASSWORD=localdev
# Left unset on purpose: this file's own header says "no authentication
# required", but a non-empty token here switches internal-service auth
# ON — and the sandbox's actual runtime (Bun) doesn't attach
# X-CodeAPI-Internal-Token to its file_server requests (confirmed by
# capturing the raw traffic), so every request 401s. Empty token =
# requireInternalServiceAuth skips the check entirely, matching what
# this file already claims to be. Set a real CODEAPI_INTERNAL_SERVICE_TOKEN
# again once/if that header-propagation gap is fixed upstream.
- CODEAPI_INTERNAL_SERVICE_TOKEN=${CODEAPI_INTERNAL_SERVICE_TOKEN:-}
depends_on:
- redis
# Local Service API (combined API + Workers, no auth required)
# For production, split into api + worker-sandbox pods
service:
build:
context: .
dockerfile: service/Dockerfile.local
target: production
container_name: service
restart: unless-stopped
ports:
- 3112:3112
environment:
- LOCAL_MODE=${LOCAL_MODE:-true}
- SANDBOX_ENDPOINT=http://sandbox:2000/api/v2
- FILE_SERVER_URL=http://file_server:3000
- TOOL_CALL_SERVER_URL=http://tool_call_server:3033
# Left unset on purpose: this file's own header says "no authentication
# required", but a non-empty token here switches internal-service auth
# ON — and the sandbox's actual runtime (Bun) doesn't attach
# X-CodeAPI-Internal-Token to its file_server requests (confirmed by
# capturing the raw traffic), so every request 401s. Empty token =
# requireInternalServiceAuth skips the check entirely, matching what
# this file already claims to be. Set a real CODEAPI_INTERNAL_SERVICE_TOKEN
# again once/if that header-propagation gap is fixed upstream.
- CODEAPI_INTERNAL_SERVICE_TOKEN=${CODEAPI_INTERNAL_SERVICE_TOKEN:-}
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_PASSWORD=localdev
- PYTHON_CONCURRENCY=1
- OTHER_CONCURRENCY=8
- JOB_WINDOW=1000
# Must match or exceed programmatic request timeout for tool calls to work
- JOB_TIMEOUT=300000
- PORT=3112
# Programmatic Tool Calling mode: `blocking` (legacy) or `replay` (Temporal-style).
- PTC_MODE=${PTC_MODE:-replay}
- PTC_DEBUG=${PTC_DEBUG:-false}
depends_on:
- redis
- sandbox
- file_server
- tool_call_server
# Redis - Shared job queue and state store
redis:
image: redis:7-alpine
container_name: redis
restart: unless-stopped
command: redis-server --requirepass localdev
ports:
- 6379:6379
# MinIO (S3-compatible storage) - Shared file storage
minio:
image: quay.io/minio/minio
container_name: minio
restart: unless-stopped
ports:
- 9000:9000
- 9001:9001
volumes:
- minio_data:/data
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=minioadmin
command: server /data --console-address ":9001"
volumes:
minio_data: