Repository navigation
Expand file tree
/
Copy pathcompose.yml
More file actions
161 lines (154 loc) · 6.21 KB
/
Copy pathcompose.yml
File metadata and controls
161 lines (154 loc) · 6.21 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
# Crewship compose stack.
#
# docker compose --profile worker up -d # isolated non-root worker
# docker compose --profile worker --profile data up -d # + example backing services
#
# Everything here is opt-in through profiles: nothing starts with a bare
# `docker compose up`. See docs/agents/architecture.md#docker-worker for image targets.
#
# Security boundary (see docs/security.md):
# * no privileged containers, no host PID/IPC/network namespaces
# * no host Docker socket, no bind of host home, credentials or browser profiles
# * published ports are loopback-only; service-to-service traffic uses the
# project network by DNS name (postgres, redis) and needs no host port at all
# * the PostgreSQL password is a file secret outside the source checkout
# (no baked default password and no password in this file or environment)
#
# Images come from mirror.gcr.io, Google's Docker Hub mirror, which has no
# anonymous pull limit. Digests verified 2026-10-09 to match registry-1.docker.io:
# postgres:18-bookworm sha256:1c59e2c3c818eaa0f0628f695b36e7c9e362d6b219b36a54a32df645cbd7e1af
# (amd64 sha256:a10c981235b4f635e65df0cfb66a5598064628128505dbc6a3ed4ca303717521,
# PG_VERSION=18.6-1.pgdg12+2, created 2026-08-25)
# redis:8-alpine sha256:becdda6c7f4b3fb42e42fd7f120bbf5c54c4caaaf16f26da24e4563d2c1f0576
# (amd64 sha256:9c3ecc609a8087c0f11c494fefaf37a8f7bf9a967631d4a0da8967a9810be354,
# REDIS_VERSION=8.10.1, created 2026-08-18)
#
# Copy blueprint/containers/worker.env.example to .env (ignored) to override the defaults.
name: crewship
services:
worker:
profiles: ["worker"]
build:
context: .
dockerfile: Dockerfile
target: worker
args:
CREWSHIP_USER: ${CREWSHIP_USER:-coder}
CREWSHIP_UID: ${CREWSHIP_UID:-1000}
CREWSHIP_GID: ${CREWSHIP_GID:-1000}
CREWSHIP_HOME: ${CREWSHIP_HOME:-/home/coder}
CREWSHIP_WORKSPACE: ${CREWSHIP_WORKSPACE:-/home/coder/Dev}
image: crewship/worker:${CREWSHIP_TAG:-dev}
# PID 1 reaper only: this is signal handling, not an init system. The image
# has no systemd, no user manager and no linger.
init: true
command: ["sleep", "infinity"]
working_dir: ${CREWSHIP_WORKSPACE:-/home/coder/Dev}
environment:
CREWSHIP_CONFIG: /opt/crewship/blueprint/containers/crewship.container.yml
CREWSHIP_ROOT: /opt/crewship
volumes:
- workspace:${CREWSHIP_WORKSPACE:-/home/coder/Dev}
tmpfs:
- /tmp:rw,nosuid,nodev,size=1g,mode=1777
networks: [crewship]
# Bounded resources: a runaway build or agent cannot exhaust the host.
cpus: "${WORKER_CPUS:-4}"
mem_limit: ${WORKER_MEMORY:-6g}
memswap_limit: ${WORKER_MEMORY:-6g}
mem_reservation: ${WORKER_MEMORY_RESERVATION:-1g}
pids_limit: ${WORKER_PIDS:-4096}
shm_size: ${WORKER_SHM:-512m}
ulimits:
nofile:
soft: 8192
hard: 16384
cap_drop: ["NET_RAW"]
# `no-new-privileges` is deliberately NOT set on the worker: ansible become
# for a second convergence pass goes through setuid sudo inside the container.
# The backing services below do set it, since their entrypoints drop
# privileges from root instead of escalating.
stop_grace_period: 15s
# ---------------------------------------------------------------------------
# Optional development backing services. These are generic examples for local
# work, NOT a reproduction of any captured application deployment: empty
# volumes, no imported data, no application schema, no production topology.
# ---------------------------------------------------------------------------
postgres:
profiles: ["data"]
image: mirror.gcr.io/library/postgres:18-bookworm@sha256:1c59e2c3c818eaa0f0628f695b36e7c9e362d6b219b36a54a32df645cbd7e1af
init: true
environment:
POSTGRES_USER: ${POSTGRES_USER:-developer}
POSTGRES_DB: ${POSTGRES_DB:-developer}
# No POSTGRES_PASSWORD here by design; the value is read from the secret file.
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
POSTGRES_INITDB_ARGS: "--data-checksums"
secrets:
- postgres_password
ports:
- "127.0.0.1:${POSTGRES_PORT:-15432}:5432"
volumes:
- postgres-data:/var/lib/postgresql
networks: [crewship]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U \"${POSTGRES_USER:-developer}\" -d \"${POSTGRES_DB:-developer}\" -h 127.0.0.1"]
interval: 10s
timeout: 5s
retries: 12
start_period: 30s
cpus: "${POSTGRES_CPUS:-1}"
mem_limit: ${POSTGRES_MEMORY:-1g}
memswap_limit: ${POSTGRES_MEMORY:-1g}
pids_limit: ${POSTGRES_PIDS:-512}
shm_size: 256m
security_opt: ["no-new-privileges:true"]
cap_drop: ["ALL"]
cap_add: ["CHOWN", "DAC_OVERRIDE", "FOWNER", "SETGID", "SETUID"]
restart: unless-stopped
redis:
profiles: ["data"]
image: mirror.gcr.io/library/redis:8-alpine@sha256:becdda6c7f4b3fb42e42fd7f120bbf5c54c4caaaf16f26da24e4563d2c1f0576
init: true
command:
- "redis-server"
- "--save"
- "300 10"
- "--appendonly"
- "no"
- "--maxmemory"
- "${REDIS_MAXMEMORY:-256mb}"
- "--maxmemory-policy"
- "allkeys-lru"
ports:
- "127.0.0.1:${REDIS_PORT:-16379}:6379"
volumes:
- redis-data:/data
networks: [crewship]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 12
start_period: 10s
cpus: "${REDIS_CPUS:-1}"
mem_limit: ${REDIS_MEMORY:-512m}
memswap_limit: ${REDIS_MEMORY:-512m}
pids_limit: ${REDIS_PIDS:-256}
security_opt: ["no-new-privileges:true"]
cap_drop: ["ALL"]
cap_add: ["CHOWN", "DAC_OVERRIDE", "SETGID", "SETUID"]
restart: unless-stopped
networks:
crewship:
driver: bridge
volumes:
workspace:
postgres-data:
redis-data:
secrets:
postgres_password:
# Keep credentials outside the checkout: Git/Docker ignores do not protect
# an editor's runtime workspace bind. Override this directory explicitly
# when invoking Compose through sudo so HOME cannot change its meaning.
file: "${CREWSHIP_SECRET_DIR:-${HOME}/.local/state/crewship/secrets}/postgres_password"