5.2 KiB
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:
- dockerd открывает путь
data-root→ диска там ещё нет → видит пустой каталог на root-ФС (или создаёт новый). - Через N секунд диск монтируется поверх точки монтирования — реальные данные «появляются».
- Но dockerd уже разобрал своё (пустое) состояние и держит его в памяти. Перечитывания нет.
Итог: контейнеры целы на диске, но daemon их не видит. Ничего не потеряно.
Как распознать (диагностика)
# 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. Немедленно (диск уже смонтирован)
sudo systemctl restart docker # daemon перечитает диск → все контейнеры вернутся
2. Постоянно, reboot-безопасно — drop-in
/etc/systemd/system/docker.service.d/mounts.conf:
[Unit]
RequiresMountsFor=/srv/dev-disk-by-uuid-<UUID>/docker-data
After=srv-dev\x2ddisk\x2dby\x2duuid\x2d<UUID>\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 <dir> (UID взять из docker inspect --format '{{.Config.User}}').
Как запускать долгий chown: sudo -n systemd-run --unit=<name> --collect --property=Type=oneshot chown -R ... — переживает разрыв SSH (большое дерево на USB-диске chown'ится минутами).
Урок
Любой сервис, зависящий от данных на медленно монтирующемся диске (USB-HDD), ОБЯЗАН иметь RequiresMountsFor. Без него — гонка при каждом reboot, лотерея.