Repository navigation
Expand file tree
/
Copy pathdocker-compose.agent-loop.yml
More file actions
160 lines (153 loc) · 6.57 KB
/
Copy pathdocker-compose.agent-loop.yml
File metadata and controls
160 lines (153 loc) · 6.57 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
# Local agent-loop overlay for docker-compose.yml. Opt in from the checkout's
# .env with COMPOSE_FILE=docker-compose.yml:docker-compose.agent-loop.yml and
# COMPOSE_PROFILES=backend,agent-loop. See docs/engineering/local-agent-loop.md.
#
# The Rust checker service starts checker images with
# `docker run --mount type=bind,src=<material path>`. The Docker daemon resolves
# that source inside the Docker VM (or Linux host), so the material root is the
# named volume's own daemon path, mounted at that same path in API, worker, beat
# and checker. This assumes the default /var/lib/docker data root.
#
# The socket lives on a second named volume. Docker Desktop host-shared paths
# refuse chmod on Unix sockets, and AF_UNIX paths must stay within 107 bytes.
# An optional singleton model-proxy worker uses its own private named volume.
# Invocation relay sockets use a fourth volume mounted in the checker at the
# volume's daemon-visible path so Docker can bind-mount an individual socket
# into an otherwise networkless checker image.
x-agent-loop-backend: &agent-loop-backend
environment:
WORKSTREAM_ARTIFACT_SCRATCH_ROOT: /var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-material/_data
WORKSTREAM_EXTERNAL_CHECKER_MATERIAL_ROOT: /var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-material/_data
WORKSTREAM_EXTERNAL_CHECKER_SERVICE_SOCKET: /run/ws-checker/checker.sock
volumes:
- checker_material:/var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-material/_data
- checker_socket:/run/ws-checker:ro
depends_on:
checker-volumes-init:
condition: service_completed_successfully
services:
backend:
<<: *agent-loop-backend
worker:
<<: *agent-loop-backend
environment:
WORKSTREAM_ARTIFACT_SCRATCH_ROOT: /var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-material/_data
WORKSTREAM_EXTERNAL_CHECKER_MATERIAL_ROOT: /var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-material/_data
WORKSTREAM_EXTERNAL_CHECKER_SERVICE_SOCKET: /run/ws-checker/checker.sock
WORKSTREAM_CHECKER_MODEL_PROXY_SOCKET: /run/ws-model-proxy/model-proxy.sock
volumes:
- checker_material:/var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-material/_data
- checker_socket:/run/ws-checker:ro
- checker_model_proxy:/run/ws-model-proxy:ro
beat: *agent-loop-backend
model-proxy:
environment:
WORKSTREAM_CHECKER_MODEL_PROXY_SOCKET: /run/ws-model-proxy/model-proxy.sock
WORKSTREAM_ARTIFACT_SCRATCH_ROOT: /var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-material/_data
volumes:
- checker_model_proxy:/run/ws-model-proxy
- checker_material:/var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-material/_data
depends_on:
checker-volumes-init:
condition: service_completed_successfully
healthcheck:
test: [CMD, python, -c, "import socket; s=socket.socket(socket.AF_UNIX); s.settimeout(2); s.connect('/run/ws-model-proxy/model-proxy.sock'); s.close()"]
interval: 5s
timeout: 3s
retries: 12
# Named-volume roots start root-owned 0755. The scratch manager and checker
# service both require a private 0700 root owned by the runtime UID.
checker-volumes-init:
profiles: ["backend"]
image: ${COMPOSE_PROJECT_NAME}-backend:local
pull_policy: never
user: "0:0"
network_mode: none
environment:
MATERIAL_ROOT: /var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-material/_data
RUNTIME_OWNER: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
command:
- /bin/sh
- -c
- |
set -eu
for directory in \
"$$MATERIAL_ROOT" \
/run/ws-checker \
/run/ws-model-proxy \
/var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-relay/_data; do
chown "$$RUNTIME_OWNER" "$$directory"
chmod 0700 "$$directory"
done
volumes:
- checker_material:/var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-material/_data
- checker_socket:/run/ws-checker
- checker_model_proxy:/run/ws-model-proxy
- checker_model_relay:/var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-relay/_data
# Loopback-only registry so the daemon records a platform-manifest digest.
checker-registry:
profiles: ["agent-loop"]
image: registry:2.8.3@sha256:a3d8aaa63ed8681a604f1dea0aa03f100d5895b6a58ace528858a7b332415373
ports:
- "127.0.0.1:${WORKSTREAM_CHECKER_REGISTRY_HOST_PORT:-15000}:5000"
volumes:
- checker_registry:/var/lib/registry
checker:
profiles: ["agent-loop"]
build:
context: .
dockerfile: docker/checker/Dockerfile.release
image: ${COMPOSE_PROJECT_NAME}-checker:local
init: true
user: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
# Docker socket access is root-equivalent on the daemon. Docker Desktop
# exposes the socket as root:root 0660 (GID 0); Linux uses the docker group.
group_add: ["${WORKSTREAM_DOCKER_SOCKET_GID:-0}"]
command: [/etc/workstream/checker-service.json]
network_mode: none
read_only: true
cap_drop: [ALL]
security_opt: [no-new-privileges:true]
restart: on-failure:5
environment:
DOCKER_CONFIG: /tmp/docker-config
tmpfs:
- /tmp:mode=0700,uid=${LOCAL_UID:-1000},gid=${LOCAL_GID:-1000}
volumes:
- type: bind
source: ${WORKSTREAM_CHECKER_CONFIG_FILE:?set WORKSTREAM_CHECKER_CONFIG_FILE in .env}
target: /etc/workstream/checker-service.json
read_only: true
bind:
create_host_path: false
- type: volume
source: checker_material
target: /var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-material/_data
read_only: true
- checker_socket:/run/ws-checker
- checker_model_proxy:/run/ws-model-proxy:ro
- checker_model_relay:/var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}-checker-relay/_data
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
checker-volumes-init:
condition: service_completed_successfully
healthcheck:
# Connect rather than `test -S`: a socket left on the volume by a killed
# run must not report health before the new process binds it.
test:
- CMD
- python3
- -c
- "import socket; s = socket.socket(socket.AF_UNIX); s.settimeout(2); s.connect('/run/ws-checker/checker.sock'); s.close()"
interval: 5s
timeout: 5s
retries: 12
start_period: 10s
volumes:
checker_material:
name: ${COMPOSE_PROJECT_NAME}-checker-material
checker_socket:
checker_model_proxy:
checker_model_relay:
name: ${COMPOSE_PROJECT_NAME}-checker-relay
checker_registry: