Repository navigation
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
203 lines (195 loc) · 8.85 KB
/
Copy pathdocker-compose.yml
File metadata and controls
203 lines (195 loc) · 8.85 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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
name: api-platform-lab
# ==============================================================================
# SECURITY POSTURE
#
#
# Also applied here:
# - all ports bound to 127.0.0.1, so nothing is reachable from your network
# - cap_drop: ALL, with only the capabilities each image actually needs
# - no-new-privileges, blocking setuid escalation inside the container
# - memory limits, so a runaway container cannot eat the VM
# - every bind mount is :ro and inside this project directory
#
# Not applied: nothing is privileged, the docker socket is not mounted, no
# host networking, and there are no Dockerfiles - nothing is built, only pulled.
#
# Provenance, stated plainly: nginx is a Docker Official Image. toxiproxy is
# published by Shopify's GitHub org. go-httpbin and http-https-echo are
# individuals' repos - both well-known open-source projects, both still
# strangers on the internet.
# ==============================================================================
#
# client (you, with curl)
# |
# gateway (nginx) :8080 http :8443 https
# |
# +--> echo_pool --> echo1 / echo2 (echo servers, show what the proxy did)
# +--> toxiproxy_pool --> toxiproxy --> random-status-code-with-caching (network chaos lives here)
# +--> flaky_pool --> random-status-code-1 / random-status-code-2 (return 500s on demand)
#
# Every upstream is ALSO published on localhost (ports 9001-9005) so you can
# compare "straight to the service" against "through the gateway".
#
# ------------------------------------------------------------------------------
# A NOTE ON `ports:`
#
# Each container is its own little sealed box - nothing outside it can reach
# anything inside it by default. A `ports:` entry is a door: it connects one
# port on your Mac to one port inside that container, so a service becomes
# reachable at all. No entry, no door, no access - which is exactly the
# default posture you want for anything that doesn't need to be public.
#
# Each line reads "host_ip:host_port:container_port". The last number is the
# one that matters: it's the port the process *inside* the container actually
# listens on, fixed by whoever built that image (or an env var, where noted).
# The middle number is just the door's address on your Mac - it can be
# anything free, and below is what you'd actually type into curl. Every door
# here is bound to 127.0.0.1 (see SECURITY POSTURE above), so the only thing
# that can walk through any of them is you, on this machine.
# ------------------------------------------------------------------------------
services:
# ---------------------------------------------------------------------------
# The gateway. This is the only thing you edit.
# ---------------------------------------------------------------------------
gateway:
image: nginx:1.27-alpine@sha256:65645c7bb6a0661892a8b03b89d0743208a18dd2f3f17a54ef4b76fb8e2f2a10
container_name: lab-gateway
hostname: gateway
# curl this side (8080/8443) - the other side (80/443) is just where
# nginx listens inside its own container.
ports:
- "127.0.0.1:8080:80"
- "127.0.0.1:8443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/snippets:/etc/nginx/snippets:ro
- ./nginx/certs:/etc/nginx/certs:ro
# nginx starts as root to bind :80 and read certs, then drops to the nginx
# user for its workers - hence these four and nothing else.
cap_drop: [ALL]
cap_add: [CHOWN, SETUID, SETGID, NET_BIND_SERVICE]
security_opt:
- no-new-privileges:true
mem_limit: 256m
depends_on:
- echo1
- echo2
- random-status-code-with-caching
- random-status-code-1
- random-status-code-2
- toxiproxy
healthcheck:
# 127.0.0.1, not localhost: busybox wget tries ::1 first, and this nginx
# only listens on IPv4 (the image's IPv6 entrypoint script patches
# conf.d/default.conf, which our config does not include).
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://127.0.0.1/healthz"]
interval: 10s
timeout: 3s
retries: 3
start_period: 5s
# ---------------------------------------------------------------------------
# Two identical echo instances, so load balancing has something to balance.
# This image echoes the request back as JSON - headers, path, source IP -
# which is how you SEE what a proxy does to a request.
# ---------------------------------------------------------------------------
echo1:
image: mendhak/http-https-echo:35@sha256:440ca6b810bc04606aac700e461caca5543eaa882c4e0af96a33424d05a23592
container_name: lab-echo1
hostname: echo1
environment:
HTTP_PORT: "8080"
HTTPS_PORT: "8443"
# curl this side (9001) to hit the backend directly, bypassing the
# gateway entirely - the other side (8080) is just where it listens
# inside its own container, set by HTTP_PORT above.
ports:
- "127.0.0.1:9001:8080"
cap_drop: [ALL]
security_opt:
- no-new-privileges:true
mem_limit: 256m
echo2:
image: mendhak/http-https-echo:35@sha256:440ca6b810bc04606aac700e461caca5543eaa882c4e0af96a33424d05a23592
container_name: lab-echo2
hostname: echo2
environment:
HTTP_PORT: "8080"
HTTPS_PORT: "8443"
# Same idea as echo1's ports, one door down.
ports:
- "127.0.0.1:9002:8080"
cap_drop: [ALL]
security_opt:
- no-new-privileges:true
mem_limit: 256m
# ---------------------------------------------------------------------------
# Backend for the /network-chaos/ route: go-httpbin, same image as the two
# random-status-code containers below. Named for what differentiates it
# from them here: it's also used for /delay/N, /cache/N, and /etag/X, and
# its traffic is routed THROUGH toxiproxy (see below) rather than hit
# directly, so it's where the network-chaos labs live too.
# ---------------------------------------------------------------------------
random-status-code-with-caching:
image: mccutchen/go-httpbin:2.25.0@sha256:20739736d4eb8dc1b998dff701f437b8bd62dcc46492bd0d861e89890ca36500
container_name: lab-random-status-code-with-caching
hostname: random-status-code-with-caching
# curl this side (9003) to hit it directly - the other side (8080) is
# go-httpbin's own default listen port, not something we set.
ports:
- "127.0.0.1:9003:8080"
cap_drop: [ALL]
security_opt:
- no-new-privileges:true
mem_limit: 128m
# ---------------------------------------------------------------------------
# Backend for the /flaky/ route: two instances of the same go-httpbin image
# used above, both asked for /status/200:0.5,500:0.5, which returns 500
# about half the time - random, not a property of the container itself.
# Two instances so nginx has a second one to retry against.
# ---------------------------------------------------------------------------
random-status-code-1:
image: mccutchen/go-httpbin:2.25.0@sha256:20739736d4eb8dc1b998dff701f437b8bd62dcc46492bd0d861e89890ca36500
container_name: lab-random-status-code-1
hostname: random-status-code-1
# Same idea as the ports above.
ports:
- "127.0.0.1:9004:8080"
cap_drop: [ALL]
security_opt:
- no-new-privileges:true
mem_limit: 128m
random-status-code-2:
image: mccutchen/go-httpbin:2.25.0@sha256:20739736d4eb8dc1b998dff701f437b8bd62dcc46492bd0d861e89890ca36500
container_name: lab-random-status-code-2
hostname: random-status-code-2
ports:
- "127.0.0.1:9005:8080" # same idea as random-status-code-1's ports
cap_drop: [ALL]
security_opt:
- no-new-privileges:true
mem_limit: 128m
# ---------------------------------------------------------------------------
# Toxiproxy sits on the wire between the gateway and the /network-chaos/ backend.
# Its admin API (:8474) lets you add latency, throttle bandwidth, or
# blackhole the connection at runtime - no restarts. See bin/chaos.sh.
# ---------------------------------------------------------------------------
toxiproxy:
image: ghcr.io/shopify/toxiproxy:2.12.0@sha256:9378ed52a28bc50edc1350f936f518f31fa95f0d15917d6eb40b8e376d1a214e
container_name: lab-toxiproxy
hostname: toxiproxy
command: ["-host=0.0.0.0", "-config=/config/toxiproxy.json"]
volumes:
- ./toxiproxy/toxiproxy.json:/config/toxiproxy.json:ro
# This one door (8474) reaches toxiproxy's admin API, which is what
# bin/chaos.sh talks to. It also has a second listener inside, the one
# that actually proxies traffic to random-status-code-with-caching
# (defined in toxiproxy.json) - that one has no door here on purpose, so
# it's only reachable from other containers, never from your host.
ports:
- "127.0.0.1:8474:8474"
cap_drop: [ALL]
security_opt:
- no-new-privileges:true
mem_limit: 128m
depends_on:
- random-status-code-with-caching