--- 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= 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 -f '{{index .Config.Labels "org.opencontainers.image.version"}}' docker inspect -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]] — другой дефект «контейнеры пропали»