Демон Docker не запускається: спочатку прочитайте цей журнал (потім виправте)

Було корисно?

Коли демон Docker не запускається, ваш хост перетворюється на музейний експонат: контейнери застигли в часі, CI-джоби зависли, деплої відкочуються, і хтось питає, чи «можемо ми просто перезавантажити ще раз». Можна перезавантажити, звісно. Можна також поставити мокрий ноутбук у мікрохвильовку. Жодне з цього — стратегія.

Найшвидший шлях з проблеми — це не випадковий набір рестартів. Це один чистий прочит потрібного журналу, а потім мала кількість продуманих команд, які скажуть, що саме зламалося: конфіг, сховище, функції ядра, мережеві правила, права або containerd.

Швидкий план діагностики (що перевіряти першочергово)

Якщо у вас є лише п’ять хвилин і пейджер вібрує вам у щелепу, робіть це в порядку. Мета — швидко визначити клас вузького місця: помилка парсингу конфігу, збій залежності рантайму, корупція/переповнення сховища, невідповідність функцій ядра або відмова мережевих правил.

По-перше: systemd каже, чому воно відмовилося тримати Docker живим

Docker зазвичай управляється systemd. systemd має першу вагому думку: код виходу і миттєвий stderr.

cr0x@server:~$ systemctl status docker --no-pager -l
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Tue 2026-01-02 10:12:54 UTC; 17s ago
    Process: 1842 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock (code=exited, status=1/FAILURE)
   Main PID: 1842 (code=exited, status=1/FAILURE)
        CPU: 230ms

Jan 02 10:12:54 server dockerd[1842]: failed to start daemon: error initializing graphdriver: overlay2: failed to mount /var/lib/docker/overlay2: invalid argument
Jan 02 10:12:54 server systemd[1]: docker.service: Main process exited, code=exited, status=1/FAILURE
Jan 02 10:12:54 server systemd[1]: docker.service: Failed with result 'exit-code'.
Jan 02 10:12:54 server systemd[1]: Failed to start Docker Application Container Engine.

Рішення: Сприйміть серйозно перший рядок failed to start daemon:. Зазвичай це вказує на клас кореневої причини. Тут він кричить «overlay2 mount invalid argument» → невідповідність ядра/файлової системи/overlayfs, а не «баг у Docker».

По-друге: journalctl для Docker дає повний стек, не лише заголовок

cr0x@server:~$ journalctl -u docker -b --no-pager -n 200
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54.118922635Z" level=info msg="Starting up"
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54.152001115Z" level=error msg="failed to mount overlay: invalid argument" storage-driver=overlay2
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54.152114935Z" level=fatal msg="Error starting daemon: error initializing graphdriver: overlay2: failed to mount /var/lib/docker/overlay2: invalid argument"

Рішення: Якщо ви бачите level=fatal, за яким слідує конкретна підсистема (graphdriver, iptables, daemon.json), припиніть гадати. Зосередьтеся на перевірках цієї підсистеми.

По-третє: перевірте місткість та файлову систему під /var/lib/docker

Повний диск і вичерпання інодів не завжди голосно оголошують про себе. Вони просто змушують демонів поводитися так, ніби ті забули, як писати.

cr0x@server:~$ df -h /var/lib/docker
Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme0n1p4   80G   79G  300M 100% /

cr0x@server:~$ df -i /var/lib/docker
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/nvme0n1p4   5.0M   5.0M       0  100% /

Рішення: Якщо блоки або іноди на 100%, ваша «Docker не запускається» — це інцидент сховища. Звільніть місце спочатку; не міняйте драйвери, не перевстановлюйте пакети й не «скидайте Docker», поки хост не зможе писати.

По-четверте: перевірте конфіг демона, перш ніж ганятися за примарами

Одна зайва кома в JSON може вивести з ладу всю вашу платформу контейнерів. Хотілося б, щоб це було жартом. (Не є.)

cr0x@server:~$ sudo cat /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": { "max-size": "10m", },
  "iptables": true
}

Рішення: Та зайва кома після "10m" не дозволить dockerd запуститися. Виправте JSON, а потім перезапустіть. Ні до чого більше не чіпайте.

По-п’яте: перевірте, чи containerd живий (або переконайтеся, що ні)

