-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
226 lines (210 loc) · 11.6 KB
/
Copy pathdocker-compose.yml
File metadata and controls
226 lines (210 loc) · 11.6 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
214
215
216
217
218
219
220
221
222
223
224
225
226
services:
# ─── PostgreSQL ────────────────────────────────────────
postgres:
image: postgres:17
restart: unless-stopped
environment:
POSTGRES_DB: fara
POSTGRES_USER: openpg
POSTGRES_PASSWORD: openpgpwd
# ports:
# - "5433:5432"
volumes:
- pgdata:/var/lib/postgresql/data
# PostgreSQL разумные дефолты для небольшого prod-стенда
# (подобраны под 2 vCPU / 4 GB RAM — работают на любой машине от этого размера).
# Если у тебя больше RAM — подкрути цифры по комментариям.
# Формат: "наше значение # PG default: <дефолт>"
command:
- "postgres"
# ── Memory ────────────────────────────────────────
# shared_buffers: главный кеш таблиц/индексов в RAM.
# Правило: 25% RAM. Для 4GB = 256MB, 8GB = 1GB, 16GB = 4GB.
- "-c"
- "shared_buffers=512MB" # PG default: 128MB
# effective_cache_size: ПОДСКАЗКА планировщику (память не резервируется),
# сколько данных помещается в OS page cache + shared_buffers.
# Правило: 50-75% RAM. Для 4GB = 2GB, 8GB = 4GB, 16GB = 12GB.
- "-c"
- "effective_cache_size=4GB" # PG default: 4GB
# work_mem: RAM на каждую sort/hash операцию в запросе.
# Дефолт 4MB безопасен — не взорвёт память при много коннектов.
# Для 8GB+ RAM можно поднять до 16MB.
- "-c"
- "work_mem=8MB" # PG default: 4MB (оставлен)
# maintenance_work_mem: RAM для VACUUM / CREATE INDEX.
# Ускоряет создание индексов и вакуум. Для 8GB+ можно 512MB, 16GB+ — 1GB.
- "-c"
- "maintenance_work_mem=128MB" # PG default: 64MB
# ── Planner (SSD-оптимизированные) ────────────────
# random_page_cost: стоимость random read vs sequential.
# Дефолт 4.0 для HDD, для SSD/NVMe = 1.1. Разница критична — на HDD-дефолте
# планировщик делает seq scan вместо index scan.
- "-c"
- "random_page_cost=1.1" # PG default: 4.0 (HDD)
# effective_io_concurrency: сколько параллельных IO-запросов может сделать диск.
# Для SSD = 200, NVMe = 300, HDD = 2. По умолчанию всего 1.
- "-c"
- "effective_io_concurrency=200" # PG default: 1
# ── WAL / Checkpoints ─────────────────────────────
# checkpoint_completion_target: размазывает IO от checkpoint по времени.
# В PG 16+ уже дефолт 0.9, указан явно для явности.
- "-c"
- "checkpoint_completion_target=0.9" # PG default: 0.9 (PG 16+)
# ── Logging (диагностика) ─────────────────────────
# Логирует запросы дольше 1000 мс — помогает ловить slow queries.
- "-c"
- "log_min_duration_statement=1000" # PG default: -1 (off)
# Логирует ожидания блокировок (lock contention).
- "-c"
- "log_lock_waits=on" # PG default: off
- "-c"
- "max_connections=150" # PG default: 100
# Dev shared memory для параллельных запросов и больших shared_buffers.
# Дефолт Docker всего 64MB, не хватает даже для умеренного shared_buffers.
# равно или чуть больше shared_buffers
shm_size: 512MB # Docker default: 64MB
healthcheck:
test: ["CMD-SHELL", "pg_isready -U openpg -d fara"]
interval: 5s
timeout: 3s
retries: 10
# ─── Backend (FastAPI) ─────────────────────────────────
backend:
build:
context: .
dockerfile: docker/backend.Dockerfile
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
env_file:
- .env
environment:
# DB config (env_nested_delimiter="__")
DOTORM_DATABASES_POSTGRES__FARA__HOST: postgres
# DOTORM_DATABASES_POSTGRES__FARA__PORT: 5432
# DOTORM_DATABASES_POSTGRES__FARA__USER: openpg
# DOTORM_DATABASES_POSTGRES__FARA__PASSWORD: openpgpwd
# DOTORM_DATABASES_POSTGRES__FARA__DATABASE: fara
# DOTORM_DATABASES_POSTGRES__FARA__DRIVER: asyncpg
# DOTORM_DATABASES_POSTGRES__FARA__SYNC_DB: "true"
# Workers count
# WEB_WORKERS: 2
# Disable SSL for local Docker postgres
PGSSLMODE: prefer
# Logger
LOGGER__LOG_LEVEL: DEBUG
# Cookie only https, because use double token pattern
AUTH__COOKIE_SECURE: true
AUTH__COOKIE_NAME: session_cookie
AUTH__COOKIE_SAMESITE: lax
# Cron settings
# CRON__ENABLED: "true"
# CRON__CHECK_INTERVAL: 60
# CRON__MAX_THREADS: 2
# Work with external api, Telegram, Whatsapp, Google etc...
# SITE_URL: "https://mydomain.com"
# API_URL: "https://mydomain.com/api"
# SITE_URL: "http://127.0.0.1:7777"
# API_URL: "http://127.0.0.1:7777/api"
# ports:
# - "8000:8000"
# Секрет релея: бэкенд создаёт файл при первом старте, релей читает.
# Отдельный том, а не filestore: оттуда файлы раздаются наружу.
TURN__SECRET_FILE: /run/turn/secret
volumes:
- filestore_docker:/app/filestore
- turn_secret:/run/turn
security_opt:
- no-new-privileges:true
# ─── TURN/STUN (coturn) ────────────────────────────────
# Релей для звонков: и для внутренних WebRTC между сотрудниками, и для
# звонилки в браузере к АТС. Нужен там, где прямое p2p не собирается —
# симметричный NAT у мобильных операторов, закрытый наружу UDP в офисе.
#
# Поднимается ВМЕСТЕ со всем остальным (docker compose up -d). Секрет
# генерируется сам, адрес релея берётся из site_url, а если он не задан —
# из домена, по которому браузер открыл CRM. Настраивать руками нечего.
# Не забудьте открыть порты в фаерволе хоста: host-сеть, в отличие от
# опубликованных портов, правила ufw НЕ обходит. Одна команда на всё:
# sudo bash deploy/open-turn-ports.sh
#
# Выключить: TURN__ENABLED=false в .env (тогда CRM отдаёт только STUN) и,
# если контейнер не нужен вовсе, `docker compose stop turn`.
turn:
image: coturn/coturn:4.6
restart: unless-stopped
# host-сеть — не прихоть: релею нужен диапазон портов и настоящие адреса
# клиентов, а публикация сотни UDP-портов через docker-proxy поднимает
# сотню процессов. На Linux-проде это правильный режим; на Docker Desktop
# (Windows/macOS) host-режима нет — там см. закомментированный вариант.
network_mode: host
# ports:
# - "3478:3478/udp"
# - "3478:3478/tcp"
# - "49160-49259:49160-49259/udp"
volumes:
- ./docker/turnserver.conf:/etc/coturn/turnserver.conf:ro
# Секрет: общий файл с бэкендом. Он его создаёт при первом старте,
# релей — только читает. Через переменные окружения это не сделать:
# compose подставляет их при СОЗДАНИИ контейнера, поэтому любая правка
# требовала бы пересоздавать оба сервиса, а опечатка в регистре имени
# давала бы молча пустой секрет и релей, отвергающий все звонки.
- turn_secret:/run/turn:ro
# TLS: сертификат сайта от certbot (см. deploy/proxy) — только вместе с
# копированием ключа под пользователя релея, см. docker/turnserver.conf.
# - ./deploy/proxy/certbot/conf:/etc/letsencrypt:ro
# Ждём секрет: при первом запуске релей может стартовать раньше бэкенда.
# $$ — экранирование для compose: подстановку делает шелл контейнера, а не
# compose. TURN_EXTRA_ARGS (из .env, ЗАГЛАВНЫМИ) — для того, что зависит
# от площадки:
# --external-ip=<белый IP> (облако с 1:1 NAT: адрес не виден изнутри)
# --allowed-peer-ip=<АТС> (если АТС в приватной сети)
# --cert=... --pkey=... (TLS)
entrypoint: ["/bin/sh", "-c"]
command:
- >
until [ -s /run/turn/secret ]; do
echo "[turn] жду секрет от бэкенда..."; sleep 2;
done;
exec turnserver -c /etc/coturn/turnserver.conf
--realm=${TURN__REALM:-fara}
--static-auth-secret="$$(cat /run/turn/secret)"
${TURN_EXTRA_ARGS:-}
healthcheck:
# Отвечает ли релей на STUN с самой машины. Не доказывает доступность
# снаружи (это делает кнопка «Проверить релей» в CRM), но ловит самое
# частое: контейнер жив, а turnserver внутри упал.
test: ["CMD-SHELL", "turnutils_stunclient -p 3478 127.0.0.1 >/dev/null 2>&1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
# В логах релея видно, кто и с какого адреса звонил, — это персональные
# данные и заметный объём. Ограничиваем срок их жизни явно.
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
security_opt:
- no-new-privileges:true
# ─── Frontend (Nginx + React SPA) ─────────────────────
frontend:
build:
context: .
dockerfile: docker/frontend.Dockerfile
restart: unless-stopped
depends_on:
- backend
# ports:
# - "7777:80"
security_opt:
- no-new-privileges:true
volumes:
pgdata:
filestore_docker:
# Общий секрет TURN. Живёт в томе, а не в .env: его пишет бэкенд, читает
# релей, и оба делают это в рантайме.
turn_secret: