Короткий ответ

Пока docker.service в failed, любой docker ps врёт. На host.example читайте journalctl -u docker -u containerd --no-pager -b, затем свободное место на томе /var/lib/docker, драйвер overlay2 и cgroup (на Ubuntu 22.04/24.04 это обычно cgroup v2 + native.cgroupdriver=systemd). Не чините «переустановкой docker-ce» и не запускайте docker system prune -a, пока демон не слушает сокет: prune без API ничего не удалит, а с полуживым daemon может снести не то.

Контейнеры проекта app подождут. Цель — вернуть dockerd, сохранив named volume app_data.

Симптомы и как отличить

Типичная картина:

  • systemctl is-active dockerfailed или inactive;
  • docker infoCannot connect to the Docker daemon at unix:///var/run/docker.sock;
  • ss -xl | grep docker.sock пусто;
  • сразу после apt upgrade docker-ce или заполнения диска.
Что видноЭто не «daemon лёг»Куда
Сокет есть, один контейнер Restartingcrash loop приложенияперезапуск контейнера
docker compose up ругается на YAMLдемон живCompose стек
df -h /var/lib/docker 100%место, демон может падать из‑за overlayдиск Docker
Нет ping до host.exampleхост/SSH, не dockerdжелезо и гипервизор

Возможные причины

От частых к редким:

  1. Том / или отдельный /var/lib/docker заполнен: overlay2 не создаёт слой, dockerd падает при старте.
  2. Зависшие mount overlay после жёсткого reboot: mount | grep overlay показывает полумёртвые точки.
  3. Несовместимость cgroup: в daemon.json прописан cgroup-parent или native.cgroupdriver=cgroupfs на хосте с unified hierarchy.
  4. containerd не стартовал (AppArmor, битый конфиг /etc/containerd/config.toml).
  5. Повреждённый daemon.json (лишняя запятая) — dockerd выходит сразу.
  6. Конфликт iptables/nft: реже на 27.x, но встречается после ручного iptables-legacy.
  7. Редко: сломанный graphdriver после миграции с aufs/devicemapper или чужой data-root.

Диагностика

Работайте по SSH под admin на host.example. Подставьте свои пути.

1. Unit и journal

systemctl status docker.service containerd.service --no-pager
journalctl -u docker -u containerd --no-pager -b | tail -n 120
sudo dockerd --validate 2>&1 || true

Ищите строки failed to start daemon, error initializing graphdriver: overlay2, cgroup mountpoint does not exist, no space left on device. Это и есть карта, не догадки.

2. Диск и mount overlay

df -hT / /var/lib/docker
df -i / /var/lib/docker
sudo du -xhd1 /var/lib/docker | sort -h
mount | grep -E 'overlay|docker'

Inode 100% даёт ту же картину, что и гигабайты. Не путайте с логами json-file.

3. Конфиг и cgroup

python3 -m json.tool /etc/docker/daemon.json
cat /proc/cgroups
stat -fc %T /sys/fs/cgroup
ps -p 1 -o comm=

На Ubuntu 22.04/24.04 ожидайте cgroup2fs и systemd как PID 1. Если daemon.json содержит "exec-opts": ["native.cgroupdriver=cgroupfs"] — это конфликт с текущим стеком 27.x.

4. Сокет и процессы-зомби

ls -l /var/run/docker.sock /run/containerd/containerd.sock
pgrep -a dockerd; pgrep -a containerd

Есть dockerd без unit — ручной запуск из отладки. Не оставляйте второй процесс.

Решение

Сценарий A. Journal: no space / overlay2 ENOSPC

Освободите не каталог volumes проекта app. Кандидаты: /var/lib/docker/tmp, старый build cache, journal хоста. Если API уже не слушает, чистите хостовое, не Docker API.

sudo journalctl --vacuum-size=200M
sudo apt-get clean
df -h /
sudo systemctl start docker

Когда сокет ожил — дальше точечная чистка по безопасному prune, не -a вслепую.

