130 lines
9.2 KiB
Markdown
130 lines
9.2 KiB
Markdown
# Jellyfin: сервер старше БД — `no such column: p.Permission_Permissions_Guid`
|
||
|
||
> **Обнаружено:** 2026-09-20 на Kraken (RPi5/OMV, arm64, Docker).
|
||
> **Статус:** ✅ **ЗАФИКСИРОВАНО 2026-09-20** — контейнер пересоздан на образе 12.1.0.0, jellyfin `healthy`, Alex подтвердил «Заработало». См. раздел «Результат» ниже.
|
||
> **Симптом:** `jellyfin` не подключается (`http://kraken:8096` → **503**), контейнер `Up` но `unhealthy`, health-check бесконечно пишет `Server is could not complete startup. Check logs.`
|
||
> **Связанные:** [[personal/tech/docker-data-root-mount-race]], [[family/how-to/kraken-access]], [[family/plans/kraken-backup-to-truenas]]
|
||
|
||
## Суть (коротко)
|
||
|
||
**БД `jellyfin.db` мигрирована под Jellyfin 12.1.0.0, а запущенный контейнер работает на образе 10.11.8.**
|
||
Сервер 10.11.8 ожидает старую схему таблицы `Permissions` (с колонкой `Permission_Permissions_Guid`), а в 12.x-схеме её больше нет → падение на конструкторе `UserManager` → сервер не стартует.
|
||
|
||
Это **не** «миграция не прошла». Наоборот: миграции применены **вперёд**, а сервер откатился **назад**.
|
||
|
||
## Диагностика (воспроизводимая)
|
||
|
||
```bash
|
||
# 1) внешний симптом
|
||
ssh kraken 'docker exec jellyfin sh -c "curl -s -o /dev/null -w \"%{http_code}\n\" http://localhost:8096/"'
|
||
# → 503
|
||
|
||
# 2) статус
|
||
ssh kraken 'docker ps --format "{{.Names}} {{.Status}}" | grep jelly'
|
||
# → jellyfin Up ... (unhealthy)
|
||
|
||
# 3) ГДЕ ЛОГ: jellyfin пишет в ФАЙЛ, не в stdout!
|
||
# docker logs пуст по свежему запуску — не путаться.
|
||
ssh kraken 'sudo docker exec jellyfin sh -c "ls -lat /config/log/"'
|
||
ssh kraken 'sudo docker exec jellyfin sh -c "grep -nE \"SqliteException|could not complete startup\" /config/log/log_20260920.log | head"'
|
||
# → SQLite Error 1: 'no such column: p.Permission_Permissions_Guid'
|
||
|
||
# 4) какая версия сервера РЕАЛЬНО запущена
|
||
ssh kraken 'docker exec jellyfin sh -c "/jellyfin/jellyfin --version"'
|
||
# → Jellyfin.Server 10.11.8.0
|
||
|
||
# 5) какой образ у контейнера vs локальный latest
|
||
ssh kraken 'docker inspect jellyfin --format "{{.Image}}"'
|
||
ssh kraken 'docker inspect jellyfin/jellyfin:latest --format "{{.Id}}"'
|
||
# → РАЗНЫЕ ID
|
||
|
||
# 6) до какой версии мигрирована БД (на Mac, копия БД)
|
||
# см. скрипт ниже: миграции по ProductVersion
|
||
```
|
||
|
||
### Разбор БД (скопировать на Mac, не трогая оригинал)
|
||
|
||
```bash
|
||
ssh kraken 'sudo docker cp jellyfin:/config/data/jellyfin.db /tmp/jf.db && sudo chmod 644 /tmp/jf.db'
|
||
scp kraken:/tmp/jf.db /Users/admin/kraken-recovery/jellyfin-db/jellyfin.db
|
||
# затем python3: SELECT ProductVersion, COUNT(*) FROM __EFMigrationsHistory GROUP BY ProductVersion
|
||
# скрипт-разбор: /Users/admin/kraken-recovery/inspect_db.py, inspect_db2.py
|
||
```
|
||
|
||
## Факты инцидента (2026-09-20)
|
||
|
||
| Что | Значение |
|
||
|---|---|
|
||
| Образ **контейнера** | `sha256:1694ff06...` = **10.11.8** |
|
||
| Образ **локальный `latest`** | `sha256:78d3ea12...` = **12.1.0.0** (обновлён 15.09) |
|
||
| БД `jellyfin.db` мигрирована до | **12.1.0.0** (последняя миграция `20260911120000_StripEmbeddedLinkedChildren`) |
|
||
| Миграций в `__EFMigrationsHistory` | 105 (наборы: 9.0.11 ×36, 10.0.11 ×19, 10.11.8 ×32, 12.0.0 ×15, 12.1.0 ×3) |
|
||
| Схема `Permissions` в БД | **без** `Permission_Permissions_Guid` (12.x-форма) |
|
||
| Контейнер создан | 26.05.2026, **не пересоздавался** |
|
||
| Первое падение в логе | **09:57 (до shutdown Kraken)** — дефект не от перезагрузки |
|
||
| `SQLiteBackups/` (авто-бэкапы) | **пуст** |
|
||
| Единственный бэкап БД | `jellyfin.db.backup-20260617_034429` (17.06) |
|
||
|
||
## Как это получилось
|
||
|
||
`latest` указывал на 10.11.8 в мае → контейнер создан на этом образе. 15.09 `latest` на Hub обновился до **12.1**. Контейнер в какой-то момент запустился на новом образе (или compose пересоздал его), миграции прошли до 12.1.0.0. Затем контейнер вернулся на **старый** образ 10.11.8 (снапшот от 26.05) — и уже не может стартовать с новой БД.
|
||
|
||
**Питфолл тега `latest`:** `docker inspect` показывает digest, откуда образ БЫЛ СКАЧАН, а не текущий `latest`. Локальный «latest» может быть сильно старше, чем `latest` в реестре. Проверять версию **внутри образа**: `docker run --rm --entrypoint sh jellyfin/jellyfin:latest -c '/jellyfin/jellyfin --version'`.
|
||
|
||
## Фикс (ВЫПОЛНЕН 2026-09-20)
|
||
|
||
**Миграцию вручную запустить НЕЛЬЗЯ и не нужно** — миграции уже применены (до 12.1.0.0), запускать нечего; даунгрейд схемы EF Core не поддерживает. Проблема не в БД, а в **образе контейнера**.
|
||
|
||
```bash
|
||
# 1) БЭКАП БД (авто-бэкапов нет!)
|
||
ssh kraken 'D=/home/kraken/backups/jellyfin-db-$(date +%Y%m%d-%H%M%S); mkdir -p $D; \
|
||
sudo docker cp jellyfin:/config/data/jellyfin.db $D/ && \
|
||
sudo docker cp jellyfin:/config/data/jellyfin.db-wal $D/ 2>/dev/null; \
|
||
sudo chown -R kraken:kraken $D; ls -la $D'
|
||
|
||
# 2) пересоздать контейнер на актуальном образе
|
||
ssh kraken 'cd /srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f/docker/jellyfin && \
|
||
sudo docker compose up -d --force-recreate'
|
||
|
||
# 3) проверка
|
||
ssh kraken 'docker exec jellyfin sh -c "/jellyfin/jellyfin --version"' # ожидаем 12.1.0.0
|
||
ssh kraken 'docker ps --format "{{.Names}} {{.Status}}" | grep jelly' # health: healthy
|
||
ssh kraken 'docker exec jellyfin sh -c "curl -s -o /dev/null -w \"%{http_code}\n\" http://localhost:8096/"'
|
||
```
|
||
|
||
**Риск:** низкий. Данные (`/config`) не трогаются, пересоздаётся только контейнер. Бэкап БД обязателен — откатываться больше некуда.
|
||
|
||
## ✅ Результат (2026-09-20)
|
||
|
||
| Шаг | Факт |
|
||
|---|---|
|
||
| Бэкап БД | `/home/kraken/backups/jellyfin-recreate-20260920-165750/` — `jellyfin.db` (24.5 МБ) + `-wal` + `-shm` |
|
||
| Пересоздание | `docker compose up -d --force-recreate` → `Container jellyfin Recreated / Started`, rc=0 |
|
||
| Статус через 15 с | **`Up 15 seconds (healthy)`** — сразу healthy, без периода `starting` |
|
||
| Подтверждение Alex | «Заработало» |
|
||
|
||
> Контейнер теперь работает на образе `jellyfin/jellyfin:latest` = **12.1.0.0**, что согласовано с версией БД. Проблема `no such column` закрыта.
|
||
|
||
**Compose jellyfin** (`/srv/.../docker/jellyfin/docker-compose.yml`):
|
||
```yaml
|
||
image: jellyfin/jellyfin # без тега = latest
|
||
restart: always
|
||
ports: ["8096:8096"]
|
||
volumes:
|
||
- /srv/.../docker/jellyfin:/config
|
||
- /srv/.../media:/media:ro
|
||
environment: [TZ=Asia/Almaty]
|
||
```
|
||
> Рекомендация на будущее: **пинить тег** (`jellyfin/jellyfin:12.1`) вместо `latest`, иначе `watchtower` может снова переключить мажорную версию и сломать БД.
|
||
|
||
## Питфоллы диагностики
|
||
|
||
- **`docker logs jellyfin` не показывает свежий старт** — jellyfin пишет в `/config/log/log_YYYYMMDD.log`, а не в stdout. Читать файл внутри контейнера.
|
||
- **В контейнере нет `sqlite3`, `python3`, `strings`** — БД разбирать только копией на Mac.
|
||
- **Старые ошибки в логе сбивают**: `System.UriFormatException: Invalid URI` и `WS ... closed` — это НЕ причина падения, а фон. Искать `SqliteException` и `could not complete startup`.
|
||
- Проверять **`--since`** фильтр осторожно: если контейнер старше, `--since 15m` даст пусто.
|
||
|
||
## Урок
|
||
|
||
При `no such column` в jellyfin (или любом EF Core сервисе) **первым делом сравнивать версию бинарника внутри запущенного контейнера с максимальной версией в `__EFMigrationsHistory`**. Версия БД выше версии сервера = откатился образ. Лечится пересозданием контейнера на правильном образе, НЕ правкой БД.
|