Files
obsidian-vault/personal/tech/docker-data-root-mount-race.md
T

6.9 KiB
Raw Blame History

title, created, type, namespace, tags, confidence, related
title created type namespace tags confidence related
Docker data-root ↔ mount race — диагностика 2026-09-20 tech personal
docker
systemd
mount
kraken
diagnostics
high
family/how-to/kraken-access
personal/tech/xray-reverse-tunnel-kraken-truenas

Docker data-root ↔ mount race

Обнаружено 2026-09-20 на Kraken (RPi5/OMV, USB-HDD). Зеркало скилла docker-data-root-mount-race (категория docker-service-administration).

Триггер

Хост, у которого Docker data-root лежит на диске, монтирующемся поздно (USB-HDD, OMV /srv/dev-disk-by-uuid-*, RPi). Признаки:

  • docker ps -a пусто, но контейнеры раньше были.
  • docker info → Containers=0, при этом диск с docker-data смонтирован.
  • После reboot сервисы в контейнерах (cloudflared, reverse-proxy bridge, jellyfin…) молча «down» — но контейнеры не удалялись.
  • journal: Duplicate entry in '/etc/fstab'? от systemd-fstab-generator.

Механизм

dockerd стартует раньше, чем монтируется диск с его data-root. Открывает путь, видит пусто → инициализирует пустое состояние (0 контейнеров). Через секунды диск монтируется поверх точки, реальный containers/ появляется — но dockerd уже разобрал состояние и не перечитывает.

Ничего не потеряно. Metadata цела на диске, daemon её просто не видит.

Причина: у docker.service нет RequiresMountsFor= на маунт-юнит диска.

Диагностика

# 1) daemon думает, что пусто
docker ps -a --format "{{.Names}}\t{{.Status}}"        # пусто
docker info --format "{{.DockerRootDir}} | containers={{.Containers}}"

# 2) но metadata НА ДИСКЕ (нужен root; каталог 711 root:root)
sudo ls -la /srv/dev-disk-by-uuid-<DISK>/docker-data/
sudo ls /srv/dev-disk-by-uuid-<DISK>/docker-data/containers/ | wc -l   # >0 = целы

# 3) подтвердить гонку: dockerd стартовал РАНЬШЕ диска
ps -o pid,lstart,cmd -p "$(pgrep -x dockerd)"          # истинное время старта
uptime -s                                                # время boot
sudo dmesg | grep -iE "EXT4-fs \(sd[a-z]" | tail -5      # когда ФС смонтировалась
findmnt /srv/dev-disk-by-uuid-<DISK>

# 4) подтвердить отсутствие зависимости (корень)
systemctl show docker -p RequiresMountsFor               # пусто = нет порядка
grep -c "<DISK-UUID>" /etc/fstab                         # 2 = дубль

ПИТФОЛЛ — не то поле времени. systemctl show docker -p ExecMainStartTimestamp может вернуть stale значение (прошлая активация). Реальное время — ps -o lstart -p $(pgrep -x dockerd).

ПИТФОЛЛ — не тот источник RestartPolicy. RestartPolicy.Name из docker-data/containers/<id>/hostconfig.json показывает то, что передал исходный docker run — часто null, даже когда политика есть в живом daemon state. НЕ делать вывод «контейнеры не поднимутся сами». Проверять живой daemon:

docker inspect <name> --format '{{.HostConfig.RestartPolicy.Name}}'

Если unless-stopped — контейнеры сами вернутся при рестарте daemon, ручной docker start не нужен.

Фикс

Немедленный (вернуть сервисы — диск уже смонтирован)

sudo systemctl restart docker
docker info --format "containers={{.Containers}} running={{.ContainersRunning}}"

Контейнеры с restart: unless-stopped поднимаются сами.

Постоянный (сделать reboot безопасным)

  1. Бэкап: /etc/fstab, /etc/docker/daemon.json, compose-каталоги сервисов → датированная папка.
  2. Drop-in, чтобы systemd не стартовал dockerd раньше диска: /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
    
    Имя .mount юнита = путь, где / → -, а каждый литеральный - escaped как \x2d (systemd escaping).
  3. sudo systemctl daemon-reload
  4. Убрать дубль строки монтирования того же диска из /etc/fstab (systemd отказывается от дублей; OMV часто добавляет свою рядом с ручной UUID=...).
  5. Проверка:
    findmnt --verify --fstab          # rc=0
    systemctl show docker -p Requires -p After   # маунт-юнит в ОБОИХ
    sudo systemctl restart docker                 # sanity: контейнеры перезагрузятся
    

Нельзя

  • Не предполагать потерю данных, если docker ps пусто, но диск смонтирован — сначала посчитать docker-data/containers/. Containers=0 в docker info не доказательство удаления.
  • Не rm -rf «устаревший» docker-data — это и есть данные.
  • Не править /etc/fstab через sed; писать полный файл локально, валидировать findmnt --verify --fstab, затем копировать на место.

Чеклист после фикса

  • docker info count == число каталогов в docker-data/containers/.
  • systemctl show docker -p RequiresMountsFor не пусто и указывает на docker-data.
  • grep -c "<DISK-UUID>" /etc/fstab = 1.
  • После тестового systemctl restart docker критичные контейнеры Up.
  • При следующем плановом reboot: docker ps -q | wc -l возвращает ожидаемое число, не 0.

Применение на Kraken (2026-09-20)

Полный кейс: family/how-to/kraken-access и personal/tech/xray-reverse-tunnel-kraken-truenas. Кратко: boot 17:29:17, dockerd 17:31:01, диск 17:31:27 (на 26 с позже) → 0 контейнеров. Фикс: drop-in RequiresMountsFor=/srv/.../6194539b.../docker-data

  • чистка fstab. Бэкап: /home/kraken/backups/docker-recovery-20260920-105228/.