Сценарий B. Повреждённый daemon.json или cgroupdriver

Снимите копию и уберите чужой driver:

sudo cp -a /etc/docker/daemon.json /etc/docker/daemon.json.bak.$(date +%F)
sudo python3 -m json.tool /etc/docker/daemon.json

Минимальный рабочий каркас для 27.x на Ubuntu (подправьте под свою политику логов, не копируйте вслепую в прод без окна):

sudo tee /etc/docker/daemon.json >/dev/null <<'EOF'
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "live-restore": true
}
EOF
sudo systemctl restart docker

Не добавляйте iptables: false, чтобы «просто завелось»: сеть контейнеров развалится, см. нет интернета.

Сценарий C. Зависшие overlay mounts

После crash ядра точки overlay остаются. Перезапуск unit не всегда их снимает.

mount | awk '/overlay/ {print $3}'

В окне обслуживания: остановите docker, размонтируйте хвосты, стартаните снова. Не rm -rf /var/lib/docker — там app_data.

sudo systemctl stop docker docker.socket containerd
sudo umount $(mount | awk '/\/var\/lib\/docker/ {print $3}' | sort -r) 2>/dev/null || true
sudo systemctl start containerd docker

Сценарий D. containerd failed

sudo containerd config dump >/tmp/containerd.dump
journalctl -u containerd -b --no-pager | tail -n 80
sudo systemctl reset-failed containerd docker
sudo systemctl start containerd docker

AppArmor DENIED на runc — правьте профиль, не apparmor=unconfined навсегда.

Как проверить, что проблема устранена

systemctl is-active docker containerd
docker info --format '{{.ServerVersion}} {{.Driver}} {{.CgroupDriver}} {{.CgroupVersion}}'
docker ps -a
cd /opt/app && docker compose ps

Ожидание: Engine 27.x, overlay2, systemd, cgroup v2. Проект app либо running, либо явно Exited по своей причине — не из‑за отсутствия daemon.

Функционально: curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/ если сервис так опубликован.

Если не помогло

  • Сокет есть, docker ps виснет: strace -p $(pidof dockerd) и диск; часто зависание на overlay при 100% inode.
  • Стартует и сразу падает: повторный journal, ищите panic в graphdriver.
  • После смены data-root «пропали» контейнеры: это другой каталог, не удаляйте старый.
  • LVM thin pool 100% (если вообще не overlay2) — это уже storage хоста, не «переустановить docker».
  • Нужна чистка образов — только после живого API и с исключением томов: prune.

Профилактика

  • Мониторинг systemctl is-active docker и df на /var/lib/docker (порог 80%).
  • Ротация json-file глобально, не «когда диск кончился».
  • Валидный JSON в daemon.json через CI/python3 -m json.tool до выкладки.
  • Не менять cgroup driver без окна и документа.
  • Snapshot VM / бэкап volume app_data до экспериментов с data-root.

FAQ

Можно ли systemctl reset-failed и забыть?

reset-failed снимает счётчик, не причину. Если unit снова уйдёт в failed — вы потеряли время. Сначала journal.

Нужно ли purge пакета docker-ce?

Нет как первый шаг. Purge легко зацепит /var/lib/docker, если руками чистили не тот каталог. Сначала конфиг и диск.

dockerd от root в foreground безопаснее?

Только для отладки в консоли BMC. В проде — unit. Не оставляйте ручной процесс плюс systemd.

Ubuntu 24.04 и nftables ломают Docker?

Docker 27.x штатно работает с iptables-nft. Ломает ручной перевод iptables-legacy «как на 16.04» или iptables: false в daemon.json.

Где лежат данные app_data, если daemon мёртв?

Named volume — каталог в /var/lib/docker/volumes/app_data/_data (имя может быть с префиксом проекта). Не копируйте его, пока overlay смонтирован криво; сначала поднимите daemon или остановите unit и снимите mounts.