-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
167 lines (163 loc) · 8.26 KB
/
Copy pathdocker-compose.yml
File metadata and controls
167 lines (163 loc) · 8.26 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
services:
app:
build:
context: .
# Match the container user to the host user so files written into the
# bind mount below are not root-owned. Set UID/GID in .env -- see
# .env.example. Changing these needs a rebuild AND `docker compose down
# -v`, because the anonymous node_modules volume keeps the ownership it
# was first created with.
args:
UID: ${UID:-1000}
GID: ${GID:-1000}
ports:
- '4200:4200'
- '4001:4001'
volumes:
- .:/app
- /app/node_modules
# This ensures the nested tina folder is visible to the watcher
- ./projects/website-angular/tina:/app/projects/website-angular/tina
# localhost inside a container is the container. The Reactome backend
# (Tomcat, and behind it Neo4j and Solr) runs on the host, so reach it
# through the docker bridge gateway. proxy.conf.js reads this and otherwise
# defaults to localhost:8080, which is correct when running on the host.
extra_hosts:
- 'host.docker.internal:host-gateway'
environment:
- NG_CLI_ANALYTICS=false
- NODE_ENV=development
- REACTOME_BACKEND=http://host.docker.internal:8080
# The render service is a sibling container, not loopback. proxy.conf.js
# reads this and otherwise defaults to 127.0.0.1:4310, which is correct
# when both run on the host.
- RENDER_TARGET=http://render:4310
stdin_open: true
tty: true
# Diagram figures for documents -- GIF, PPTX, PDF, PNG, SVG -- rendered by
# driving the app's own render page, so an exported figure cannot drift from
# what a curator sees. Replaces the Java exporters, which reimplement the
# drawing.
render:
build:
context: .
dockerfile: deploy/render-service/Dockerfile
# A render is a browser holding a large canvas, and this box also runs the
# site, Tomcat and Neo4j. If it wedges or runs out of memory, restarting is
# the right response -- there is no state to lose but the cache, which is on
# a volume.
restart: unless-stopped
# Loopback only, never 0.0.0.0. The site's own origin proxies /RenderService
# to this, so a render can only be commissioned through whatever fronts the
# site -- crawlers on the old /ContentService/exporter/* URLs are what
# exhausted Tomcat's heap and took the origin down. Publishing it here rather
# than relying on the compose network because on the dev box the site itself
# runs on the host, not in compose; a deployment where both are containers can
# drop this line and reach it by service name.
ports:
- '127.0.0.1:4310:4310'
environment:
# What it renders. The service name when the site is a container here, the
# host when it is not -- which is the case on the dev box.
- RENDER_BASE=${RENDER_BASE:-http://host.docker.internal:4200}
- RENDER_CACHE=/cache
- RENDER_CONCURRENCY=2
- RENDER_QUEUE=8
volumes:
- render-cache:/cache
# No depends_on: the site it renders may be the app service or may be on the
# host, and starting a second app container would fight the first for :4200.
extra_hosts:
- 'host.docker.internal:host-gateway'
# Chromium's default 64 MB /dev/shm is not enough for a 6000px canvas; a
# renderer that fails only on large diagrams is the usual symptom.
shm_size: '1gb'
content-node:
build:
context: .
dockerfile: deploy/content-node/Dockerfile
# It holds two lists in memory and nothing else, so a restart costs one
# rebuild of the caches -- about four seconds -- and never any data. Left
# unsupervised it runs only because somebody started it by hand, and the
# contents page goes blank the first time this box reboots, with nothing to
# connect the outage to a restart hours earlier.
restart: unless-stopped
# Host networking, for as long as the graph is on the host.
#
# Neo4j listens on 127.0.0.1:7687 and should keep doing so. A bridged
# container cannot reach that, and the usual workaround -- binding Neo4j to
# the docker bridge -- widens who can reach the database to fit a container
# in. Sharing the host's namespace keeps the database exactly as reachable
# as it is today and the service on loopback where nginx expects it.
#
# **This is the line to delete when the graph becomes a container**, which
# is the plan: a Neo4j image built per release. Then this joins the compose
# network, `NEO4J_URI` names that service instead of loopback, and it
# publishes 127.0.0.1:4400 like `render` does. `graph.mjs` already reads
# NEO4J_URI from the environment, so that is configuration rather than a
# change here. Recorded in specs/006 D13 so the reason is findable when the
# line looks arbitrary.
network_mode: host
# The credentials file is **mounted, not parsed**. graph.mjs reads it
# literally for a documented reason: a generated secret contains characters
# a shell eats, and sourcing one silently produced an empty password once.
#
# compose's own `env_file` parser does the same thing. Tried first, and it
# read `NEO4J_DATABASE=graph.db` correctly while handing the service
# `NEO4J_PASSWORD=""` -- the service then reported "graph credentials:
# MISSING" and every request 500'd. Exactly the fault the literal reader was
# written to avoid, reintroduced by the layer underneath it.
volumes:
- ${CONTENT_NODE_ENV_FILE:-~/.content-node.env}:/run/secrets/content-node.env:ro
environment:
- CONTENT_NODE_ENV_FILE=/run/secrets/content-node.env
# Runs as the owner of that file, which is 0600 and should stay that way.
# The image's own `node` user is uid 1000 and cannot read it, so the service
# started, reported "graph credentials: MISSING", and answered 500 -- a
# container that is up and useless, which is the state monitoring is worst
# at noticing.
#
# Defaults to this host's operator; override where the file has a different
# owner. `id -u`, `id -g`.
user: '${CONTENT_NODE_UID:-1020}:${CONTENT_NODE_GID:-1001}'
# No depends_on: Neo4j is not in this compose file. If it is down the
# service starts, fails to build its lists, and rebuilds on the next
# request -- which is the behaviour specs/006 D10 asks for.
# The front door. Replaces the hand-created `reactome-nginx` container, which
# mounted its config from /etc/nginx-reactome -- a *copy* of deploy/nginx that
# had to be installed with sudo and could drift from the repository without
# anything saying so. The only reason it was known to match today is that
# somebody diffed it.
#
# Mounting the repository instead makes this the single source: edit
# deploy/nginx, `docker compose exec nginx nginx -t`, reload. No sudo, no
# OS-specific install path, and it works the same on a laptop.
#
# To take over from the hand-created container:
# docker stop reactome-nginx
# docker compose up -d nginx
# To go back: `docker compose stop nginx && docker start reactome-nginx`.
# Both bind the host's ports, so only one can run at a time.
nginx:
image: nginx:alpine
restart: unless-stopped
# Host networking, as the container it replaces used: the services it
# proxies -- the site on 4200, content-node on 4400, render on 4310, the
# chatbot on 8000 -- are reached on loopback, and several of them bind there
# deliberately so nothing else can.
network_mode: host
volumes:
# Which environment this host is. dev.conf here; production.conf on the
# host that must be indexed, where the blanket bot rule would be
# catastrophic rather than merely wrong. See deploy/nginx/README.md.
- ./deploy/nginx/${NGINX_ENV:-dev}.conf:/etc/nginx/conf.d/default.conf:ro
- ./deploy/nginx/common:/etc/nginx/common:ro
# The one part that cannot live in the repository. Paths are variables so
# a laptop can point somewhere else, or at an empty directory when it is
# serving plain HTTP and has no certificates at all.
- ${LETSENCRYPT_DIR:-/etc/letsencrypt}:/etc/letsencrypt:ro
- ${CLOUDFLARE_CERT_DIR:-/etc/ssl/cloudflare}:/etc/ssl/cloudflare:ro
volumes:
# Survives a container replacement, which is the point: a cached figure is a
# file read, and rebuilding the cache means paying for every render again.
render-cache: