263 lines
17 KiB
Markdown
Executable File
263 lines
17 KiB
Markdown
Executable File
---
|
||
updated: '2026-09-27'
|
||
title: Watchtower — Kraken
|
||
created: '2026-09-20'
|
||
type: tech
|
||
namespace: family
|
||
tags:
|
||
- watchtower
|
||
- docker
|
||
- updates
|
||
- infra
|
||
- kraken
|
||
- pitfall
|
||
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]]'
|
||
- '[[personal/tech/kraken-docker-startup-order]]'
|
||
---
|
||
# Watchtower на Kraken (RPi5 / OMV / arm64)
|
||
|
||
> **Создано:** 2026-09-20. **Обновлено:** 2026-09-27.
|
||
> 🟡 **Статус 2026-09-27:** фикс 2026-09-20 **не был применён** (контейнер не пересоздан,
|
||
> крутился `containrrr/watchtower` без флагов). **Пересоздан 2026-09-27** на `nickfedor/watchtower:1.22.2`
|
||
> + критичные контейнеры исключены меткой `enable=false`. Подробно — § «ОПРОВЕРГНУТО» ниже.
|
||
> **Связанные:** [[family/how-to/arr-stack-kraken]], [[personal/tech/watchtower-docker-updates]] (реюзабельная теория), [[personal/tech/jellyfin-db-schema-mismatch]], [[personal/tech/docker-data-root-mount-race]], [[personal/tech/kraken-docker-startup-order]]
|
||
|
||
## ✅ РЕШЕНИЕ (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-файла
|
||
|
||
## 🔴 ОПРОВЕРГНУТО 2026-09-27: фикс 2026-09-20 НЕ БЫЛ ПРИМЕНЁН
|
||
|
||
**Запись «Фикс ВЫПОЛНЕН 2026-09-20» выше — неверна.** Проверка 2026-09-27 показала:
|
||
|
||
```
|
||
$ docker inspect watchtower --format '{{.Config.Image}} | Created:{{.Created}}'
|
||
containrrr/watchtower | Created:2026-05-12T15:10:55Z
|
||
$ docker inspect watchtower --format '{{.Config.Cmd}}'
|
||
[] ← БЕЗ ФЛАГОВ
|
||
```
|
||
|
||
**Что произошло:** compose-файл действительно был исправлен 2026-09-20 (образ `nickfedor/watchtower:1.22.2`,
|
||
флаги `--interval 86400 --cleanup --label-enable`), но **контейнер не был пересоздан**. Создан он
|
||
2026-05-12 и с тех пор не менялся. `docker compose up -d watchtower` **не отработал** —
|
||
либо не выполнился, либо выполнился не в той директории.
|
||
|
||
**Почему проверка это не поймала:** прогон, записанный как доказательство (`scanned=7 failed=0`),
|
||
шёл через `docker run --rm ... nickfedor/watchtower:1.22.2`. Это **временный контейнер из нужного
|
||
образа** — он подтверждает, что образ рабочий, но **ничего не говорит о работающем контейнере**.
|
||
Боевой `watchtower` продолжал крутить `containrrr/watchtower` без `--label-enable`.
|
||
|
||
🔴 **Урок (общий):** `docker run --rm <образ>` проверяет **образ**, а не **работающий контейнер**.
|
||
Проверять надо `docker inspect` самого контейнера — образ, `Cmd`, дату создания. Если дата создания
|
||
старше правки compose-файла, правка не применена.
|
||
|
||
🔴 **Урок (общий):** «поправил compose» ≠ «применил». Compose-файл — декларация; пока не выполнен
|
||
`docker compose up -d`, работающая конфигурация не меняется. Симптом-маркер: метка/флаг виден в файле,
|
||
но не в `docker inspect`.
|
||
|
||
### Что реально сделано 2026-09-27
|
||
|
||
1. Бэкап: `/home/kraken/_backup-compose-20260927/` (`mattermost.yml`, `balda.yml`, `obsidian-mcp.yml`, `watchtower-active.yml`).
|
||
2. Метка `com.centurylinklabs.watchtower.enable: "false"` добавлена в compose четырёх критичных сервисов:
|
||
`mm-postgres`, `mattermost` (`/home/kraken/mattermost/docker-compose.yml`),
|
||
`balda-mm` (`/home/kraken/balda/docker-compose.yml`),
|
||
`obsidian-mcp` (`/home/kraken/obsidian-mcp/docker-compose.yml`).
|
||
3. **Watchtower пересоздан** из `/srv/.../docker/watchtower/` — впервые с 2026-05-12:
|
||
```bash
|
||
cd /srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f/docker/watchtower
|
||
sudo docker compose up -d
|
||
# Image: nickfedor/watchtower:1.22.2
|
||
# Cmd: [--interval 86400 --cleanup --label-enable]
|
||
```
|
||
4. Контейнеры пересозданы (`docker compose up -d` в каждом проекте) — **метка применяется только
|
||
при создании контейнера**.
|
||
|
||
### 🔴 `docker update --label-add` НЕ СУЩЕСТВУЕТ
|
||
|
||
Метки (`labels`) в Docker **нельзя изменить у работающего контейнера**. Попытка:
|
||
```bash
|
||
docker update --label-add com.centurylinklabs.watchtower.enable=false mm-postgres
|
||
# → unknown flag: --label-add
|
||
```
|
||
Единственный путь — правка compose + пересоздание. Это важно: старая идея «проставить метку
|
||
командой без пересоздания» **нереализуема**.
|
||
|
||
### Результат (проверено 2026-09-27)
|
||
|
||
| Контейнер | Метка watchtower.enable | Статус |
|
||
|---|---|---|
|
||
| `mm-postgres` | `false` | running, healthy |
|
||
| `mattermost` | `false` | running, healthy |
|
||
| `balda-mm` | `false` | running |
|
||
| `obsidian-mcp` | `false` | running |
|
||
|
||
Watchtower: `nickfedor/watchtower:1.22.2`, `--interval 86400 --cleanup --label-enable`,
|
||
`Next scheduled run: ... in 23 hours 59 minutes 59 seconds`.
|
||
|
||
### Следствие: Watchtower УБИВАЛ контейнеры
|
||
|
||
Старый Watchtower без `--label-enable` лез во **все** контейнеры и гасил их SIGTERM→SIGKILL.
|
||
На `mm-postgres` это выглядело как:
|
||
```
|
||
16:25:42 container kill signal=2 ← SIGTERM
|
||
16:25:54 container kill signal=9 ← SIGKILL (пауза 11.6 с = таймаут docker stop)
|
||
16:25:58 container die exitCode=137, execDuration=70
|
||
```
|
||
`exitCode=137` = 128 + 9 (SIGKILL). **Не OOM** — `dmesg`/`journalctl -k` пусты, RAM available 2540 МБ.
|
||
Разбор: [[personal/tech/kraken-docker-startup-order]].
|
||
|
||
⚠️ `restart: unless-stopped` **не защищает** — Watchtower работает вне политик рестарта: он сам
|
||
останавливает контейнер, чтобы пересоздать его с новым образом.
|
||
|
||
### Что дальше (открытые пункты)
|
||
|
||
| # | Пункт | Статус |
|
||
|---|---|---|
|
||
| 1 | `Allowed Hosts is not configured` warning в Radarr/Sonarr/Prowlarr — ограничить, какие hostname могут обращаться | ⏳ отдельная задача |
|
||
| 2 | Home Assistant на Kraken — `Exited (128)` ~2 месяца, не поднимался (см. [[family/how-to/kraken-access]]) | ⏳ отдельная задача |
|
||
| 3 | `/home/kraken/watchtower/` — директории нет; метка старого контейнера ссылалась на удалённый файл. **Проверить, нужна ли чистка метаданных** | ⏳ |
|
||
| 4 | `/home/kraken/_backup-compose-20260927/` — удалить после проверки Alex | ⏳ |
|
||
| 5 | ⚠️ Проверить поведение при **ребуте хоста** — соблюдается ли порядок между проектами при загрузке | ⏳ |
|
||
|
||
✅ Закрыто 2026-09-20 (частично): label проставлены на 7 контейнеров.
|
||
✅ Закрыто 2026-09-27: Watchtower **реально** пересоздан, критичные контейнеры исключены меткой.
|
||
🔴 Открыто: правка 2026-09-20 не была применена — **проверять `docker inspect`, а не файл**.
|
||
|
||
## Теория (реюзабельно)
|
||
|
||
Общие причины «Watchtower не обновляет» без привязки к Kraken — [[personal/tech/watchtower-docker-updates]].
|