# Docker data-root ↔ монтирование диска — гонка (mount race) > **Обнаружено:** 2026-09-20 на Kraken (RPi5/OMV, USB-HDD). > **Симптом-класс:** «пропали все контейнеры», `docker ps -a` пусто, `docker info` = `Containers=0` — **при целых данных на диске**. > **Связанные:** [[family/how-to/kraken-access]], [[personal/tech/xray-reverse-tunnel-kraken-truenas]], [[family/plans/kraken-backup-to-truenas]] ## Механизм (главное) `docker.service` **не имеет зависимости от монтирования диска** (`RequiresMountsFor=` пусто). Если `dockerd` стартует **раньше**, чем монтируется диск с `data-root`: 1. dockerd открывает путь `data-root` → диска там ещё нет → видит **пустой** каталог на root-ФС (или создаёт новый). 2. Через N секунд диск монтируется **поверх** точки монтирования — реальные данные «появляются». 3. Но dockerd уже разобрал своё (пустое) состояние и держит его **в памяти**. Перечитывания нет. Итог: **контейнеры целы на диске, но daemon их не видит.** Ничего не потеряно. ## Как распознать (диагностика) ```bash # 1) daemon видит 0, а на диске metadata есть? docker info --format "{{.DockerRootDir}} | containers={{.Containers}}" sudo ls /srv/dev-disk-by-uuid-<...>/docker-data/containers/ | wc -l # 35 = целы # 2) реальное время старта dockerd (ExecMainStartTimestamp ВРЁТ — stale!) ps -o pid,lstart,cmd -p $(pgrep -x dockerd) # 3) когда смонтирован диск (dmesg: "[130s] EXT4-fs (sda1): mounted") uptime -s findmnt /srv/dev-disk-by-uuid-<...> sudo journalctl -u docker -b | head -5 # 4) есть ли зависимость от mount? systemctl show docker -p RequiresMountsFor # пусто = ГОНКА ВОЗМОЖНА ``` **Ключевой признак:** `docker ps -a` пусто + `docker-data/containers/` полон → **это гонка**, а не потеря данных. > ⚠️ **Питфолл:** `systemctl show docker -p ExecMainStartTimestamp` дал stale-время (`15:18:36`), истинное — из `ps -o lstart` (`17:31:01`). Сверять с `dmesg` по времени монтирования. ## Факт инцидента 2026-09-20 (Kraken) | Событие | Время | |---|---| | Boot | 17:29:17 | | Ядро видит `sda1` | +130 с → 17:31:27 | | **dockerd стартовал** | **17:31:01** ← на 26 с раньше диска | | Диск смонтирован | 17:31:27 | USB-HDD на Kraken поднимается **~130 с** — dockerd его обгоняет. ## Фикс ### 1. Немедленно (диск уже смонтирован) ```bash sudo systemctl restart docker # daemon перечитает диск → все контейнеры вернутся ``` ### 2. Постоянно, reboot-безопасно — drop-in `/etc/systemd/system/docker.service.d/mounts.conf`: ```ini [Unit] RequiresMountsFor=/srv/dev-disk-by-uuid-/docker-data After=srv-dev\x2ddisk\x2dby\x2duuid\x2d\x2d....mount ``` Затем `sudo systemctl daemon-reload`. Проверка: `systemctl show docker -p Requires -p After` → маунт-юнит в **обоих**. > Имя маунт-юнита: systemd экранирует `-` как `\x2d`. Взять из `systemctl list-units --type=mount`. ### 3. Проверить fstab на дубли Симптом в journal: `Failed to create unit file ... already exists. Duplicate entry in '/etc/fstab'?` На Kraken было **два** маунта одного диска (OMV-блок + ручная строка `UUID=...`) → неопределённость порядка. Убрать дубль. ## Сопутствующий питфолл: права на `~` контейнера После перерегистрации диска каталог может получить **чужой UID**. На Kraken `docker/hermes/config` стал `10000:10000 700`, а контейнер работает под `USER 1000` → `mkdir: /opt/data: Permission denied` → **crash-loop** (`Restarting (1)`). **Признак:** `Restarting (1)` + в логах циклический `Permission denied` на `HOME`-каталог. **Фикс:** `sudo chown -R 1000:1000 ` (UID взять из `docker inspect --format '{{.Config.User}}'`). **Как запускать долгий chown:** `sudo -n systemd-run --unit= --collect --property=Type=oneshot chown -R ...` — переживает разрыв SSH (большое дерево на USB-диске chown'ится минутами). ## Урок Любой сервис, зависящий от данных на **медленно монтирующемся диске** (USB-HDD), ОБЯЗАН иметь `RequiresMountsFor`. Без него — гонка при каждом reboot, лотерея.