cr0x@server:~$ systemctl status containerd --no-pager -l
● containerd.service - containerd container runtime
     Loaded: loaded (/lib/systemd/system/containerd.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2026-01-02 10:08:11 UTC; 6min ago
       Docs: man:containerd(8)
   Main PID: 1210 (containerd)

Рішення: Якщо containerd впав, Docker може отримувати помилки сокету або рантайму. Виправте containerd спочатку. Якщо containerd здоровий — рухайтеся далі.

Один журнал, який треба прочитати спочатку (і чому)

Прочитайте журнал systemd для юніту docker перед тим, як читати щось інше. Не тому, що це модно. А тому, що це авторитетно. Він фіксує:

  • Чому systemd припинив перезапуск сервісу (перевищення ліміту запусків, цикли падінь).
  • Точно те, що dockerd виводив у stderr/stdout.
  • Часування відносно інших сервісів (containerd, мережа, монтування).

На більшості сучасних дистрибутивів це головна команда:

cr0x@server:~$ journalctl -u docker -b --no-pager -o cat
time="2026-01-02T10:12:54.118922635Z" level=info msg="Starting up"
time="2026-01-02T10:12:54.152114935Z" level=fatal msg="Error starting daemon: failed to load listeners: can't create unix socket /var/run/docker.sock: permission denied"

Рішення: Ця помилка — не «Docker не може поговорити з Docker». Це проблема прав/власності файлової системи/SELinux/AppArmor на шляху сокета (або в його батьківському каталозі). Тепер ви знаєте, в якому класі відмови ви знаходитеся.

Не починайте з /var/log/docker.log, якщо тільки ви не на системі, яка явно логувала туди. Багато інсталяцій цього не роблять. Не починайте з випадкових фіксів зі Stack Overflow. Ваша система вже сказала, що не так; ви просто ще не послухали.

Цікаві факти та історія (щоб помилки стали зрозумілі)

  • Docker спочатку використовував LXC (Linux Containers) для ізоляції, перед тим як перейти на libcontainer, що змінило спосіб використання низькорівневих функцій ядра.
  • containerd відокремили від Docker, щоб ядро рантайму могло розвиватися незалежно; тому «Docker впав» насправді може означати «containerd впав».
  • overlay2 став за замовчуванням на багатьох дистрибутивах, бо він швидкий і економний по місцю, але вибагливий щодо функцій файлової системи (особливо на старих ядрах).
  • Інтеграція з iptables не опціональна для класичного Docker-мережування; коли firewalld/nftables/iptables конфліктують, Docker може не стартувати, а не лише падати при запуску контейнера.
  • Прийняття cgroups v2 змінило механіку контролю ресурсів; старі версії Docker на нових дистрибутивах можуть аварійно завершуватися через невідповідність драйверів cgroup.
  • Стандартні налаштування логування Docker (json-file) можуть тихо заповнювати диск; демон, що не запускається після події переповнення диска, часто — наслідок неконтрольованого росту логів.
  • Поведінка start-limit — це функція systemd: після повторних збоїв він перестає пробувати. Оператори часто помилково читають це як «Docker завис».
  • /var/lib/docker не святе; це просто стан. Там є образи, шари, метадані та томи (залежно від конфіг). Його можна мігрувати, але робити це недбало — означає заробити роботу на вихідних.
  • Rootless Docker існує, щоб зменшити привілеї демона, але це додає окремий клас відмов навколо користувацьких сервісів, XDG_RUNTIME_DIR і делегування cgroup.

Практичні завдання: команди, виводи та рішення

Ви не фіксуєте Docker, бубонячи «перезапусти». Ви фіксуєте Docker, збираючи невелику кількість фактів і приймаючи рішення після кожного з них. Нижче — задачі, які я використовував у реальних інцидентах, з реалістичними виводами і тим, що вони означають.

Завдання 1: Підтвердити стан юніту і останню причину збою

cr0x@server:~$ systemctl is-enabled docker; systemctl is-active docker; systemctl status docker --no-pager -l
enabled
failed
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Tue 2026-01-02 10:12:54 UTC; 2min 11s ago
    Process: 1842 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock (code=exited, status=1/FAILURE)
Jan 02 10:12:54 server dockerd[1842]: failed to start daemon: Error initializing network controller: failed to create NAT chain DOCKER: iptables failed

Рішення: Якщо збій вказує на network controller / iptables, не гайте часу на перевірки сховища. Перейдіть до секції iptables/nftables.

Завдання 2: Витягнути повні логи за час буту для docker

cr0x@server:~$ journalctl -u docker -b --no-pager -n 300
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=info msg="Starting up"
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=info msg="libcontainerd: started new containerd process" pid=1901
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=error msg="iptables failed: iptables -t nat -N DOCKER: iptables v1.8.7 (nf_tables): Chain already exists."
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=fatal msg="Error starting daemon: Error initializing network controller: iptables failed"

Рішення: «Chain already exists» натякає на застарілі правила від попереднього запуску або конфлікт з бекендом nftables. Ви в режимі відмови мережевих правил.

Завдання 3: Перевірити, чи systemd не обмежує вам запуск

cr0x@server:~$ systemctl status docker --no-pager -l | sed -n '1,25p'
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: failed (Result: start-limit-hit) since Tue 2026-01-02 10:13:09 UTC; 18s ago
Jan 02 10:13:09 server systemd[1]: docker.service: Start request repeated too quickly.
Jan 02 10:13:09 server systemd[1]: docker.service: Failed with result 'start-limit-hit'.

Рішення: Очистіть start-limit після того, як виправите базову проблему; інакше ви «виправите» і все одно побачите відмову.

cr0x@server:~$ sudo systemctl reset-failed docker

Завдання 4: Валідувати /etc/docker/daemon.json, не довіряючись очам

cr0x@server:~$ sudo python3 -m json.tool /etc/docker/daemon.json
Expecting property name enclosed in double quotes: line 3 column 36 (char 61)

Рішення: Виправте синтаксис JSON спочатку. Якщо це не працює, Docker не запуститься. Після виправлення файлу, запускайте валідатор доти, поки він не виведе відформатований JSON і не поверне 0.

Завдання 5: Витягти ефективну командну лінію Docker (override-типи важливі)

cr0x@server:~$ systemctl cat docker --no-pager
# /lib/systemd/system/docker.service
[Service]
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

# /etc/systemd/system/docker.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// --data-root /mnt/docker-data --storage-driver=overlay2

Рішення: Якщо ви бачите overrides, ставтеся до них підозріло, поки не доведено зворотне. Багато інцидентів «Docker зламався після оновлення» насправді — «старий override зустрів нові дефолти».

Завдання 6: Перевірити монтування data-root і тип файлової системи

cr0x@server:~$ findmnt -no SOURCE,FSTYPE,OPTIONS /var/lib/docker
/dev/nvme0n1p4 ext4 rw,relatime

cr0x@server:~$ findmnt -no SOURCE,FSTYPE,OPTIONS /mnt/docker-data
/dev/sdb1 xfs rw,relatime,attr2,inode64,logbufs=8,logbsize=32k

Рішення: Overlay2 на XFS зазвичай вимагає ftype=1. Якщо ви мігрували дані Docker на старіше XFS, відформатоване з ftype=0, overlay2 не спрацює.

Завдання 7: Перевірити XFS ftype (критично для overlay2 на XFS)

cr0x@server:~$ sudo xfs_info /dev/sdb1 | grep ftype
naming   =version 2              bsize=4096   ascii-ci=0, ftype=0

Рішення: ftype=0 — це червоне світло для overlay2. Виправлення: переформатувати з ftype=1 (потребує міграції даних) або змінити драйвер сховища (зазвичай поганий варіант). Не продовжуйте нескінченно перезапускати.

Завдання 8: Перевірити підтримку overlayfs ядром (і знайти причини «invalid argument»)

cr0x@server:~$ uname -r
4.15.0-213-generic

cr0x@server:~$ lsmod | grep overlay
overlay               102400  0

cr0x@server:~$ sudo dmesg -T | tail -n 20
[Mon Jan  2 10:12:54 2026] overlayfs: filesystem on '/var/lib/docker/overlay2' not supported as upperdir

Рішення: Рядок dmesg каже, що ядро відхилило файлову систему як upperdir для overlay (поширено для певних мережевих файлових систем, неправильних монтувань або непідтримуваних опцій). Виправте монтування/файлову систему; Docker цього не «замажить».

Завдання 9: Підтвердити сокет containerd і його стан

cr0x@server:~$ ls -l /run/containerd/containerd.sock
srw-rw---- 1 root root 0 Jan  2 10:08 /run/containerd/containerd.sock

cr0x@server:~$ systemctl status containerd --no-pager -l | sed -n '1,15p'
● containerd.service - containerd container runtime
     Active: active (running) since Tue 2026-01-02 10:08:11 UTC; 6min ago

Рішення: Якщо сокет відсутній або containerd падає, виправте containerd перед Docker. Якщо containerd в порядку — проблема в іншому.

Завдання 10: Шукати очевидні відмови прав (SELinux/AppArmor видно тут)

cr0x@server:~$ sudo journalctl -b --no-pager | grep -E 'DENIED|apparmor="DENIED"|avc:'
Jan 02 10:12:54 server kernel: audit: type=1400 apparmor="DENIED" operation="create" profile="docker-default" name="/var/run/docker.sock" pid=1842 comm="dockerd"

Рішення: Якщо бачите явні відмови, припиніть трактувати це як проблему конфігу Docker. Виправте політику/профіль або контекст файлу. Запускати Docker з «просто вимкніть безпеку» — шлях до ескалації інциденту у порушення безпеки.

Завдання 11: Інспектувати невідповідність бекендів iptables (iptables vs nft)

cr0x@server:~$ sudo iptables --version
iptables v1.8.7 (nf_tables)

cr0x@server:~$ sudo iptables -t nat -S | sed -n '1,25p'
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-N DOCKER-ISOLATION-STAGE-1
-N DOCKER-ISOLATION-STAGE-2

Рішення: Якщо Docker скаржиться на існування ланцюгів, у вас може бути конфліктуючий менеджер правил (firewalld, kube-proxy, кастомні скрипти). Прийміть рішення, хто володіє правилами. У критичному випадку обережно почистіть лише Docker-керовані ланцюги — після розуміння «радіусу ураження».

Завдання 12: Підтвердити режим cgroup і невідповідність драйверів

cr0x@server:~$ mount | grep cgroup2
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)

