-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathdocker-compose.dev.yml
More file actions
213 lines (200 loc) · 7.9 KB
/
Copy pathdocker-compose.dev.yml
File metadata and controls
213 lines (200 loc) · 7.9 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
204
205
206
207
208
209
210
211
212
213
# Local mirror of the production streaming path.
#
# publisher -> SRS (ingress) -> ffmpeg ABR -> origin nginx -> origin caddy
# -> edge nginx -> edge caddy -> browser
#
# The Laravel app itself stays native under Yerd; containers reach it through the
# app-bridge service, and SRS webhooks hit it exactly as they do in production.
#
# Start with: ./scripts/dev-stack.sh up
name: streaming-dev
services:
# ------------------------------------------------------------- app bridge
# Plain HTTP entry point to the host-served Laravel app; see
# docker/dev/app-bridge.conf for why this exists.
app-bridge:
image: nginx:1.27-alpine
volumes:
- ./docker/dev/app-bridge.conf:/etc/nginx/conf.d/default.conf:ro
extra_hosts:
- "streaming.test:host-gateway"
restart: unless-stopped
# ---------------------------------------------------------------- ingress
origin-srs:
image: ossrs/srs:5
command: ./objs/srs -c /usr/local/srs/conf/origin.conf
volumes:
- ./docker/dev/origin-srs.conf:/usr/local/srs/conf/origin.conf:ro
ports:
- "1935:1935" # RTMP ingress (point OBS here)
- "1985:1985" # SRS HTTP API
depends_on:
- app-bridge
restart: unless-stopped
# ------------------------------------------------------- ABR transcoding
hls-transcoder:
build: ./docker/ffmpeg-hls
environment:
SRS_API_URL: http://origin-srs:1985/api/v1
SRS_RTMP_URL: rtmp://origin-srs:1935
OUTPUT_BASE_DIR: /var/www/hls/live
CHECK_INTERVAL: "5"
# copy is the local default: the ladder is remuxed rather than encoded, so
# a laptop can hold several channels at once. Set DEV_ABR_MODE=transcode
# when you are actually working on the ladder itself.
ABR_MODE: ${DEV_ABR_MODE:-copy}
# Production runs a 60 minute rewind window (1800 segments). That is ~5GB of
# disk per source, which is not something a laptop wants, so dev defaults to
# 5 minutes. Raise it when you are actually working on the DVR window itself.
DVR_WINDOW_SEGMENTS: ${DEV_DVR_WINDOW_SEGMENTS:-150}
# Archive-only mirror of the publisher's bitstream. /var/www/hls/source is a
# sibling of the ladder's directory, so it falls outside nginx's
# `location ~ ^/live/` and is unreachable by a viewer. In the default
# ABR_MODE=copy dev stack the ladder is already a remux of the same
# bitstream, so this mostly exists to exercise the indexing path; set
# DEV_ARCHIVE_SOURCE=0 to save the disk.
ARCHIVE_SOURCE: ${DEV_ARCHIVE_SOURCE:-1}
SOURCE_OUTPUT_DIR: /var/www/hls/source
volumes:
- hls:/var/www/hls
depends_on:
- origin-srs
restart: unless-stopped
# ----------------------------------------------------------------- origin
origin-nginx:
image: nginx:1.27-alpine
volumes:
- ./docker/dev/origin-nginx.conf:/etc/nginx/nginx.conf:ro
- hls:/var/www/hls
depends_on:
- hls-transcoder
- app-bridge
restart: unless-stopped
origin-caddy:
image: caddy:2-alpine
volumes:
- ./docker/dev/origin-Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-logs:/var/log/caddy
ports:
- "8070:8070" # origin, mostly for debugging
depends_on:
- origin-nginx
restart: unless-stopped
# ------------------------------------------------------------------- edge
# Built rather than pulled: the image adds the njs module and hls-auth.js, so
# playback tokens are verified locally here exactly as they are in production.
edge-nginx:
build: ./docker/edge-nginx
environment:
HLS_VIEWER_SECRET: ${HLS_VIEWER_SECRET:-}
HLS_EMBED_SECRET: ${HLS_EMBED_SECRET:-}
HLS_TOKEN_LEEWAY: ${HLS_TOKEN_LEEWAY:-60}
STREAM_SYSTEM_STREAMKEY: ${STREAM_SYSTEM_STREAMKEY:-}
volumes:
- ./docker/dev/edge-nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- origin-caddy
- app-bridge
restart: unless-stopped
edge-caddy:
image: caddy:2-alpine
volumes:
- ./docker/dev/edge-Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-logs:/var/log/caddy
ports:
# 8085 matches the edge server row that LocalDevelopmentServersSeeder creates.
# 8080 is Yerd's and 8081 is Reverb's, so the edge stays off both.
- "8085:8080"
depends_on:
- edge-nginx
restart: unless-stopped
# --------------------------------------------------------------- storage
# versitygw exposes a plain directory over the S3 API: the segment archive,
# recordings and thumbnails all behave like they do against real object storage.
s3:
image: ghcr.io/versity/versitygw:latest
command: >
--access ${DEV_S3_KEY:-devkey}
--secret ${DEV_S3_SECRET:-devsecret123}
--region ${AWS_DEFAULT_REGION:-eu-central-1}
--port :7070
posix /buckets
volumes:
- s3-data:/buckets
ports:
# Host side only. 7070 is AnyDesk's default listener, which silently wins the
# bind and takes the whole stack down with it, so the host port is both moved
# and overridable. Inside the compose network this is still :7070, which is
# why S3_ENDPOINT below does not change.
- "${DEV_S3_PORT:-7075}:7070"
restart: unless-stopped
s3-init:
image: alpine:3
# versitygw's posix backend treats top-level directories as buckets.
command: sh -c "mkdir -p /buckets/${AWS_BUCKET:-streaming} && echo 'bucket ready'"
volumes:
- s3-data:/buckets
depends_on:
- s3
restart: "no"
# --------------------------------------------------------- segment archive
# Mirrors the transcoder's HLS segments to S3 and maintains the per-hour index
# playlists that recordings are later cut from. This is the only recording path:
# SRS DVR is off and the MP4 uploader is gone.
archive-uploader:
build: ./docker/archive-uploader
command: ["python", "-u", "archive_uploader.py"]
environment:
S3_BUCKET: ${AWS_BUCKET:-streaming}
S3_REGION: ${AWS_DEFAULT_REGION:-eu-central-1}
S3_ACCESS_KEY: ${DEV_S3_KEY:-devkey}
S3_SECRET_KEY: ${DEV_S3_SECRET:-devsecret123}
S3_ENDPOINT: http://s3:7070
HLS_PATH: /var/www/hls/live
ARCHIVE_SOURCE: ${DEV_ARCHIVE_SOURCE:-1}
SOURCE_HLS_PATH: /var/www/hls/source
# Matches DVR_WINDOW_SEGMENTS on the transcoder (150 segments x 2s = 5 min).
# The reaper must never delete inside the window the player can still seek to.
DVR_WINDOW_SECONDS: ${DEV_DVR_WINDOW_SECONDS:-300}
REAP_INTERVAL: "30"
INDEX_UPLOAD_INTERVAL: "20"
# Unlimited locally; S3 is a container on the same host. Set this low
# (e.g. 10, well under the ~11.5 Mbps per source the ladder produces) to
# watch the backlog guard fire.
MAX_UPLOAD_RATE_MBPS: ${DEV_MAX_UPLOAD_RATE_MBPS:-0}
volumes:
- hls:/var/www/hls
- archive-state:/var/lib/dvr-archive
depends_on:
- s3
- hls-transcoder
restart: unless-stopped
# -------------------------------------------------------- fake broadcasters
# Stands in for OBS: one ffmpeg per channel, pushing a distinct animated
# pattern into the ingress app with the channel's stream key.
publisher:
image: linuxserver/ffmpeg:latest
entrypoint: ["/bin/bash", "/publish.sh"]
environment:
RTMP_URL: rtmp://origin-srs:1935/ingress
CHANNELS: ${DEV_PUBLISH_CHANNELS:-}
SIZE: ${DEV_PUBLISH_SIZE:-1280x720}
FPS: ${DEV_PUBLISH_FPS:-30}
# loop encodes one short clip per channel and then pushes it with -c copy,
# so the publishers stop costing CPU once the clips are cached in the
# volume below. Set DEV_PUBLISH_MODE=live for a moving on-screen clock.
MODE: ${DEV_PUBLISH_MODE:-loop}
CLIP_SECONDS: ${DEV_PUBLISH_CLIP_SECONDS:-20}
CLIP_DIR: /clips
volumes:
- ./docker/dev/publish.sh:/publish.sh:ro
- publisher-clips:/clips
depends_on:
- origin-srs
restart: unless-stopped
volumes:
hls:
archive-state:
s3-data:
caddy-logs:
publisher-clips: