Implement media storage and processing features: update configuration in .env.example and appsettings files, enhance Docker setup for media storage, and add media-related services and database entities. Include ffmpeg for media handling and adjust Kestrel settings for large file uploads.

This commit is contained in:
Leonid Pershin
2026-07-24 08:33:11 +03:00
parent 1dd6991174
commit e15ecbdb29
47 changed files with 2599 additions and 1 deletions
+200
View File
@@ -0,0 +1,200 @@
# Подготовка диска под медиахранилище (tvvm)
Runbook: разметка, форматирование и монтирование диска `sdb` (700G) под хранилище TeleWave.
Выполняется **один раз** на сервере `tvvm` перед запуском фичи медиа. Все команды — от root
(`sudo -i` или с `sudo` перед каждой).
> ⚠️ Команды разметки **уничтожают данные** на целевом диске. Диск `sdb` сейчас пустой (нет
> разделов), но каждый шаг ниже содержит проверку — не пропускайте их.
Итог: раздел `sdb1` (ext4) смонтирован в `/srv/telewave/media`, внутри созданы рабочие каталоги,
запись из контейнера (сейчас работает под root) возможна.
---
## 0. Проверить, что это тот самый диск
```bash
lsblk -o NAME,SIZE,TYPE,MOUNTPOINTS,FSTYPE /dev/sdb
```
Ожидается: `sdb` размером `700G`, тип `disk`, **без разделов и без точек монтирования**. Убедитесь
дополнительно, что на диске нет файловой системы и подписей:
```bash
sudo wipefs -n /dev/sdb # -n = «сухой прогон», ничего не меняет
```
Если вывод пустой — диск чист, продолжаем. Если что-то нашлось (следы старой ФС/RAID) —
**остановитесь** и разберитесь, что это, прежде чем идти дальше.
---
## 1. Создать таблицу разделов и один раздел
GPT + один раздел на весь диск:
```bash
sudo parted -s /dev/sdb mklabel gpt
sudo parted -s -a optimal /dev/sdb mkpart primary ext4 0% 100%
sudo partprobe /dev/sdb
lsblk /dev/sdb
```
Должен появиться `sdb1` размером ~700G.
---
## 2. Отформатировать в ext4
`-m 1` уменьшает резерв под root с 5% до 1% (на диске данных резерв в 35 ГБ не нужен), `-L` даёт
метку тома:
```bash
sudo mkfs.ext4 -m 1 -L telewave-media /dev/sdb1
```
---
## 3. Создать точку монтирования
```bash
sudo mkdir -p /srv/telewave/media
```
---
## 4. Прописать в /etc/fstab (монтирование по UUID)
Монтируем по UUID, а не по имени `sdb1` — имя может измениться при добавлении дисков. Узнать UUID:
```bash
sudo blkid /dev/sdb1
```
Скопируйте значение `UUID="..."` и добавьте строку в `/etc/fstab` (подставьте свой UUID):
```
UUID=ВАШ-UUID /srv/telewave/media ext4 defaults,noatime,nofail,x-systemd.device-timeout=10 0 2
```
Пояснения к опциям:
- `noatime` — не обновлять время доступа при чтении сегментов; заметно снижает лишние записи при
раздаче видео.
- `nofail` — если диск не подключился, система всё равно загрузится (приложение просто не сможет
писать, а не «висит» на загрузке).
- `x-systemd.device-timeout=10` — не ждать диск дольше 10с при старте.
Проверить, что fstab корректен, и смонтировать:
```bash
sudo systemctl daemon-reload
sudo mount -a
findmnt /srv/telewave/media
```
`findmnt` должен показать смонтированный `ext4` на `/dev/sdb1`. **Ошибка на этом шаге лучше, чем
на следующей перезагрузке** — если `mount -a` ругается, чините fstab сейчас.
---
## 5. Рабочие каталоги и права
Создать структуру, ожидаемую приложением:
```bash
sudo mkdir -p /srv/telewave/media/{inbox,uploads,originals,assets}
```
**Владелец.** Контейнер сейчас работает под `root` (в Dockerfile нет `USER`), а bind-mount
пробрасывает права хоста внутрь как есть. Поэтому достаточно оставить владельцем root:
```bash
sudo chown -R root:root /srv/telewave/media
sudo chmod -R 755 /srv/telewave/media
```
Чтобы вы могли класть файлы в `inbox/` вручную (SFTP/rsync) под своим пользователем, откройте на
запись именно этот каталог вашей группе:
```bash
sudo chown root:$(id -gn) /srv/telewave/media/inbox
sudo chmod 775 /srv/telewave/media/inbox
```
> При переходе контейнера на non-root пользователя (если позже добавим `USER` в Dockerfile —
> в aspnet-образе это обычно uid `1654`), сменить владельца на этот uid:
> `sudo chown -R 1654:1654 /srv/telewave/media` (кроме `inbox`, оставленного вам).
---
## 6. Проброс в контейнер (bind mount)
В `docker-compose.yml`, в сервис `app`, добавить том (этого пока **нет** в репозитории — появится
вместе с реализацией фичи, здесь для справки):
```yaml
services:
app:
# ... существующая конфигурация ...
volumes:
- /srv/telewave/media:/media
mem_limit: 3g
```
И переменные окружения в `.env` (см. `docs/media-storage-and-streaming.md`):
```
Storage__RootPath=/media
```
Выбран **bind mount**: диск смонтирован в ОС через fstab (шаги 1–5) и виден всегда, независимо от
Docker — это важно, потому что файлы в `inbox/` кладутся вручную по SFTP/rsync, в том числе когда
контейнер остановлен.
> **Альтернатива — named volume, монтируемый самим Docker** (не используем, для справки). Позволяет
> пропустить шаги 3–5, но диск тогда доступен только при запущенном контейнере, а подкаталоги всё
> равно надо создавать заранее. Пример:
>
> ```yaml
> services:
> app:
> volumes:
> - media:/media
> mem_limit: 3g
> volumes:
> media:
> driver: local
> driver_opts:
> type: ext4
> device: /dev/disk/by-uuid/ВАШ-UUID
> o: noatime
> ```
>
> Разметка и `mkfs.ext4` (шаги 1–2) обязательны в любом случае.
---
## 7. Проверка записи из контейнера
После добавления тома и пересборки образа убедиться, что контейнер пишет на диск:
```bash
docker compose exec app sh -c 'touch /media/.wtest && ls -l /media/.wtest && rm /media/.wtest'
```
Команда должна отработать без ошибок доступа. На этом подготовка хоста завершена — дальнейшее
(создание `MediaAsset`, нарезка ffmpeg) делает уже само приложение.
---
## Приложение: если диск нужно расширить в будущем
Если VM отдаст диску больше места (например `sdb` вырастет с 700G), после увеличения на стороне
гипервизора:
```bash
sudo growpart /dev/sdb 1 # расширить раздел на весь диск
sudo resize2fs /dev/sdb1 # расширить ext4 (можно на смонтированном)
df -h /srv/telewave/media
```