Merge remote-tracking branch 'origin/main'

This commit is contained in:
Hermes committed 2026-09-20 19:31:16 +06:00
commit d11d1effcb
6 files changed
+417 -6

No files matched your search

+78 -1
View File
@@ -241,7 +241,7 @@ curl -s -H "X-Api-Key: $PKEY" "http://localhost:9696/prowlarr/api/v1/search?quer
## Radarr Quality Profiles на Kraken (проверено 2026-09-04)
Via `http://kraken:7878/radarr/api/v3/qualityprofile` (X-Api-Key из config.xml; **UrlBase=`/radarr`**). Radarr v6.1.1.10360, Linuxserver image, net `docker_default`.
Via `http://kraken:7878/radarr/api/v3/qualityprofile` (X-Api-Key из config.xml; **UrlBase=`/radarr`**). Linuxserver image, сеть `media_net` (с 2026-09-20; ранее ошибочно жил в `docker_default`). Версия — см. таблицу актуальных версий ниже.
| id | Профиль | Разрешённые качества | Cutoff |
|----|---------|----------------------|--------|
@@ -355,6 +355,83 @@ sudo docker start prowlarr
- `POST /api/v3/indexer/test` с телом `{"indexerId":N}` → HTTP 400 (валидирует как НОВЫЙ индексер, требует Name/Implementation). Для теста всех сразу: `POST /api/v3/indexer/testall`.
- `GET /api/v1/health` в Prowlarr и `/api/v1/indexerstatus` НЕ показывают причины блокировки. Смотреть `.../docker/prowlarr/config/logs/prowlarr.debug.txt` (grep по имени индексера и `Cloudflare`/`403`).
## Обновление Radarr / Sonarr (2026-09-20)
Watchtower их не обновлял (см. [[family/how-to/kraken-watchtower]]), поэтому обновлено вручную:
**Radarr 6.1.1.10360 → 6.4.4.10685**, **Sonarr 4.0.17.2952 → 4.0.20.3014**.
```bash
# Sonarr — метаданные проекта правильные, обычный up:
cd /srv/.../docker/sonarr && sudo docker compose pull sonarr && sudo docker compose up -d sonarr
```
### ⚠️ Ловушка: Radarr принадлежал ЧУЖОМУ compose-проекту
`docker compose up -d radarr` из `docker/radarr/` падал:
`Conflict. The container name "/radarr" is already in use`.
Причина: контейнеры `radarr` и `transmission` были созданы **17.05.2026 из общего проекта `docker`** (файл `/srv/.../docker/docker-compose.yml`, **сейчас его нет — удалён**). Метаданные: `com.docker.compose.project=docker`. При этом `docker/radarr/docker-compose.yml` существовал и не использовался.
Проверка, к какому проекту принадлежит контейнер:
```bash
sudo docker inspect radarr -f '{{index .Config.Labels "com.docker.compose.project"}} {{index .Config.Labels "com.docker.compose.project.config_files"}}'
```
Фикс (**данные в `config/` не трогаются**, только контейнер):
```bash
sudo docker stop radarr && sudo docker rm radarr
cd /srv/.../docker/radarr && sudo docker compose up -d radarr
# стало: project=radarr file=.../docker/radarr/docker-compose.yml, сеть media_net
```
`transmission` остался в проекте `docker` (его compose-файл в `docker/transmission/`), но подключён к `media_net` — работает.
### Диагностические грабли (Radarr/Sonarr API)
- `POST /api/v3/indexer/test` с телом `{"indexerId":N}` → **HTTP 400** (валидирует как НОВЫЙ индексер, требует Name/Implementation/AppProfileId). Использовать **`POST /api/v3/indexer/testall`**.
- То же для клиентов: **`POST /api/v3/downloadclient/testall`**.
- Триггер `UrlBase`: Radarr `/radarr/api/v3/...`, Sonarr `/sonarr/api/v3/...`.
### Итоговое состояние compose-проектов и сетей (2026-09-20)
После всех правок важно, потому что **`docker compose up -d` надо запускать из своего каталога**, иначе будет конфликт имени контейнера.
| Контейнер | Compose-проект | Файл | Сеть |
|---|---|---|---|
| radarr | `radarr` ✅ | `docker/radarr/docker-compose.yml` | `media_net` |
| sonarr | `sonarr` ✅ | `docker/sonarr/docker-compose.yml` | `media_net` |
| prowlarr | `prowlarr` ✅ | `docker/prowlarr/docker-compose.yml` | `media_net` |
| flaresolverr | (в том же файле prowlarr) | `docker/prowlarr/docker-compose.yml` | `media_net` |
| transmission | `transmission` ✅ | `docker/transmission/docker-compose.yml` | `media_net` |
| watchtower | `watchtower` | `docker/watchtower/docker-compose.yml` | — |
✅ **`transmission` тоже исправлен (2026-09-20, позже в той же сессии).** Был в проекте `docker`, пересоздан так же: `stop` → `rm` → `up -d` из `docker/transmission/`. Данные **не пострадали**: 244 торрента в `./torrents/` + 244 resume-файла на месте, RPC вернул `torrents: 244`. Проверка перед пересозданием обязательна — считать торренты ДО и ПОСЛЕ:
```bash
sudo ls $D/transmission/torrents/ | wc -l # до и после должно совпасть
```
**Общее правило:** если `docker compose up -d` даёт `Conflict. The container name "/X" is already in use` — контейнер принадлежит чужому (возможно, удалённому) compose-проекту. Смотреть `com.docker.compose.project` и `project.config_files`, затем `stop` → `rm` → `up -d` из правильного каталога. Данные в bind-mount (`config/`, `torrents/`) при этом не трогаются.
Проверка принадлежности любого контейнера:
```bash
sudo docker inspect <name> -f '{{index .Config.Labels "com.docker.compose.project"}} {{index .Config.Labels "com.docker.compose.project.config_files"}}'
```
### Версии после обновления (2026-09-20)
| Сервис | Версия |
|---|---|
| Radarr | **6.4.4.10685** |
| Sonarr | **4.0.20.3014** |
| Prowlarr | **2.6.5.5623** |
| FlareSolverr | 3.5.2 |
| Watchtower | **1.22.2** (`nickfedor/watchtower`, см. [[family/how-to/kraken-watchtower]]) |
Автообновлением занимается Watchtower — **проверить его конфиг перед тем, как ждать обновлений**: [[family/how-to/kraken-watchtower]], теория — [[personal/tech/watchtower-docker-updates]].
## Автообновление (Watchtower) — 2026-09-20
Все сервисы стека (`radarr`, `sonarr`, `prowlarr`, `flaresolverr`, `transmission`) **плюс `jellyfin` и `portainer`** размечены label `com.centurylinklabs.watchtower.enable=true` → обновляются автоматически (7 контейнеров, проверено `scanned=7`). Полный разбор и список того, что НЕ обновляется: [[family/how-to/kraken-watchtower]]. Теория: [[personal/tech/watchtower-docker-updates]].
## Notes
- See [[arr-stack-taiga]] for Taiga (secondary) arr stack
+169
View File
@@ -0,0 +1,169 @@
---
updated: '2026-09-20'
title: Watchtower — Kraken
created: '2026-09-20'
type: tech
namespace: family
tags:
- watchtower
- docker
- updates
- infra
- kraken
related:
- '[[family/how-to/arr-stack-kraken]]'
- '[[personal/tech/watchtower-docker-updates]]'
- '[[personal/tech/jellyfin-db-schema-mismatch]]'
- '[[personal/tech/docker-data-root-mount-race]]'
---
# Watchtower на Kraken (RPi5 / OMV / arm64)
> **Создано:** 2026-09-20. **Статус:** ✅ ЗАВЕРШЕНО — версия 1.22.2 (форк nickfedor), label проставлены на 7 контейнеров, проверено прогоном `scanned=7 failed=0`.
> **Связанные:** [[family/how-to/arr-stack-kraken]], [[personal/tech/watchtower-docker-updates]] (реюзабельная теория), [[personal/tech/jellyfin-db-schema-mismatch]], [[personal/tech/docker-data-root-mount-race]]
## ✅ РЕШЕНИЕ (2026-09-20): какие контейнеры обновляются автоматом
Решение Alex: «вариант 1 + jellyfin, portainer, transmission». Итого **7 контейнеров размечены** label `com.centurylinklabs.watchtower.enable=true`:
| Контейнер | Где label | Примечание |
|---|---|---|
| `radarr` | `docker/radarr/docker-compose.yml` | |
| `sonarr` | `docker/sonarr/docker-compose.yml` | |
| `prowlarr` | `docker/prowlarr/docker-compose.yml` | |
| `flaresolverr` | `docker/prowlarr/docker-compose.yml` | тот же файл |
| `jellyfin` | `docker/jellyfin/docker-compose.yml` | ⚠️ тег `latest` — см. ниже |
| `portainer` | `docker/portainer/docker-compose.yml` | данные в `/data`, пересоздание безопасно |
| `transmission` | `docker/transmission/docker-compose.yml` | 244 торрента в `./` (config), пересоздание данные не задело |
**НЕ размечены (сознательно):**
- `watchtower` — сам себя (иначе зацикливание)
- `hermes-kraken` — агент Hermes
- `xray-reverse-bridge` — VPN-мост
- `rclone`, `cloudflared`
Проверка после простановки:
```bash
sudo docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
nickfedor/watchtower:1.22.2 --run-once --monitor-only --label-enable
# → Update session completed failed=0 scanned=7 updated=0 ← ровно 7, не 13
```
### Про Jellyfin и тег (решение Alex)
Алекс явно потребовал: **«пусть ставит до всех публичных релизов»** → стоит `image: jellyfin/jellyfin:latest`, Watchtower поставит в т.ч. мажор 13.
Моя рекомендация была пинить `12` (после инцидента `jellyfin-db-schema-mismatch`, где контейнер остался на старом образе при уже мигрированной БД и отдавал 503). **Алекс выбрал `latest` — риск принят осознанно.** Если Jellyfin однажды отдаст 503 после автообновления — смотреть [[personal/tech/jellyfin-db-schema-mismatch]], бэкап БД: `/home/kraken/backups/jellyfin-label-20260920-190935/`.
⚠️ Важное следствие `--cleanup`: старые образы удаляются, откатиться на предыдущую версию после автообновления будет **некуда**.
## Что было сломано (2026-09-20)
Watchtower стоял на `containrrr/watchtower` **без единого флага** и **не обновил ни один контейнер за ~2.5 месяца**.
Четыре независимые причины:
| # | Причина | Как выглядело в логе |
|---|---|---|
| 1 | Не задан `--interval` | `Scheduling first run: ... in 23 hours 59 minutes` — каждый рестарт контейнера сбрасывал таймер, а рестарты были |
| 2 | `DOCKER_API_VERSION=1.40` (старый API) | `Unable to update container "/prowlarr": no available image info` |
| 3 | Образ `containrrr/watchtower` мёртв | last push **2023-11-11** (проверено через Docker Hub API) |
| 4 | Нет label на целевых контейнерах | `Scanned=12 Updated=0` |
Итог до фикса: `Session done Failed=0 Scanned=12 Updated=0`, а единственная попытка обновления упала с `no available image info`.
## Фикс (ВЫПОЛНЕН 2026-09-20)
`containrrr/watchtower` → **`nickfedor/watchtower:1.22.2`** (активный форк; у containrrr последний push 2023-11-11).
```bash
D=/srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f/docker/watchtower
sudo cp $D/docker-compose.yml /home/kraken/arr-fix-backup-20260920/watchtower-compose.bak
cd $D && sudo docker compose pull watchtower && sudo docker compose up -d watchtower
```
Compose (`docker/watchtower/docker-compose.yml`):
```yaml
services:
watchtower:
image: nickfedor/watchtower:1.22.2
container_name: watchtower
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 86400 --cleanup --label-enable
# DOCKER_API_VERSION=1.40 УДАЛЁН — именно он ломал обновление
```
Флаги:
- `--interval 86400` — явные 24ч (без флага таймер сбрасывался каждым стартом)
- `--cleanup` — удалять старые образы (диск на 87%, иначе забьёт)
- `--label-enable` — обновлять ТОЛЬКО контейнеры с label `com.centurylinklabs.watchtower.enable=true`
## Проверка (обязательна — «запущено» ≠ «работает»)
```bash
# 1) версия и API
sudo docker logs --tail 20 watchtower
# → Watchtower 1.22.2 using Docker API v1.54 (был v1.40)
# → Next scheduled run: ... in 23 hours 59 minutes ← таймер виДЕН
# 2) РЕАЛЬНЫЙ прогон без изменений — БЕЗ label (сравнение)
sudo docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
nickfedor/watchtower:1.22.2 --run-once --monitor-only
# → Update session completed failed=0 scanned=13 updated=0
# → "Found new image" container=transmission ← баг no-available-image-info ВЫЛЕЧЕН
# 3) С label (актуальный режим) → должно быть ровно 7
sudo docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
nickfedor/watchtower:1.22.2 --run-once --monitor-only --label-enable
# → Update session completed failed=0 scanned=7 updated=0
```
## ⚠️ КРИТИЧНО: Watchtower и Jellyfin — история и принятое решение
**Watchtower уже один раз сломал Jellyfin** (см. [[personal/tech/jellyfin-db-schema-mismatch]]): контейнер остался на старом образе 10.11.8 при уже мигрированной до 12.1 БД → `no such column: p.Permission_Permissions_Guid` → 503.
Разбор инцидента показывает: **сама миграция БД прошла нормально**, упало из-за рассинхрона «старый сервер + новая схема». То есть мажорный апдейт сам по себе БД не ломает.
**Решение Alex (2026-09-20):** тег `latest`, обновляемся до всех публичных релизов, включая мажор 13. Риск принят осознанно. Бэкап БД перед пересозданием: `/home/kraken/backups/jellyfin-label-20260920-190935/` (24 МБ).
**Если Jellyfin отдаёт 503 после автообновления** — это тот же класс проблемы: смотреть `personal/tech/jellyfin-db-schema-mismatch`, проверить `docker exec jellyfin /jellyfin/jellyfin --version` против версии в `__EFMigrationsHistory`.
⚠️ Следствие `--cleanup`: старые образы удаляются, откат на предыдущую версию **после** автообновления невозможен. Если нужен откат — только полный restore БД из бэкапа.
## Диагностика Watchtower
```bash
sudo docker ps --format "{{.Names}}\t{{.Image}}\t{{.Status}}" | grep watchtower
sudo docker logs --tail 40 watchtower
# кто помечен для автообновления:
for c in $(sudo docker ps --format "{{.Names}}"); do
echo "$c -> $(sudo docker inspect $c -f '{{index .Config.Labels "com.centurylinklabs.watchtower.enable"}}')"
done
```
Грабли:
- `Unable to update container: no available image info` — старый `DOCKER_API_VERSION`, либо несовместимость containrrr-версии с новым dockerd.
- **Рестарт контейнера сбрасывает таймер** — без `--interval` это делает Watchtower бесполезным.
- `--run-once` **нельзя** запускать без `--monitor-only`, если не хочешь реальных обновлений.
- Watchtower пишет в stdout (`docker logs`), в отличие от Jellyfin.
## Бэкап
`/home/kraken/arr-fix-backup-20260920/watchtower-compose.bak` + остальные бэкапы в той же папке:
- `radarr-config-preupgrade.tar.gz` (58M), `sonarr-config-preupgrade.tar.gz` (20M), `prowlarr-config-preupgrade.tar.gz` (3.9M)
- `prowlarr.db.bak`, `watchtower-compose.bak`, `networks.txt`, 4× `<container>-inspect.json`, 3× compose-файла
## Что дальше (открытые пункты)
| # | Пункт | Статус |
|---|---|---|
| 1 | `Allowed Hosts is not configured` warning в Radarr/Sonarr/Prowlarr — ограничить, какие hostname могут обращаться | ⏳ отдельная задача |
| 2 | Home Assistant на Kraken — `Exited (128)` ~2 месяца, не поднимался (см. [[family/how-to/kraken-access]]) | ⏳ отдельная задача |
✅ Закрыто 2026-09-20: label проставлены, решение по Jellyfin принято (`latest`), первый прогон с label прошёл (`scanned=7 failed=0`).
## Теория (реюзабельно)
Общие причины «Watchtower не обновляет» без привязки к Kraken — [[personal/tech/watchtower-docker-updates]].
+1 -1
View File
@@ -272,7 +272,7 @@ cd /home/kraken/<name> && sudo docker compose restart # рестарт
cd /home/kraken/<name> && sudo docker compose pull && sudo docker compose up -d # обновить
```
> ⚠️ Watchtower: нужна переменная `DOCKER_API_VERSION=1.54` — иначе крашится (API mismatch)
> ⚠️ Watchtower: `DOCKER_API_VERSION` **убирать** (2026-09-20). Ранее здесь стояло `DOCKER_API_VERSION=1.40`, и именно он вместе с «no available image info» ломал обновление. Пиннинг версии API вообще не нужен — новая версия Watchtower сама согласует её с dockerd (`using Docker API v1.54`). Полный разбор: [[family/how-to/kraken-watchtower]], теория — [[personal/tech/watchtower-docker-updates]].
> ⚠️ sudo через SSH требует `< /dev/null` для каждой команды с tee/pipe
---
+31 -4
View File
@@ -1,7 +1,7 @@
---
created: '2026-05-20'
updated: '2026-09-04'
status: active
updated: '2026-09-20'
status: broken
tags:
- kraken
- watchlist
@@ -62,14 +62,39 @@ Jellyfin (8096) → rescan → виден контент
**Важно:** `process_thumbs` автоматически определяет отступ из `## Фильмы` и сохраняет при переносе. `SECTION_THUMBDN = "## Новинки👎"` (без пробела) — должно точно совпадать с заголовком.
## 🔴 Pipeline МЁРТВ с 2026-06-20 (аудит 2026-09-20)
**Автодобавление фильмов НЕ работает.** Скрипты живы, но их никто не запускает.
Доказательства (проверено 2026-09-20):
- `crontab -l` юзера `kraken` — watchlist-строк **НЕТ**. Есть только `sync-vault.sh` (каждый час) и два `pgs-to-srt` (часовой + 03:00).
- root crontab и `/etc/cron.d/`: `grep -rl watchlist` → пусто.
- systemd timers (user + system) → 0 штук.
- Внутри Hermes-контейнера на Кракене: `docker exec hermes-kraken /opt/hermes/.venv/bin/hermes cron list` → **"No scheduled jobs."**
- Последний коммит автором `Hermes` (= nightly-скрипт) — **2026-06-20**. Распределение по месяцам: май 1, июнь 9, июль/август/сентябрь — **0**. Единственные коммиты в vault после июня — от `eagle`, `syncthing`, `taiga`.
Скрипты существуют и исполняемы, но не в кроне:
```
~/scripts/watchlist-nightly.sh mtime 2026-05-29
~/scripts/watchlist-discover.sh mtime 2026-05-29
```
**Побочный эффект — файл засран `❓`-мусором.** Так как `resolve --recheck` не бегает, ambiguous-строки копят дампы кандидатов: «Крестный отец» ×4 блока по 6 строк, «Nightmare Alley» ×31 строка, «Stand by me» ×40 строк, «Фарго» ×30. Секции `👍/👎` не обрабатываются — 40+ позиций висят в «Новинки», не переехав в основной список.
Аудит завершён без изменений на Кракане — ничего не трогалось. Три варианта для Alex: (1) восстановить крон, (2) сначала почистить `❓`-мусор, (3) оставить как есть.
## Cron Jobs (на Кракене с 2026-05-27)
Весь watchlist pipeline работает на Кракене (мигрировал с Eagle 2026-05-27).
| Job | Расписание | Скрипт |
|-----|-----------|--------|
| `watchlist-nightly` | ежедн. 01:00 | `~/.hermes/scripts/watchlist-nightly.sh` |
| `watchlist-discover` | вс 09:00 | `~/.hermes/scripts/watchlist-discover.sh` |
| `watchlist-nightly` | ежедн. 01:00 | `~/scripts/watchlist-nightly.sh` |
| `watchlist-discover` | вс 09:00 | `~/scripts/watchlist-discover.sh` |
⚠️ Фактический путь — `~/scripts/`, **не** `~/.hermes/scripts/` (в доке ранее было ошибочно). Оба скрипта вызывают CLI напрямую через `uv run --project $WS`, без LLM. `uv` лежит в `~/.local/bin/uv`.
`WS` в обоих скриптах: `/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/watchlist-sync` — **другой UUID**, чем фактический корень репо (см. ниже). Возможный источник поломки: проверить, что путь резолвится.
**watchlist-nightly.sh** (на Кракене):
1. `sync-vault.sh` (pull) → `process-thumbs --apply` → `sync-vault.sh` (push)
@@ -146,7 +171,9 @@ Jellyfin library mapping: Movies → `movies`, Cartoons → `mixed` (movies + ep
## Open Tasks
- 🔴 **[2026-09-20] Восстановить cron для watchlist pipeline** — pipeline мёртв с 20 июня (см. раздел выше). Решение за Alex: восстановить крон / сначала почистить `❓`-мусор / оставить как есть.
- 🔴 **[2026-09-04] Решить стратегию качества загрузки новых фильмов** (см. профили в [[arr-stack-kraken]]). Корень — захардкоженный `qualityProfileId: 1` (`Any`) в `watchlist_sync/arr.py`. Пока НЕ менялось (НИЧЕГО не правилось, ждём решение Alex). Вопрос юзеру: сохранить 4K (→ создать профиль «2160p без Remux/BR-DISK» и сменить id в arr.py) или опустить до 1080p (id 4); и менять ли и для Sonarr (сериалы) тоже.
- 🟡 Почистить `❓`-мусор в movies-watchlist.md (повторяющиеся дампы кандидатов после многомесячного простоя)
- 🟡 Передавать Transmission locations через router script при каждом импорте (сейчас вручную)
- 🔴 rsync невыполненных фильмов с HTPC на Кракен (`Фильмы не перенесенные с htpc на кракен.md`)
- 🟡 Watchlist sync-up: добавить перенесённые фильмы в нужные разделы
@@ -95,6 +95,8 @@ ssh kraken 'docker ps -q | wc -l' # ожидаем ~12, НЕ 0
> ⚠️ **Не путать с другим дефектом:** после этого reboot `jellyfin` поднялся, но отдавал **503** — это **отдельная** проблема (сервер старше БД, `no such column: p.Permission_Permissions_Guid`), НЕ связанная с гонкой монтирования. См. [[personal/tech/jellyfin-db-schema-mismatch]]. При диагностике «сервис не работает после reboot» различать: контейнер не поднялся (гонка) vs поднялся, но падает внутри (своя ошибка приложения).
> ℹ️ **Обновление 2026-09-20 (позже в тот же день):** `radarr` был **пересоздан** (переведён из общего проекта `docker` в свой `docker/radarr`, обновлён до 6.4.4) — см. [[family/how-to/arr-stack-kraken]]. `watchtower` сменил образ на `nickfedor/watchtower:1.22.2` — см. [[family/how-to/kraken-watchtower]]. Число контейнеров и их состав могли измениться; проверка `docker ps -q | wc -l` по-прежнему корректна как индикатор гонки, но ожидаемое число сверять заново.
## Крон не догоняет пропущенное окно
Общий питфолл для сервисов на этом узле: если Kraken лежал, cron-задачи (бэкап `0 4 * * *`, t610-подобные) **пропускаются без компенсации**. Для критичных — добавлять `@reboot`-строку с проверкой «артефакт за сегодня уже есть?».
+136
View File
@@ -0,0 +1,136 @@
---
title: Watchtower — почему не обновляет контейнеры
created: '2026-09-20'
updated: '2026-09-20'
type: tech
namespace: personal
tags: [watchtower, docker, updates, infra, pitfall]
related:
- "[[family/how-to/kraken-watchtower]]"
- "[[personal/tech/docker-data-root-mount-race]]"
- "[[personal/tech/jellyfin-db-schema-mismatch]]"
---
# Watchtower — почему не обновляет контейнеры
Реюзабельная теория. Живой разбор на Kraken — в [[family/how-to/kraken-watchtower]].
**Главный вывод: `docker ps` показывает `Up (healthy)` — это ничего не говорит о том, что Watchtower хоть раз что-то обновил.** Отсутствие обновлений не даёт ни ошибки, ни алерта. На Kraken Watchtower «работал» 2.5 месяца и не обновил ни один из 12 контейнеров.
## Четыре причины (проверять в этом порядке)
### 1. Не задан `--interval` → таймер сбрасывается каждым стартом
Без флага интервал = 24ч **от момента старта процесса**. Любой рестарт контейнера (reboot, `docker restart`, обновление самого Watchtower) обнуляет отсчёт. Если контейнер рестартуют чаще раза в сутки — **проверка не наступает никогда**.
Признак в логе:
```
level=info msg="Scheduling first run: ... in 23 hours, 59 minutes, 59 seconds"
level=info msg="Waiting for running update to be finished..."
```
Вторая строка — процесс проснулся, увидел незавершённый апдейт и **снова уснул**. Признак, что цикл заклинило.
**Фикс:** `--interval 86400` явно, либо `--schedule "0 0 4 * * *"` (cron-синтаксис из 6 полей), если нужен запуск в тихое время.
### 2. `DOCKER_API_VERSION` запинен на старую версию
`DOCKER_API_VERSION=1.40` в environment **ломает** чтение метаданных образа. Симптом:
```
level=info msg="Found new lscr.io/linuxserver/prowlarr:latest image (3e9bd62ca90c)"
level=info msg="Unable to update container \"/prowlarr\": no available image info. Proceeding to next."
```
Watchtower **нашёл** новый образ, но не может обновиться. В новых версиях API показывается сам: `using Docker API v1.54`.
**Фикс:** убрать `DOCKER_API_VERSION` из environment вообще. Watchtower сам согласует версию с dockerd.
### 3. Образ `containrrr/watchtower` не развивается
Last push `containrrr/watchtower` — **2023-11-11** (проверено Docker Hub API). Он несовместим с современным dockerd, отсюда и `no available image info` — это не только про API-версию.
**Фикс:** активный форк `nickfedor/watchtower` (актуальная версия 1.22.2, теги `latest`, `nightly`, semver).
```bash
# проверить дату образа
curl -s "https://hub.docker.com/v2/repositories/containrrr/watchtower/tags?page_size=5" \
| jq -r '.results[] | "\(.name) updated=\(.last_updated)"'
# проверить поддержку своей архитектуры (например arm64 для RPi)
curl -s "https://hub.docker.com/v2/repositories/nickfedor/watchtower/tags/1.22.2" \
| jq -r '.images[] | "\(.architecture) \(.os)"'
```
### 4. `--label-enable` без единого label → не обновит НИЧЕГО
С флагом `--label-enable` Watchtower трогает только контейнеры с label
`com.centurylinklabs.watchtower.enable=true`. Если label нет ни у кого — **сам по себе флаг делает Watchtower бесполезным**.
Проверка, кто помечен:
```bash
for c in $(docker ps --format "{{.Names}}"); do
echo "$c -> $(docker inspect $c -f '{{index .Config.Labels "com.centurylinklabs.watchtower.enable"}}')"
done
```
⚠️ `docker inspect` на контейнере без label вернёт **пустую строку**, а не «false» — не путать с `false` (явное отключение).
## Рабочий конфиг
```yaml
services:
watchtower:
image: nickfedor/watchtower:1.22.2
container_name: watchtower
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 86400 --cleanup --label-enable
# НЕ добавлять DOCKER_API_VERSION
```
- `--interval 86400` — сутки, видно в логе рядом со `Next scheduled run`
- `--cleanup` — удалять старые образы; без него диск забивается (на Kraken 87%)
- `--label-enable` — оптин: обновляется только то, что явно помечено
## Проверка (обязательна)
`Up` + отсутствие ошибок ≠ работа. Нужен живой прогон:
```bash
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
nickfedor/watchtower:1.22.2 --run-once --monitor-only
```
`--monitor-only` обязателен, иначе `--run-once` **реально обновит** контейнеры.
Что должно быть в выводе:
```
level=info msg="Watchtower 1.22.2 using Docker API v1.54"
level=info msg="Found new image" container=<X> new_id=<...>
level=info msg="Update session completed" failed=0 scanned=N skipped=0 updated=0
```
`Found new image` = баг с метаданными вылечен. `updated=0` в monitor-only — нормально.
## ⚠️ Автообновление может сломать сервис: пинить мажор версии
Тип `latest` + автообновление = переход на новую **мажорную** версию без предупреждения. Для сервисов с миграциями БД (EF Core, Prisma, любые forward-only миграции) это необратимо:
- Jellyfin на Kraken: `latest` уехал 10.11.8 → 12.1, БД мигрировала вперёд, откатить схему нельзя → сервер отдавал **503**, `no such column: ...`. Детали: [[personal/tech/jellyfin-db-schema-mismatch]].
**Правило (общее):** сервисам с forward-only миграциями БД безопаснее пиновый тег (`image: jellyfin/jellyfin:12.1`), а не `latest` + автообновление.
⚠️ **Но это рекомендация, не аксиома — на Kraken решено иначе.** Alex 2026-09-20 явно выбрал `latest` для Jellyfin: «пусть ставит до всех публичных релизов», т.е. включая мажор 13. Риск принят осознанно, бэкап БД делается перед пересозданием. См. [[family/how-to/kraken-watchtower]] § «Про Jellyfin и тег».
Отдельно важный нюанс: **упал не мажорный апдейт как таковой**, а рассинхрон «контейнер на старом образе + уже мигрированная БД». Сама миграция прошла нормально. То есть мажорный апдейт БД не ломает — ломает откат сервера назад без отката схемы.
## Питфоллы диагностики
- `docker logs watchtower` — Watchtower пишет в **stdout**, в отличие от Jellyfin (тот пишет в файл). Смотреть логи легко.
- Таймстемпы в логе Watchtower — **UTC**, локальное время сервиса может быть другим.
- Единожды увиденный `Found new image` не значит, что обновление применилось — нужна следующая строка (`Unable to update` / `Updated`).
- Проверять надо **фактическую** дату запущенного образа, а не тег:
```bash
docker inspect <container> -f '{{index .Config.Labels "org.opencontainers.image.version"}}'
docker inspect <container> -f '{{index .Config.Labels "build_version"}}'
```
## Урок
Watchtower — компонент, который **молча не работает**. Его нельзя «поставить и забыть»: обязательны (а) явный `--interval`, (б) отсутствие `DOCKER_API_VERSION`, (в) периодический `--run-once --monitor-only` как health-check, (г) осознанное решение, каким контейнерам вообще разрешено автообновление.
## Связанные
- [[family/how-to/kraken-watchtower]] — живой разбор и точные команды на Kraken
- [[personal/tech/jellyfin-db-schema-mismatch]] — что ломает автообновление мажора
- [[personal/tech/docker-data-root-mount-race]] — другой дефект «контейнеры пропали»