Repository navigation
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
139 lines (137 loc) · 8.61 KB
/
Copy pathdocker-compose.yml
File metadata and controls
139 lines (137 loc) · 8.61 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
services:
# Minimal backend-only stack. Sandbox containers are created dynamically
# by the UnoSim backend via the Docker socket and are not persistent services.
unosim-backend:
build:
context: .
dockerfile: Dockerfile
image: unosim-server:latest
container_name: unosim-server
restart: unless-stopped
# Longer than the backend's 10 s internal shutdown deadline, so Docker
# never SIGKILLs the backend while it removes its sandbox containers.
stop_grace_period: 15s
# Bounded on-disk log: Docker's json-file default keeps every line forever.
logging:
driver: json-file
options:
max-size: "${UNOSIM_LOG_MAX_SIZE:-10m}"
max-file: "${UNOSIM_LOG_MAX_FILE:-5}"
group_add:
- "${DOCKER_GID:?Set DOCKER_GID to the numeric GID of /var/run/docker.sock}"
environment:
- PORT=3000
- UNOSIM_SERVER_MODE=docker
- NODE_ENV=production
# Docker deployments require a trusted gateway; user authentication is optional.
# Compose fails before startup when either required secret is absent.
- UNOSIM_GATEWAY_SECRET=${UNOSIM_GATEWAY_SECRET:?Set UNOSIM_GATEWAY_SECRET to at least 32 characters}
- UNOSIM_TRUSTED_PROXY=${UNOSIM_TRUSTED_PROXY:?Set UNOSIM_TRUSTED_PROXY to an IP or CIDR for Express proxy trust}
- UNOSIM_ALLOWED_WS_ORIGINS=${UNOSIM_ALLOWED_WS_ORIGINS:?Set UNOSIM_ALLOWED_WS_ORIGINS to the comma-separated browser origins}
# Public GitHub source; set SOURCE and REF both empty for built-ins only.
- UNOSIM_EXAMPLES_SOURCE=${UNOSIM_EXAMPLES_SOURCE-ttbombadil/unosim-examples}
- UNOSIM_EXAMPLES_REF=${UNOSIM_EXAMPLES_REF:-}
- UNOSIM_EXAMPLES_ALLOWED_HOSTS=${UNOSIM_EXAMPLES_ALLOWED_HOSTS:-api.github.com,raw.githubusercontent.com}
- UNOSIM_EXAMPLES_VALIDATE_RATE_LIMIT_MAX_REQUESTS=${UNOSIM_EXAMPLES_VALIDATE_RATE_LIMIT_MAX_REQUESTS:-5}
- UNOSIM_EXAMPLES_OVERRIDE_RATE_LIMIT_MAX_REQUESTS=${UNOSIM_EXAMPLES_OVERRIDE_RATE_LIMIT_MAX_REQUESTS:-60}
- UNOSIM_EXAMPLES_GLOBAL_LOAD_STARTS_PER_MINUTE=${UNOSIM_EXAMPLES_GLOBAL_LOAD_STARTS_PER_MINUTE:-20}
- UNOSIM_EXAMPLES_MAX_CONCURRENT_LOADS=${UNOSIM_EXAMPLES_MAX_CONCURRENT_LOADS:-4}
- UNOSIM_EXAMPLES_MAX_LOAD_QUEUE=${UNOSIM_EXAMPLES_MAX_LOAD_QUEUE:-32}
- UNOSIM_EXAMPLES_MAX_FILE_FETCH_CONCURRENCY=${UNOSIM_EXAMPLES_MAX_FILE_FETCH_CONCURRENCY:-8}
- UNOSIM_EXAMPLES_MAX_OUTBOUND_FETCHES=${UNOSIM_EXAMPLES_MAX_OUTBOUND_FETCHES:-16}
- UNOSIM_EXAMPLES_MAX_SOURCES=${UNOSIM_EXAMPLES_MAX_SOURCES:-32}
- UNOSIM_EXAMPLES_SNAPSHOT_CACHE_MAX_ENTRIES=${UNOSIM_EXAMPLES_SNAPSHOT_CACHE_MAX_ENTRIES:-64}
- UNOSIM_EXAMPLES_SNAPSHOT_CACHE_MAX_BYTES=${UNOSIM_EXAMPLES_SNAPSHOT_CACHE_MAX_BYTES:-67108864}
- UNOSIM_EXAMPLES_REFRESH_RETRY_MS=${UNOSIM_EXAMPLES_REFRESH_RETRY_MS:-30000}
# Optional, read-only GitHub token for api.github.com (60 -> 5000 ref lookups per hour).
- UNOSIM_GITHUB_TOKEN=${UNOSIM_GITHUB_TOKEN:-}
- ARDUINO_CACHE_DIR=${PWD}/server/arduino-cache
- UNOSIM_SHARED_TEMP_DIR=${PWD}/temp
- DOCKER_HOST=unix:///var/run/docker.sock
- DOCKER_SANDBOX_IMAGE=unosim-sandbox:latest
# Runtime backends and boards (docs/INSTALL_SERVER.md). Empty keeps the application
# default: host mock only, Uno. The pilot of the browser emulation sets
# UNOSIM_RUNTIME_BACKENDS=browser,host-mock and UNOSIM_DEFAULT_RUNTIME=browser in .env.
- UNOSIM_RUNTIME_BACKENDS=${UNOSIM_RUNTIME_BACKENDS:-}
- UNOSIM_DEFAULT_RUNTIME=${UNOSIM_DEFAULT_RUNTIME:-}
- UNOSIM_BOARDS=${UNOSIM_BOARDS:-}
- UNOSIM_DEFAULT_BOARD=${UNOSIM_DEFAULT_BOARD:-}
# Every compile runs in its own container of this image (npm run build:compile-sandbox):
# no network, read-only root and sketch, bounded tmpfs. See docs/SECURITY.md.
- COMPILE_SANDBOX_IMAGE=unosim-compile-sandbox:latest
- COMPILE_SANDBOX_MEMORY_MB=${COMPILE_SANDBOX_MEMORY_MB:-512}
- COMPILE_SANDBOX_CPU_LIMIT=${COMPILE_SANDBOX_CPU_LIMIT:-1}
- COMPILE_SANDBOX_PIDS_LIMIT=${COMPILE_SANDBOX_PIDS_LIMIT:-128}
# Owns the sandbox containers across restarts and redeploys: a new backend
# container removes the sandboxes its predecessor left running. Must be
# unique among backends running at the same time on this Docker host.
- UNOSIM_INSTANCE_ID=${UNOSIM_INSTANCE_ID:-unosim-server}
# Logical simulation capacity grows on-demand; idle logical runners shrink after IDLE_TIMEOUT_MS.
# Admission caps running plus waiting simulations. Without a host-specific value it
# stays at the application default 25; the Ubuntu/VBox installer writes the value
# measured on its reference VM. See docs/CAPACITY_MODEL.md before raising.
- SIMULATION_ADMISSION_MAX=${SIMULATION_ADMISSION_MAX:-25}
- SIMULATION_MAX_CONCURRENT=${SIMULATION_MAX_CONCURRENT:-200}
# Empty keeps the application default (60000 ms, server/config.ts); a value
# from .env or a reviewed capacity.env proposal is passed through unchanged.
- SIMULATION_QUEUE_TIMEOUT_MS=${SIMULATION_QUEUE_TIMEOUT_MS:-}
# Total paused time of one run; a paused run still holds its capacity.
- SIMULATION_MAX_PAUSED_SECONDS=${SIMULATION_MAX_PAUSED_SECONDS:-600}
- SANDBOX_POOL_IDLE_TIMEOUT_MS=300000
# Per-sandbox Docker resource limits
# ┌─ Scenario breakdown ────────────────────────────────────────────────────┐
# │ Dev (default, no docker-compose): uses config.ts defaults │
# │ SANDBOX_MEMORY_MB = 256 MB (safe floor: g++/cc1plus needs 150-300 MB │
# │ when compiling inside the container) │
# │ CI (GitHub Actions ubuntu-latest): same defaults, no override needed │
# │ Linux cgroup v2 hard-kills cc1plus at 64 MB → must be ≥ 256 │
# │ Production (this docker-compose): explicit override – can be tuned │
# │ 256 MB covers compile phase; AVR runtime alone only needs ~30 MB │
# └─────────────────────────────────────────────────────────────────────────┘
- SANDBOX_MEMORY_MB=256
- SANDBOX_CPU_LIMIT=0.25
# Compile capacity: workers, global compile limit, Docker-sandbox limit.
- WORKER_COUNT=${WORKER_COUNT:-8}
- COMPILE_MAX_CONCURRENT=${COMPILE_MAX_CONCURRENT:-8}
- SANDBOX_START_MAX_CONCURRENT=${SANDBOX_START_MAX_CONCURRENT:-8}
- SANDBOX_START_SLOT_TIMEOUT_MS=${SANDBOX_START_SLOT_TIMEOUT_MS:-30000}
- DOCKER_CONTROL_TIMEOUT_MS=${DOCKER_CONTROL_TIMEOUT_MS:-2000}
ports:
# Secure default: a host-local gateway can reach UnoSim, LAN clients cannot
# bypass it. Override only with a private gateway-facing bind address.
- "${UNOSIM_BIND_ADDRESS:-127.0.0.1}:3000:3000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# The backend runs as the image's unprivileged `node` user (UID/GID 1000).
# Run `sudo ./scripts/prepare-runtime-dirs.sh` once before the first start:
# otherwise Docker creates missing mount sources as root:root and the
# backend cannot write its compile cache, temp files or storage (EACCES).
- ${PWD}/server/arduino-cache:${PWD}/server/arduino-cache
- ${PWD}/temp:${PWD}/temp
- ./storage:/app/storage
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:3000/api/readiness"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
networks:
default:
# A host-local gateway (e.g. Nginx on the host) reaches the backend through
# the published port; Docker forwards that connection from this network's
# gateway, so the backend sees the gateway address as its peer, never
# 127.0.0.1. A fixed gateway makes UNOSIM_TRUSTED_PROXY deterministic.
# The Ubuntu/VBox installer writes these values together with
# UNOSIM_TRUSTED_PROXY=<gateway>/32; change all three together.
ipam:
config:
- subnet: ${UNOSIM_DOCKER_SUBNET:-172.31.253.0/24}
gateway: ${UNOSIM_DOCKER_GATEWAY:-172.31.253.1}
# NOTE: The mcp/sonarqube MCP server is intentionally NOT part of this stack.
# It is a stdio-based dev tool managed by Docker Desktop MCP Toolkit and
# launched on-demand per VS Code session. Running it as a persistent service
# makes no sense and causes constant restart loops.
#
# SonarQube itself (sonarqube + sonar-db) lives in its own stack at
# ~/Documents/sonarqube/docker-compose.yml and is reached from the host
# via http://localhost:9000.