[2026-09-27] eagle: family/how-to/kraken-watchtower.md personal/tech/kraken-docker-startup-order.md personal/tech/watchtower-docker-updates.md
This commit is contained in:
1 parent
b4645e072f
commit
4d62d8608f
3 files changed
+217
-12
No files matched your search
@@ -1,5 +1,5 @@
|
||||
---
|
||||
updated: '2026-09-20'
|
||||
updated: '2026-09-27'
|
||||
title: Watchtower — Kraken
|
||||
created: '2026-09-20'
|
||||
type: tech
|
||||
@@ -10,16 +10,21 @@ tags:
|
||||
- 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. **Статус:** ✅ ЗАВЕРШЕНО — версия 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. **Обновлено:** 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): какие контейнеры обновляются автоматом
|
||||
|
||||
@@ -155,14 +160,102 @@ done
|
||||
- `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 проставлены, решение по Jellyfin принято (`latest`), первый прогон с label прошёл (`scanned=7 failed=0`).
|
||||
✅ Закрыто 2026-09-20 (частично): label проставлены на 7 контейнеров.
|
||||
✅ Закрыто 2026-09-27: Watchtower **реально** пересоздан, критичные контейнеры исключены меткой.
|
||||
🔴 Открыто: правка 2026-09-20 не была применена — **проверять `docker inspect`, а не файл**.
|
||||
|
||||
## Теория (реюзабельно)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ created: '2026-09-27'
|
||||
updated: '2026-09-27'
|
||||
type: tech
|
||||
namespace: personal
|
||||
status: awaiting-verification
|
||||
status: resolved
|
||||
tags:
|
||||
- kraken
|
||||
- docker
|
||||
@@ -17,6 +17,8 @@ tags:
|
||||
- balda
|
||||
related:
|
||||
- '[[personal/tech/kraken-host-resource-limits.md]]'
|
||||
- '[[personal/tech/watchtower-docker-updates]]'
|
||||
- '[[family/how-to/kraken-watchtower]]'
|
||||
- '[[personal/projects/balda/balda-kraken-mm-deploy.md]]'
|
||||
- '[[personal/plans/balda-mm-endtoend-plan.md]]'
|
||||
---
|
||||
@@ -29,6 +31,15 @@ related:
|
||||
>
|
||||
> **Найдены ДВЕ независимые причины.** Они не связаны между собой и лечатся по-разному.
|
||||
> См. `personal/tech/kraken-host-resource-limits.md` — это ДРУГОЙ инцидент (нехватка RAM), не путать.
|
||||
>
|
||||
> ✅ **ИТОГ 2026-09-27:** причина №1 (Watchtower) **исправлена**. Причина №2 (порядок запуска)
|
||||
> оказалась **снята с повестки** — `depends_on` внутри проекта работал корректно, слияние
|
||||
> проектов не понадобилось. Стек поднят и healthy. Решение — § «ВЫПОЛНЕНО» ниже.
|
||||
>
|
||||
> 🔴 **Корень причины №1 лежал в документации:** [[family/how-to/kraken-watchtower]] утверждал
|
||||
> «фикс ВЫПОЛНЕН 2026-09-20», но контейнер `watchtower` не был пересоздан (создан 2026-05-12,
|
||||
> крутил `containrrr/watchtower` с `Cmd: []`). Правка в файле ≠ применённая правка.
|
||||
> Проверять `docker inspect`, а не файл.
|
||||
|
||||
## Расклад контейнеров: три ОТДЕЛЬНЫХ compose-проекта
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
---
|
||||
title: Watchtower — почему не обновляет контейнеры
|
||||
created: '2026-09-20'
|
||||
updated: '2026-09-20'
|
||||
updated: '2026-09-27'
|
||||
type: tech
|
||||
namespace: personal
|
||||
tags: [watchtower, docker, updates, infra, pitfall]
|
||||
tags: [watchtower, docker, updates, infra, pitfall, compose]
|
||||
related:
|
||||
- "[[family/how-to/kraken-watchtower]]"
|
||||
- "[[personal/tech/docker-data-root-mount-race]]"
|
||||
- "[[personal/tech/jellyfin-db-schema-mismatch]]"
|
||||
- "[[personal/tech/kraken-docker-startup-order]]"
|
||||
---
|
||||
|
||||
# Watchtower — почему не обновляет контейнеры
|
||||
@@ -85,12 +86,93 @@ services:
|
||||
- `--cleanup` — удалять старые образы; без него диск забивается (на Kraken 87%)
|
||||
- `--label-enable` — оптин: обновляется только то, что явно помечено
|
||||
|
||||
## Проверка (обязательна)
|
||||
## 🔴 Причина 5 (главная по коварству): правка compose НЕ ПРИМЕНЕНА
|
||||
|
||||
`Up` + отсутствие ошибок ≠ работа. Нужен живой прогон:
|
||||
`--interval`, дедуп по API-версии, форк образа — всё это может быть **правильно прописано в файле**
|
||||
и при этом **не действовать**, потому что контейнер не пересоздан. Compose-файл — **декларация**;
|
||||
работающая конфигурация меняется только после `docker compose up -d`.
|
||||
|
||||
**Маркер проблемы:** конфиг в файле ≠ `docker inspect` контейнера.
|
||||
|
||||
```bash
|
||||
# что РЕАЛЬНО запущено (а не что написано в файле)
|
||||
docker inspect watchtower --format 'Image:{{.Config.Image}}'
|
||||
docker inspect watchtower --format 'Cmd:{{.Config.Cmd}}'
|
||||
docker inspect watchtower --format 'Created:{{.Created}}'
|
||||
```
|
||||
|
||||
**Признак, что правка не применена:** `Created` (дата создания контейнера) **старше** даты правки
|
||||
compose-файла. На Kraken: файл исправлен 2026-09-20, контейнер создан 2026-05-12 и не менялся —
|
||||
4 месяца крутился старый `containrrr/watchtower` с `Cmd: []`.
|
||||
|
||||
### 🔴 Почему фейковая проверка проходит: `docker run --rm` проверяет ОБРАЗ, а не контейнер
|
||||
|
||||
Соблазнительный способ «проверить Watchtower»:
|
||||
```bash
|
||||
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
|
||||
nickfedor/watchtower:1.22.2 --run-once --monitor-only
|
||||
nickfedor/watchtower:1.22.2 --run-once --monitor-only --label-enable
|
||||
# → Update session completed failed=0 scanned=7 updated=0 ← выглядит как доказательство!
|
||||
```
|
||||
Этот прогон создаёт **временный контейнер из указанного образа** и корректно отвечает на вопрос
|
||||
«рабочий ли образ `nickfedor/watchtower:1.22.2`». Он **ничего не говорит** о том, какой образ
|
||||
и с какими флагами крутится в боевом контейнере `watchtower`. На Kraken именно этот прогон был
|
||||
записан в документацию как «проверено, фикс работает» — при том, что боевой Watchtower оставался
|
||||
старым и **убивал контейнеры**.
|
||||
|
||||
🔴 **Правило:** для проверки **работающего** сервиса смотреть `docker inspect <container>`,
|
||||
а не запускать отдельный экземпляр образа. `docker run --rm` = проверка образа.
|
||||
|
||||
## 🔴 Watchtower может УБИВАТЬ контейнеры (SIGTERM → SIGKILL)
|
||||
|
||||
Watchtower не только обновляет — он **останавливает** контейнеры, и это видно как:
|
||||
|
||||
```
|
||||
container kill signal=2 ← SIGTERM
|
||||
container kill signal=9 ← SIGKILL, пауза ~10 с = таймаут docker stop
|
||||
container die exitCode=137
|
||||
```
|
||||
|
||||
`exitCode=137` = 128 + 9 (SIGKILL). **Не путать с OOM-killer:** проверить
|
||||
`dmesg | grep -i -E 'oom|killed process'` и `journalctl -k -b` — если пусто, убийца не ядро.
|
||||
|
||||
⚠️ **`restart: unless-stopped` НЕ защищает от Watchtower.** Политики рестарта действуют на сбои;
|
||||
Watchtower останавливает контейнер сам, штатно, чтобы пересоздать его с новым образом.
|
||||
|
||||
Признак в логе Watchtower, что он полез вне расписания:
|
||||
```
|
||||
level=info msg="Waiting for running update to be finished..."
|
||||
```
|
||||
Это значит предыдущая сессия обновления зависла и не закрылась — Watchtower дождался её
|
||||
и пошёл по контейнерам немедленно.
|
||||
|
||||
**Как исключить контейнер из-под Watchtower:** метка `com.centurylinklabs.watchtower.enable=false`
|
||||
(требуется `--label-enable`, иначе метка игнорируется).
|
||||
|
||||
## 🔴 `labels` нельзя изменить у работающего контейнера
|
||||
|
||||
**`docker update --label-add` НЕ СУЩЕСТВУЕТ** (`unknown flag: --label-add`). Метки задаются
|
||||
только при создании контейнера. Единственный путь: правка `labels` в compose + `docker compose up -d`
|
||||
(пересоздание). Проверено на Docker 29.4.3 / Compose v5.1.3.
|
||||
|
||||
Практическое следствие: «проставить метку без пересоздания» — нереализуемая идея. Пересоздание
|
||||
безопасно, если данные в томах, но требует явного решения.
|
||||
|
||||
## Проверка (обязательна)
|
||||
|
||||
`Up` + отсутствие ошибок ≠ работа. **И `docker run --rm` ≠ проверка работающего сервиса** (см. выше).
|
||||
|
||||
Правильный двухшаговый порядок:
|
||||
|
||||
```bash
|
||||
# ШАГ 1 — что РЕАЛЬНО запущено (главная проверка)
|
||||
docker inspect watchtower --format 'Image:{{.Config.Image}} Cmd:{{.Config.Cmd}} Created:{{.Created}}'
|
||||
# Image: nickfedor/watchtower:1.22.2
|
||||
# Cmd: [--interval 86400 --cleanup --label-enable]
|
||||
# Created: <должна быть ПОЗЖЕ правки compose-файла>
|
||||
|
||||
# ШАГ 2 — рабочий ли образ (вспомогательно)
|
||||
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
|
||||
nickfedor/watchtower:1.22.2 --run-once --monitor-only --label-enable
|
||||
```
|
||||
`--monitor-only` обязателен, иначе `--run-once` **реально обновит** контейнеры.
|
||||
|
||||
@@ -102,6 +184,9 @@ level=info msg="Update session completed" failed=0 scanned=N skipped=0 updated=0
|
||||
```
|
||||
`Found new image` = баг с метаданными вылечен. `updated=0` в monitor-only — нормально.
|
||||
|
||||
⚠️ Если `scanned` **больше** ожидаемого числа размеченных контейнеров — значит `--label-enable`
|
||||
не действует, и Watchtower трогает всё подряд. Проверять `Cmd` из шага 1.
|
||||
|
||||
## ⚠️ Автообновление может сломать сервис: пинить мажор версии
|
||||
|
||||
Тип `latest` + автообновление = переход на новую **мажорную** версию без предупреждения. Для сервисов с миграциями БД (EF Core, Prisma, любые forward-only миграции) это необратимо:
|
||||
@@ -127,10 +212,26 @@ level=info msg="Update session completed" failed=0 scanned=N skipped=0 updated=0
|
||||
|
||||
## Урок
|
||||
|
||||
Watchtower — компонент, который **молча не работает**. Его нельзя «поставить и забыть»: обязательны (а) явный `--interval`, (б) отсутствие `DOCKER_API_VERSION`, (в) периодический `--run-once --monitor-only` как health-check, (г) осознанное решение, каким контейнерам вообще разрешено автообновление.
|
||||
Watchtower — компонент, который **молча не работает**. Его нельзя «поставить и забыть»: обязательны (а) явный `--interval`, (б) отсутствие `DOCKER_API_VERSION`, (в) периодический `--run-once --monitor-only` как health-check, (г) осознанное решение, каким контейнерам вообще разрешено автообновление, (д) **проверка `docker inspect`, что правка реально применена**.
|
||||
|
||||
### 🔴 Два универсальных урока (2026-09-27)
|
||||
|
||||
**1. Файл ≠ работающая конфигурация.** Compose-файл — декларация. Пока не выполнен
|
||||
`docker compose up -d`, ничего не изменилось. Проверять **`docker inspect` контейнера**, а не файл.
|
||||
Дата создания контейнера (`Created`) старше даты правки файла = **правка не применена**.
|
||||
|
||||
**2. `docker run --rm <образ>` проверяет ОБРАЗ, а не работающий контейнер.** Прогон временного
|
||||
контейнера из «правильного» образа выглядит как полноценное доказательство (`scanned=7 failed=0`),
|
||||
но не говорит ничего о боевом сервисе. Именно так на Kraken в документацию попала запись
|
||||
«фикс выполнен», при том что 4 месяца крутился старый Watchtower и **убивал контейнеры**.
|
||||
Для проверки боевого сервиса — только `docker inspect` самого контейнера.
|
||||
|
||||
Оба урока общие, не только про Watchtower: они применимы к любому сервису, правка которого
|
||||
делается через compose-файл.
|
||||
|
||||
## Связанные
|
||||
|
||||
- [[family/how-to/kraken-watchtower]] — живой разбор и точные команды на Kraken
|
||||
- [[personal/tech/kraken-docker-startup-order]] — что Watchtower ломает на Kraken (убийство контейнеров, exit 137)
|
||||
- [[personal/tech/jellyfin-db-schema-mismatch]] — что ломает автообновление мажора
|
||||
- [[personal/tech/docker-data-root-mount-race]] — другой дефект «контейнеры пропали»
|
||||
Reference in new issue
Block a user