7.3 KiB
Executable File
Skill mirror: docker-data-root-mount-race
Зеркало скилла
docker-data-root-mount-race(категорияdocker-service-administration) для поиска по vault. Создано: 2026-09-20. Источник: Kraken mount-race инцидент. Связанные: personal/tech/docker-data-root-mount-race (полный разбор), personal/tech/jellyfin-db-schema-mismatch, family/plans/kraken-backup-to-truenas
Когда применять
Хост, у которого Docker data-root лежит на поздно монтирующемся диске (USB HDD, OMV /srv/dev-disk-by-uuid-*, RPi + внешний диск):
docker ps -aпусто, хотя контейнеры были.docker info→Containers=0при смонтированном диске.- После reboot сервисы в контейнерах «молча down» (туннели, reverse-proxy, jellyfin) — но не удалены.
- Journal:
Duplicate entry in '/etc/fstab'?
Механизм
dockerd стартует раньше, чем монтируется диск с data-root → видит пустой каталог → загружает пустое состояние (0 контейнеров). Диск монтируется позже, но daemon не перечитывает. Данные целы.
Причина: docker.service без RequiresMountsFor=.
Диагностика
docker ps -a --format "{{.Names}}\t{{.Status}}" # пусто
docker info --format "{{.DockerRootDir}} | containers={{.Containers}}"
sudo ls <data-root>/containers/ | wc -l # >0 = целы
ps -o pid,lstart,cmd -p "$(pgrep -x dockerd)" # РЕАЛЬНОЕ время старта
uptime -s; sudo dmesg | grep -iE "EXT4-fs \(sd[a-z]" | tail -5
systemctl show docker -p RequiresMountsFor # пусто = гонка возможна
grep -c "<DISK-UUID>" /etc/fstab # 2 = дубль
Питфоллы диагностики:
systemctl show docker -p ExecMainStartTimestampдаёт stale время → толькоps -o lstart.RestartPolicy.Nameвhostconfig.json=null, но в live-состоянии политика есть. Проверятьdocker inspect <name> --format '{{.HostConfig.RestartPolicy.Name}}'. Приunless-stoppedконтейнеры вернутся сами, ручнойdocker startне нужен.
Фикс
Немедленно: sudo systemctl restart docker (диск уже смонтирован).
Постоянно: drop-in /etc/systemd/system/docker.service.d/mounts.conf:
[Unit]
RequiresMountsFor=/srv/dev-disk-by-uuid-<DISK>/docker-data
After=srv-dev\x2ddisk\x2dby\x2duuid\x2d<DISK>.mount
systemctl daemon-reload, + убрать дубль строки из/etc/fstab.
Проверка: systemctl show docker -p Requires -p After → маунт-юнит в обоих.
Подтверждение реальным reboot
systemctl restart docker — НЕ тот же тест, что reboot (диск уже смонтирован). Проверка после реального выключения/включения 2026-09-20: все 12 контейнеров поднялись сами.
ssh kraken 'docker ps -q | wc -l' # ожидаем ~12, НЕ 0
🔴 «Сервис down после reboot» — ДВЕ разные причины, не путать
| Наблюдение | Причина | Где смотреть |
|---|---|---|
docker ps пусто (0) |
mount race | этот скилл |
Контейнер Up, но 5xx / unhealthy |
своя ошибка приложения | лог внутри контейнера |
Реальный пример путаницы: после reboot jellyfin был Up, но 503 — из-за несовпадения версий (образ старше схемы БД), НЕ из-за монтирования. См. personal/tech/jellyfin-db-schema-mismatch.
Правило: контейнер Up → mount race ни при чём, читать свой лог приложения.
Питфолл — логи не в stdout. docker logs может быть пуст, если приложение пишет в файл внутри volume (jellyfin: /config/log/log_YYYYMMDD.log). Читать файл; фильтровать старые ошибки по StartedAt.
Питфолл — дрейф версий у latest-тегов. docker inspect image:latest показывает digest, откуда скачали, а не текущий latest. Локальный latest может быть на месяцы старше. Проверять версию внутри образа: docker run --rm --entrypoint sh <image>:latest -c '<bin> --version'. Если версия БД выше версии сервера → пересоздать контейнер на верном образе, НЕ даунгрейдить данные.
Смежная ловушка: смешанные владельцы под data-root
Бэкап/tar дерева сервисов на том же диске: часть каталогов root:root, часть 1000:1000 → обычный юзер получает Permission denied и молча частичный архив.
sudo ls -ldn <data-root>/../docker/*/ | awk '{print $3, $4, $NF}' # владельцы
Если sudo -n true проходит — архивировать под sudo -n, а на приёмнике ставить владельца: rsync --chown=<user>:<group>.
Питфолл — долгий chown -R/tar умирает с SSH-сессией. Запускать отсоединённо:
sudo systemd-run --unit=<name> --collect --property=Type=oneshot chown -R 1000:1000 <path>
Питфолл — Restarting (1) + mkdir: Permission denied на data-каталоге: владелец на хосте ≠ UID контейнера. docker inspect <name> --format '{{.Config.User}}' → chown <uid>:<gid>. Первые mkdir-ошибки могут быть буферизованным остатком от прошлого запуска — убедиться, что контейнер реально держится Up.
Никогда
- Не считать
docker psпустым признаком потери данных — сначала проверитьcontainers/count. - Не
rm -rf«устаревший» docker-data — это реальные данные. - Не править
/etc/fstabчерез sed — писать файл локально,findmnt --verify --fstab, затем копировать.
Чеклист после фикса
docker infocount == число каталогов вcontainers/RequiresMountsForнепусто и указывает наdocker-datagrep -c "<UUID>" /etc/fstab== 1- После
systemctl restart dockerкритичные контейнерыUp - После реального reboot:
docker ps -q | wc -l== ожидаемое, не 0