cr0x@server:~$ journalctl -u docker -b --no-pager | grep -i cgroup | tail -n 5
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=fatal msg="Error starting daemon: Devices cgroup isn't mounted"

Рішення: Це часто вказує на стару збірку Docker або неправильну конфігурацію для cgroups v2. Виправлення — вирівняння версій (оновлення Docker) або налаштування правильного драйвера/режиму cgroup для вашого дистрою. Не «вирубуйте» контролі ресурсів для задоволення цієї проблеми — якщо вам подобається рулетка продуктивності.

Завдання 13: Шукати корупцію або часткові записи після втрат живлення

cr0x@server:~$ journalctl -u docker -b --no-pager | tail -n 20
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=error msg="failed to load container metadata" error="unexpected end of JSON input"
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=fatal msg="Error starting daemon: error while opening volume store metadata database"

Рішення: Корупція метаданих — річ реальна. Тепер ви вирішуєте: відновити з бекапу, вибірково видалити пошкоджений об’єкт або перебудувати стан Docker. Вибір залежить від того, чи можете ви дозволити собі втрату локальних образів/томів.

Завдання 14: Запустити dockerd напряму в режимі dry-run (корисно, коли systemd ховає stderr)

cr0x@server:~$ sudo dockerd --debug --validate --config-file=/etc/docker/daemon.json
unable to configure the Docker daemon with file /etc/docker/daemon.json: the following directives are specified both as a flag and in the configuration file: hosts

Рішення: У вас конфліктуючі джерела конфігу (флаги systemd ExecStart vs daemon.json). Видаліть одне джерело правди. В продакшні я надаю перевагу лишати hosts у systemd і тримати daemon.json для налаштувань демона, не для слушателів.

Завдання 15: Перевірити конфлікти портів (поширено з старими прапорами dockerd)

cr0x@server:~$ sudo ss -ltnp | grep -E ':2375|:2376' || true
LISTEN 0      4096         0.0.0.0:2375      0.0.0.0:*    users:(("dockerd",pid=902,fd=7))

Рішення: Якщо старий процес dockerd все ще прив’язаний (або інший сервіс), новий демон не може забіндитись. Коректно вбийте зайвий процес, а потім виправте юніт, щоб не запускати кілька демонів одночасно.

Завдання 16: Безпечно звільнити місце, не знищивши все

cr0x@server:~$ sudo du -sh /var/lib/docker/* 2>/dev/null | sort -h | tail -n 10
2.1G	/var/lib/docker/containers
12G	/var/lib/docker/overlay2
18G	/var/lib/docker/volumes

cr0x@server:~$ sudo find /var/lib/docker/containers -name '*-json.log' -size +200M -printf '%p %s\n' | head
/var/lib/docker/containers/2f3.../2f3...-json.log 987654321

Рішення: Якщо логи контейнерів — винуватець, злештуйте логи, а не видаляйте каталоги контейнерів.

cr0x@server:~$ sudo truncate -s 0 /var/lib/docker/containers/2f3.../2f3...-json.log

Рішення: Спочатку запустіть демон, потім налаштуйте ротацію логів належним чином. Переповнення диска — це аварія; ідеальна гігієна може почекати годину.

Великі режими відмов (як вони виглядають у логах)

Збої при старті демона Docker групуються в кілька кошиків. Впізнайте кошик — і ви скоротите інцидент удвічі.

1) Парсинг конфігу та конфлікти налаштувань

Типові рядки в логах:

  • unable to configure the Docker daemon with file ...: invalid character
  • directives are specified both as a flag and in the configuration file
  • unknown log opt після зміни версії

Що насправді відбувається: Docker суворий щодо синтаксису JSON і щодо дубльованих налаштувань. Флаги systemd теж — «налаштування».

Філософія виправлення: Одне джерело правди. Тримайте daemon.json мінімальним; ставте слухачі (-H) у systemd або навпаки, але не розпилюйте їх між обома.

2) Збої драйвера сховища (overlay2, devicemapper, btrfs, zfs)

Типові рядки в логах:

  • error initializing graphdriver
  • overlay2: failed to mount
  • failed to register layer

Що насправді відбувається: Ядро й файлова система домовляються про функції. Якщо вони не згодні, overlayfs повертає «invalid argument», а Docker переводить це в відчай.

Філософія виправлення: Підтвердіть тип файлової системи/опції й підтримку ядра. Не міняйте драйвер сховища під час інциденту, якщо не готові втратити локальні образи й можливо томи.

3) Місткість і стан файлової системи

Типові рядки в логах:

  • no space left on device
  • read-only file system після помилки вводу/виводу
  • database is locked або часткові читання метаданих після аварійного вимкнення

Що насправді відбувається: Docker потребує багато стану. Якщо сховище хоста не може писати надійно, запуск стане першою жертвою.

Філософія виправлення: Відновіть можливість запису (звільнення місця, fsck, перемонтування, виправлення диска). Лише потім розглядайте Docker-специфічні ремедії.

4) Збої залежностей runtime/containerd

Типові рядки в логах:

  • failed to dial "/run/containerd/containerd.sock"
  • containerd: connect: no such file or directory

Що насправді відбувається: Docker делегує функції рантайму. Якщо containerd відсутній, несумісний або не працює — Docker не зможе продовжити.

Філософія виправлення: Розглядайте containerd як сервіс-пререквізит. Вирівняйте версії через пакетний менеджер і тримайте юніт здоровим.

5) Помилки ініціалізації мережі (iptables/nftables/firewalld)

Типові рядки в логах:

  • failed to create NAT chain DOCKER
  • iptables: No chain/target/match by that name
  • Chain already exists з бекендом nf_tables

Що насправді відбувається: Docker намагається запрограмувати NAT і фільтри. Якщо інший актор керує цими таблицями по-іншому (або бекенд iptables змінився), Docker не може створити те, що очікує.

Філософія виправлення: Визначте власника правил. Якщо треба втрутитися — робіть це вибірково і документуйте. Випадкові очищення правил — це як відрубати SSH собі ж.

6) Права, LSM і створення сокета

Типові рядки в логах:

  • can't create unix socket /var/run/docker.sock: permission denied
  • apparmor="DENIED" або SELinux AVC denials

Що насправді відбувається: Docker має створити привілейований сокет і простори імен монтування. Модулі безпеки й права файлової системи можуть зупинити його.

Філософія виправлення: Читайте відмову. Виправляйте політику/контекст/власність. Вимикати SELinux «через Docker» — як знімати датчики диму через пригорання тосту.

Одна цитата, бо це досі робота: “Hope is not a strategy.” — Gene Kranz

Поширені помилки: симптом → причина → виправлення

Ці ситуації постійно виникають, бо їх легко створити і важко діагностувати під тиском.

1) Docker застряг у start-limit-hit

Симптом: systemctl показує start-limit-hit і відмовляється запускатися знову.

Коренева причина: Docker кілька разів аварійно завершувався; systemd припинив перезапуски.

Виправлення: Виправте основну помилку спочатку, потім:

cr0x@server:~$ sudo systemctl reset-failed docker
cr0x@server:~$ sudo systemctl start docker

2) «invalid character» або помилки JSON при старті

Симптом: Docker падає миттєво після зміни конфігу.

Коренева причина: Неправильний JSON, коментарі в JSON, зайві коми або неправильні типи.

Виправлення: Валідуйте файл, потім виправте:

cr0x@server:~$ sudo python3 -m json.tool /etc/docker/daemon.json

3) overlay2 «failed to mount» / «invalid argument»

Симптом: ініціалізація graphdriver завершується з помилкою, mount overlay2 не вдається.

Коренева причина: Непідтримувана файлова система для upperdir (поширено з NFS), XFS ftype=0 або невідповідність ядро/ФС.

Виправлення: Розмістіть data-root на підтримуваній локальній файловій системі (ext4, XFS з ftype=1). Перевірте за допомогою xfs_info і dmesg. За потреби мігруйте стан.

4) Помилки ланцюгів iptables після змін у фаєрволі

Симптом: Docker падає з помилками створення NAT-ланцюгів.

Коренева причина: Конфліктуючі менеджери фаєрволу або зміна бекенду iptables (legacy vs nf_tables).

Виправлення: Вирівняйте інструменти iptables і власність правил. У контрольованому середовищі встановіть консистентний бекенд і зробіть так, щоб firewalld/kube/Docker співіснували свідомо.

5) «permission denied» на /var/run/docker.sock

Симптом: Docker не може створити свій сокет.

Коренева причина: Неправильні права на підшляхи /var/run, застарілий сокет із неправильним власником або відмова LSM.

Виправлення: Видаліть застарілий сокет (якщо Docker зупинений), виправте власність, ліквідуйте AppArmor/SELinux відмови. Не ставте chmod 777 і не радійте цьому.

6) Docker падає після переміщення data-root на «швидке сховище»

Симптом: Docker працював; після переміщення –data-root на нове сховище він не стартує.

Коренева причина: Нове монтування — мережеве сховище або відформатоване без потрібних функцій.

Виправлення: Переоцініть сховище. Горячі шляхи Docker вимагають низької латентності локального диска. Якщо мережеве сховище необхідне — використовуйте його для томів, а не для overlay-шер.

7) Диск повний і Docker не стартує після спроб очищення

Симптом: Ви видалили «дещо», Docker все ще не запускається, і тепер метадані виглядають пошкодженими.

Коренева причина: Видалення випадкових файлів у /var/lib/docker ламає консистентність метаданих.

Виправлення: Зупиніть демон. Відновіть з бекапу, якщо є. Якщо ні — прийміть, що перебудова (повне очищення data-root) може бути безпечнішим, ніж продовження часткового лікування.

8) Помилки cgroup на нових дистрибутивах

Симптом: Помилки про те, що devices cgroup не змонтовано, або невідповідність драйвера cgroup.

Коренева причина: Версія Docker не сумісна з дефолтами cgroups v2 або неправильна конфігурація драйвера cgroup.

Виправлення: Оновіть Docker до версії, що підтримує режим cgroup вашого дистрибутиву, і тримайте конфіг консолідованим по флоту.

Жарт #1: Якщо ваш «фікс» — перезапуск Docker, доки воно не запрацює, ви по суті граєте на автоматі зі правами root.

Три міні-історії з корпоративного життя

Міні-історія 1: Аутедж, спричинений неправильною припущенням

Команда мала план: перемістити data-root Docker з системного диска на більший спільний монтувальний шлях. Команда зі сховищ пообіцяла, що це «просто як диск». Він був змонтований через NFS, але ніхто прямо не сказав «NFS» у запиті на зміну. Усі припускали «сховище — це сховище».

Міграція пройшла в тихе вікно. Вони rsync-нули /var/lib/docker на /mnt/docker-data, додали systemd override з –data-root і перезапустили. Docker не повернувся. systemd сказав «failed to mount overlay». On-call витратив 40 хвилин на читання документації overlay2 і модулів ядра.

Прорив прийшов із dmesg, а не з логів Docker: overlayfs відкинув upperdir, бо файлова система не була підтримана. NFS підходить для масивного зберігання. Він не підходить для union файлової системи шарів Docker. Неправильне припущення не було «overlay2 ненадійний». Неправильне припущення — «NFS поводиться як ext4».

Вони відкотили на локальний XFS з потрібними фічами і використовували NFS лише для томів додатків, чітко розмежувавши межі. Аутедж закінчився. Постмортем завершився новим правилом: у change request обов’язково вказувати типи сховищ. «Shared mount» — це не тип.

Міні-історія 2: Оптимізація, що обернулась проти

Інженер, орієнтований на продуктивність, хотів швидшого старту контейнерів. Він помітив високу зміну в директорії overlay2 і вирішив налаштувати монтування, щоб зменшити записову ампліфікацію. «Оптимізація» включала перенесення Docker на файлову систему з агресивними опціями і вимкнення деяких метаданих, які він вважав накладними.

У dev з небагатьма контейнерами це виглядало добре. Потім продакшн: сотні контейнерів, часті pull’и образів, багато дрібних операцій з файлами. Через кілька днів вузол почав кидати періодичні помилки I/O. Після жорсткого ребуту Docker не запустився. Логи показували помилки реєстрації шарів і помилки бази метаданих.

Причина була проста. Оптимізація зменшила запас міцності: система стала чутливішою до втрати живлення й крайових випадків файлової системи. Кошт декількох відсотків продуктивності — значно вищий ризик корупції й важчий шлях відновлення.

Вони відкотили зміни монтувань, перебудували вузол і ввели правило: якщо змінюєш субстрат сховища під Docker, роби це з документованою матрицею сумісності і планом відкату. Перф-виграші є, але «швидко й крихко» — погана торгівля в продакшн.

Міні-історія 3: Нудна, але правильна практика, що врятувала день

Інша організація мала звичку, про яку ніхто не хвалився: вони збирали бут-логи критичних сервісів і відправляли їх у центральне місце. Не лише аплікейшн-логи — також логи systemd юнітів і повідомлення ядра. Це було нудно. Це також працювало.

Одного ранку частина вузлів перестала запускати Docker після рутинного оновлення ОС. Початковий інстинкт був «регресія Docker». Але таймлайн у логах показав інше: Docker впав відразу після перезавантаження фаєрвола на буті. Бекенд iptables змінився, і менеджер фаєрвола почав попередньо створювати ланцюги в спосіб, який Docker не сприймав.

Тому що вони мали логи, не було довгих суперечок. Вони знайшли точку зміни, відтворили на канарці і впровадили консистентну конфігурацію бекенду iptables. Docker повернувся без дотиків до сховища, образів чи робочих навантажень контейнерів.

Ця практика не запобігла відмові. Вона запобігла тривалій аврагії. У продакшні час до розуміння — це половина інциденту.

Чеклісти / покроковий план

Чекліст A: Запустити Docker знову (мінімальні безпечні кроки)

  1. Припиніть треш. Якщо сервіс у циклі падінь, зупиніть його, поки розбираєтесь.
    cr0x@server:~$ sudo systemctl stop docker
    
  2. Прочитайте журнал один раз, правильно.
    cr0x@server:~$ journalctl -u docker -b --no-pager -n 200
    

    Рішення: Визначте кошик: конфіг, сховище, місткість, мережа, права, залежність.

  3. Перевірте диск і іноди на файловій системі data-root.
    cr0x@server:~$ df -h /var/lib/docker; df -i /var/lib/docker
    

    Рішення: Якщо повно — звільніть місце, не видаляючи випадкові дані. Обрізайте логи; видаляйте відомі великі артефакти обережно.

  4. Валідуючий daemon.json, якщо існує.
    cr0x@server:~$ test -f /etc/docker/daemon.json && sudo python3 -m json.tool /etc/docker/daemon.json
    

    Рішення: Виправте помилки парсингу; усуньте дублікати з systemd-флагами.

  5. Підтвердіть, що containerd здоровий.
    cr0x@server:~$ systemctl status containerd --no-pager -l
    

    Рішення: Якщо потрібно — виправте containerd першочергово.

  6. Очистіть обмеження старту systemd після виправлення.
    cr0x@server:~$ sudo systemctl reset-failed docker
    
  7. Запустіть Docker і дивіться логи в реальному часі 30 секунд.
    cr0x@server:~$ sudo systemctl start docker
    cr0x@server:~$ journalctl -u docker -f --no-pager
    

    Рішення: Якщо знову падає, ви тепер зловили точну точку переходу без археології скролінгу.

Чекліст B: Якщо підозрюється корупція сховища (будьте обережні)

  1. Зніміть снапшот або скопіюйте докази перш ніж щось робити (якщо можете). Хоча б захопіть логи та поточний розподіл розмірів /var/lib/docker.
  2. Не видаляйте випадкові каталоги під /var/lib/docker, поки dockerd працює. Зупиніть його.
  3. Визначте, чи важливі томи на цьому хості. У деяких середовищах збережені дані лежать у Docker volumes; в інших — ні. Ваш план відновлення залежить від цього.
  4. Віддавайте перевагу перебудові вузла над ремісничим ремонтом, коли хости — «корови». Обирайте обережне відновлення, коли хост — «пет».

Чекліст C: Якщо підозрюється iptables/мережа

  1. Підтвердіть, що помилка Docker згадує iptables/nftables.
  2. Перевірте бекенд iptables і поточні ланцюги.
  3. Визначте іншого менеджера правил (firewalld, kube-proxy, кастомні скрипти).
  4. Зробіть власність правил явною, потім перезапустіть Docker.

Жарт #2: Мережа Docker проста, поки не стає складною — тоді це інтерпретативний танець від iptables.

Питання й відповіді

1) Чи запускати dockerd вручну для дебагу?

Так, коротко, якщо systemd ховає stderr або ви підозрюєте конфлікти конфігурацій. Використовуйте --debug і зупиніть юніт systemd спочатку, щоб уникнути двох демонів, що б’ються за той самий сокет.

2) Безпечно видаляти /var/lib/docker, щоб «виправити»?

Безпечно лише якщо ви свідомо витираєте локальні образи, контейнери й можливо томи (залежно від налаштувань). Це крайній засіб для швидкого відновлення на безстанкових вузлах, а не стандартне рішення.

3) Docker каже overlay2 failed to mount. Чи Docker зламався?

Зазвичай ні. Це частіше несумісність файлової системи/ядра (XFS ftype, непідтримуваний upperdir або опції монтування). Перевірте dmesg для реальної скарги ядра.

4) Чому Docker падає через iptables під час старту? Хіба він не може працювати без NAT?

Класичне мостове мережування Docker залежить від правил iptables. Якщо Docker не може запрограмувати NAT/фільтри, він відмовляється запускати мережу коректно і може не запускати демон, щоб уникнути напівробочого стану.

5) Я змінив daemon.json і тепер Docker не стартує. Яка найшвидша перевірка здорового глузду?

Валідуйте JSON парсером:

cr0x@server:~$ sudo python3 -m json.tool /etc/docker/daemon.json

Якщо помилка — виправте синтаксис. Якщо успіх — шукайте конфлікти директив із системд-флагами.

6) Docker не запускається після оновлення ОС. Хто ймовірний винуватець?

Поширені винуватці: зміни за замовчуванням cgroups v2, перемикання бекенду iptables і старі override у systemd drop-ins. Почніть з systemctl cat docker і журналу.

7) Чи containerd може бути запущений, а Docker все одно застрягати?

Абсолютно. Здоров’я containerd прибирає один клас відмов. Docker все одно може впасти на ініціалізації драйвера сховища, мережевих правилах, правах сокета або парсингу daemon.json.

8) Як зрозуміти, що диск «достатньо повний», щоб зламати Docker?

Якщо вільне місце вимірюється сотнями МБ або іноди вичерпані, Docker може не стартувати або поводитися невірно. Перевіряйте і df -h, і df -i. Також слідкуйте за перемонтуванням у режим read-only після помилок I/O.

9) Що робити, якщо docker info зависає замість того, щоб падати?

Якщо CLI зависає, зазвичай воно чекає на сокет. Перевірте, чи демон працює (systemctl is-active docker) і чи існує сокет (ls -l /var/run/docker.sock). Зависання — це часто «демон не відповідає», а не «CLI зламався».

10) Чи rootless Docker менш схильний до відмов?

Він падає по-іншому. Ви зменшуєте зону можливого ураження привілеями, але додаєте залежність від користувацьких сервісів, делегування cgroup і per-user runtime директорій. Добре, коли він спроєктований для цього; заплутано, якщо його прилаштували посеред процесу.

Наступні кроки, які реально зменшать інциденти

Запуск Docker — це негайна перемога. Попередити наступний «демон впав» — справжня робота. Ось що я б зробив після втихання пилу інциденту:

  1. Кодувати швидкий план діагностики у вашому ранбуку з дистрою-специфічними шляхами й рішеннями. Команди вище — це базис; адаптуйте під себе.
  2. Уніфікувати джерело конфігу Docker: оберіть daemon.json для налаштувань демона і systemd drop-ins для ExecStart-флагів, або навпаки — просто не мішайте.
  3. Розміщувати стан Docker на правильному сховищі: локальний ext4 або XFS з потрібними фічами, моніторити місткість і іноди. Тримайте overlay-слої поза мережевими монтуваннями.
  4. Контролювати ріст логів: налаштуйте ротацію логів контейнерів і моніторинг /var/lib/docker/containers/*-json.log. Переповнення диска — це опційна аварія.
  5. Зробити власність фаєрволу явною в дизайні платформи: Docker, firewalld, Kubernetes і агенти безпеки можуть співіснувати, але лише якщо явно розподілити, хто пише які правила.
  6. Практикувати відновлення на непроизводчому вузлі: симулювати зламаний daemon.json, переповнений диск і конфлікт iptables. Ваше майбутнє «я» буде вдячне і трохи менш кофеїнове.
← Попередня
Бенчмаркінг ZFS: правила, що запобігають фейковим результатам
Наступна →
Підказки без бібліотек: позиціонування, стрілка та доступні ARIA-патерни

Залишити коментар