-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathdocker-compose.yaml
More file actions
181 lines (174 loc) · 6.36 KB
/
Copy pathdocker-compose.yaml
File metadata and controls
181 lines (174 loc) · 6.36 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
services:
postgres:
image: postgres:latest
restart: always
volumes:
- pg_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_DB: ${POSTGRES_DB}
ports:
- 5432:5432
healthcheck:
test: ["CMD-SHELL", "pg_isready", "-d", "db_prod"]
interval: 30s
timeout: 60s
retries: 5
start_period: 80s
hasura:
image: hasura/graphql-engine:latest.cli-migrations-v3
restart: always
depends_on:
postgres:
condition: service_healthy
ports:
- 4000:8080
volumes:
- ./hasura/metadata:/hasura-metadata
- ./hasura/migrations:/hasura-migrations
environment:
HASURA_GRAPHQL_METADATA_DIR: /hasura-metadata
HASURA_GRAPHQL_MIGRATIONS_DIR: /hasura-migrations
HASURA_GRAPHQL_DATABASE_URL: ${HASURA_DATABASE_URL}
HASURA_GRAPHQL_ADMIN_SECRET: ${HASURA_ADMIN_SECRET}
HASURA_GRAPHQL_JWT_SECRET: '{"type": "HS256", "key": "${HASURA_JWT_SECRET}", "audience": "${HASURA_JWT_AUDIENCE}", "issuer": "${HASURA_JWT_ISSUER}"}'
HASURA_GRAPHQL_ENABLE_CONSOLE: ${HASURA_ENABLE_CONSOLE}
HASURA_GRAPHQL_DEV_MODE: ${HASURA_GRAPHQL_DEV_MODE}
HASURA_GRAPHQL_PG_CONNECTIONS: 4
HASURA_GRAPHQL_UNAUTHORIZED_ROLE: public
command:
- graphql-engine
- serve
# Untrusted-input compilers. Cap resources and drop privileges. Not read_only:
# these compilers write intermediate files; confirm a writable path per image
# before tightening further. NET_BIND_SERVICE is the one capability kept, so
# the non-root uvicorn can bind port 80.
# NOTE: the healthchecks need the hardened images (which add /health to z88dk)
# rebuilt and pushed — see zxcode-api-z88dk / zxcode-api-zxbasic.
z88dk:
image: ghcr.io/stever/zxcode-api-z88dk
restart: always
mem_limit: 512m
cpus: 1.0
pids_limit: 256
cap_drop: [ALL]
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:80/health',timeout=3).status==200 else 1)"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
zxbasic:
image: ghcr.io/stever/zxcode-api-zxbasic
restart: always
mem_limit: 512m
cpus: 1.0
pids_limit: 256
cap_drop: [ALL]
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:80/health',timeout=3).status==200 else 1)"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
# Headless emulator: compiles a program to .tap and renders it running to
# GIF/MP4. Renders inline BASIC, or a public project looked up from Hasura
# (compiling asm/bas2tap in-process and zxbasic/c via the Hasura actions).
# Talks to Hasura as the unauthenticated `public` role, so it holds no
# secrets. Does untrusted execution; not exposed publicly.
gif-service:
build:
context: .
dockerfile: apps/gif-service/Dockerfile
restart: always
depends_on:
- hasura
environment:
HASURA_URL: http://hasura:8080/v1/graphql
# Untrusted execution: cap CPU/mem/processes and drop privileges. Root FS is
# read-only with a writable tmpfs for the temp mp4/f32le files it creates.
# NOTE: verify `user: node` + `read_only` on first deploy — the image must
# let the node user read /app and tsx must cache under /tmp.
mem_limit: 1g
cpus: 2.0
pids_limit: 512
user: node
read_only: true
tmpfs:
- /tmp
volumes:
- screenshot_cache:/cache
cap_drop: [ALL]
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:5001/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
# NETWORK ISOLATION (prod): gif-service + zxbasic + z88dk need no inbound
# internet, only intra-stack traffic (gif-service -> hasura; hasura ->
# zxbasic/z88dk). In the prod compose put them on an `internal: true`
# network that also carries hasura. Not wired here to avoid breaking dev
# connectivity that can't be validated in this repo.
#
# AUTO-RESTART ON HANG: plain `restart: always` restarts on exit, NOT on an
# unhealthy healthcheck. To recover a wedged event loop automatically, run
# an autoheal sidecar (or Swarm). With compile now isolated in a killable
# child and the render wall-clock guard, the remaining wedge risk is small.
# GoToSocial: the bot's federated identity, served at social.zxplay.org but
# presenting handles as @user@zxplay.org via the account-domain webfinger trick.
# TLS is terminated by the Caddy proxy, so Let's Encrypt is disabled here.
gotosocial:
image: superseriousbusiness/gotosocial:latest
restart: always
environment:
GTS_HOST: social.zxplay.org
GTS_ACCOUNT_DOMAIN: zxplay.org
GTS_PROTOCOL: https
GTS_BIND_ADDRESS: 0.0.0.0
GTS_PORT: "8080"
GTS_DB_TYPE: sqlite
GTS_DB_ADDRESS: /gotosocial/storage/sqlite.db
GTS_STORAGE_LOCAL_BASE_PATH: /gotosocial/storage
GTS_LETSENCRYPT_ENABLED: "false"
GTS_ACCOUNTS_REGISTRATION_OPEN: "false"
# Trust X-Forwarded-* from the proxy on the Docker network. Tighten to the
# proxy's actual subnet in production.
GTS_TRUSTED_PROXIES: "172.16.0.0/12"
volumes:
- gotosocial_data:/gotosocial/storage
# The Mastodon adapter: holds the access token, watches mentions, calls
# gif-service, posts replies. Runs no untrusted code.
mastodon-bot:
build:
context: .
dockerfile: apps/mastodon-bot/Dockerfile
restart: always
depends_on:
- gif-service
- gotosocial
environment:
# Use the public host so the Host header matches GTS_HOST (GoToSocial
# rejects API requests whose Host is not its configured host).
MASTODON_INSTANCE_URL: https://social.zxplay.org
MASTODON_ACCESS_TOKEN: ${MASTODON_ACCESS_TOKEN}
GIF_SERVICE_URL: http://gif-service:5001
STATE_FILE: /data/state.json
volumes:
- bot_data:/data
volumes:
pg_data:
gotosocial_data:
bot_data:
screenshot_cache: