Ви на виклику. Деплой не відбувся. CI червоний. Контейнери, які вчора запускалися без проблем, раптом відмовляються стартувати з помилкою no space left on device. Ви підключаєтесь по SSH, виконуєте df -h, і диск виглядає… відносно нормально. Або ще гірше: він повний, і ви не розумієте, що його заповнило, бо «ми запускаємо лише кілька контейнерів».
Docker — гарний фокусник. Він вміє створювати додатки. Він також вміє тихо зменшувати диск — у різних шарах зберігання, логах, кешах і метаданих. Трюк у тому, щоб знати, куди дивитися і які очищення безпечні в продакшені.
Швидкий план діагностики
Це потік «викрутимося за 10 хвилин». Він пріоритезує перевірки, які скажуть вам, чи проблема в байтах диска, в інодах або в особливостях файлової системи (нюанси overlay, метадані thinp, квоти проектів).
По-перше: підтвердіть, що саме заповнене (байти проти інодів проти монту)
- Перевірте вільні байти:
df -hна відповідному монту (/,/var,/var/lib/dockerта будь-якому виділеному диску для Docker). - Перевірте іноди:
df -i. Якщо іноди на 100%, ви можете отримати «немає місця» при наявності гігабайтів вільного простору. - Підтвердіть Docker root:
docker info→Docker Root Dir. Люди перевіряють/і забувають, що Docker на/var(або навпаки).
По-друге: визначте, яка категорія зростає
- Власна звітність Docker:
docker system df -v, щоб побачити образи, контейнери, томи та кеш збірки. - Реальність файлової системи:
du -xhd1 /var/lib/docker(або вашого Docker root), щоб зрозуміти, де байти реально живуть. Числа Docker можуть відставати від реального стану, особливо щодо логів. - Логи: перевірте JSON-логи контейнерів або використання journald. Логи — найпоширеніший «ми про це не подумали» пожирач диска.
По-третє: усувайте проблему у найменш руйнівному порядку
- Зупиніть кровотечу: обертайте логи, обмежте драйвер логів або притримайте галасливі додатки.
- Звільніть безпечний простір: очистіть кеш збірки та dangling-образи. Уникайте знищення томів, якщо не впевнені.
- Вирішіть структурні проблеми: перемістіть Docker root на більший диск, додайте моніторинг, квоти, встановіть політику зберігання логів і виправте спаунер CI-білдерів.
Жарт №1: Диск як мінібар у готелі — ніхто не пам’ятає, що користувався ним, поки не прийшов час виїзду.
Що насправді означає «no space left on device»
Це повідомлення бреше шляхом опущення деталей. Воно може означати:
- Немає вільних блоків на файловій системі, яка лежить під writable-слоем Docker, томом або тимчасовою директорією.
- Немає вільних інодів (ви не можете створити нові файли, навіть якщо є байти).
- Досягнута квота (квоти проектів, XFS-квоти або обмеження метаданих драйвера зберігання).
- Метадані thin pool заповнені (поширено при старих налаштуваннях devicemapper).
- Повний інший монтаж, ніж той, який ви перевіряли (наприклад,
/varповний, а/— ні). - Обмеження файлової системи overlay, що проявляються як помилки простору (наприклад, занадто багато шарів або copy-up, що різко збільшує використання).
Операційно: трактуйте це як «ядро відмовило в виділенні». Ваше завдання — з’ясувати яке виділення і воно відбувалося.
Цитата, яку варто тримати на стікері в датацентрі:
«Надія — не стратегія.» — перефразована ідея, яку часто приписують лідерам з надійності в операціях
Якщо ваша стратегія управління диском — «попрунимо, коли болітиме», ви вже працюєте на надії.
Практичні завдання: команди, виводи та рішення
Це реальні виконувані команди. Кожна містить, що означає вивід і яке рішення з нього випливає. Використовуйте їх по черзі, а не хаотично, як єнот в серверній.
Завдання 1: Визначте повну файлову систему
cr0x@server:~$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p2 80G 62G 14G 82% /
/dev/nvme1n1p1 200G 196G 4.0G 99% /var/lib/docker
tmpfs 16G 1.2G 15G 8% /run
Значення: Ваш диск даних Docker повний (/var/lib/docker на 99%). Коренева файлова система — не головна проблема.
Рішення: Зосередьтеся на використанні Docker root; не витрачайте час на очищення /.
Завдання 2: Перевірка виснаження інодів (хитра помилка «немає місця»)
cr0x@server:~$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/nvme0n1p2 5242880 841120 4401760 17% /
/dev/nvme1n1p1 13107200 13107200 0 100% /var/lib/docker
Значення: Файлова система Docker витратила іноди, а не блоки. Часто трапляється з мільйонами дрібних файлів (node_modules, розпакування шарів образів, кеші збірки).
Рішення: Прунінг може допомогти, але в довгостроковій перспективі ймовірно потрібно створити файлову систему з більшою щільністю інодів (ext4) або перейти на XFS (динамічні іноди) і зменшити кількість дрібних файлів.
Завдання 3: Підтвердіть фактичний Docker root
cr0x@server:~$ docker info --format '{{.DockerRootDir}}'
/var/lib/docker
Значення: Docker погоджується, що використовує /var/lib/docker.
Рішення: Всі наступні аналізи диска мають орієнтуватися на цей шлях (якщо ви не використовуєте альтернативний рантайм або rootless Docker).
Завдання 4: Отримайте високорівневу звітність зайнятості простору Docker
cr0x@server:~$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 48 12 72.4GB 41.8GB (57%)
Containers 18 7 3.1GB 2.2GB (71%)
Local Volumes 64 9 88.6GB 55.0GB (62%)
Build Cache 214 0 61.3GB 61.3GB
Значення: Томи і кеш збірки домінують. Це не переважно «занадто багато контейнерів».
Рішення: Почніть з prune кешу збірки (зазвичай безпечно), потім ретельно перевірте томи перед очищенням.
Завдання 5: Поглиблена звітність Docker
cr0x@server:~$ docker system df -v
Images space usage:
REPOSITORY TAG IMAGE ID CREATED SIZE SHARED SIZE UNIQUE SIZE CONTAINERS
app/api prod 2a1b3c4d5e6f 2 days ago 1.21GB 820MB 390MB 4
app/api old 7f6e5d4c3b2a 3 weeks ago 1.18GB 820MB 360MB 0
Build cache usage:
CACHE ID CACHE TYPE SIZE CREATED LAST USED USAGE SHARED
k9x... regular 2.3GB 2 weeks ago 2 weeks ago 1
...
Значення: Ви помітите невикористані теги образів (0 контейнерів) і давні кеші.
Рішення: Видаліть невикористані образи та кеші в першу чергу; розгляньте політику зберігання останніх N версій на вузол.
Завдання 6: Знайдіть найбільші директорії під Docker root (перевірка реальності)
cr0x@server:~$ sudo du -xhd1 /var/lib/docker | sort -h
1.1G /var/lib/docker/network
3.6G /var/lib/docker/containers
62G /var/lib/docker/buildkit
112G /var/lib/docker/overlay2
181G /var/lib/docker
Значення: Overlay2 і buildkit — головні «важковаговики». Директорія containers також непогана за розміром (часто через логи).
Рішення: Якщо containers велика, перевірте логи. Якщо buildkit велика — пруньте кеш збірки. Overlay2 вимагає акуратного очищення через Docker, а не ручного видалення.
Завдання 7: Знайдіть найбільші файли логів контейнерів (драйвер json-file)
cr0x@server:~$ sudo find /var/lib/docker/containers -name "*-json.log" -printf "%s %p\n" | sort -nr | head
21474836480 /var/lib/docker/containers/4c2.../4c2...-json.log
9876543210 /var/lib/docker/containers/91a.../91a...-json.log
1234567890 /var/lib/docker/containers/ab7.../ab7...-json.log
Значення: Один контейнер записав ~20GB логів. Це вже не «трохи шумить». Це повідомлення про евакуацію диска.
Рішення: Негайно вкоротіть цей лог (тимчасово безпечно), потім впровадьте ротацію і виправте галасливий додаток.
Завдання 8: Безпечно вкоротити занадто великий лог контейнера без перезапуску Docker
cr0x@server:~$ sudo truncate -s 0 /var/lib/docker/containers/4c2.../4c2...-json.log
cr0x@server:~$ sudo ls -lh /var/lib/docker/containers/4c2.../4c2...-json.log
-rw-r----- 1 root root 0 Jan 2 11:06 /var/lib/docker/containers/4c2.../4c2...-json.log
Значення: Ви миттєво звільнили простір; файл тепер порожній. Контейнер продовжує писати логи.
Рішення: Розглядайте це як тимчасовий пластир. Заплануйте правильне виправлення: опції логування, вибір драйвера або зменшення логів на рівні додатку.
Завдання 9: Підтвердіть, який контейнер відповідає за галасливу директорію логів
cr0x@server:~$ docker ps --no-trunc --format 'table {{.ID}}\t{{.Names}}'
CONTAINER ID NAMES
4c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b api-prod-1
Значення: Найгірший порушник логів — api-prod-1.
Рішення: Перевірте рівень логування додатку, піки запитів, повторні спроби або цикли помилок. Проблеми з диском часто — симптом помилки вище по ланцюжку.
Завдання 10: Перевірте використання дискового простору journald (якщо використовується драйвер journald)
cr0x@server:~$ journalctl --disk-usage
Archived and active journals take up 18.7G in the file system.
Значення: Journald займає значний простір. Це можуть бути Docker-логи, системні логи або й те, й інше.
Рішення: Встановіть обмеження зберігання в конфігурації journald і вакуумуйте старі логи. Не просто видаляйте файли під /var/log/journal, поки journald працює.
Завдання 11: Вакуум journald, щоб звільнити простір
cr0x@server:~$ sudo journalctl --vacuum-size=2G
Deleted archived journal /var/log/journal/7a1.../system@000...-000...journal
Vacuuming done, freed 16.7G of archived journals on disk.
Значення: Простір було безпечно звільнено засобами journald.
Рішення: Впровадьте постійну політику journald (обмеження за розміром/часом), щоб це не повторилося наступного тижня.
Завдання 12: Prune кеш збірки (зазвичай низький ризик, висока віддача)
cr0x@server:~$ docker builder prune --all --force
Deleted build cache objects:
k9x...
m2p...
Total reclaimed space: 59.8GB
Значення: Ви відновили майже 60GB, видаливши кеш збірки. Зборки можуть сповільнитись, доки кеш не прогріється знову.
Рішення: Якщо це CI-білдер, заплануйте періодичний prune або обмежте кеш політикою, замість панічного очищення.
Завдання 13: Prune невикористані образи (відносно безпечно, але розумійте стратегію деплою)
cr0x@server:~$ docker image prune -a --force
Deleted Images:
deleted: sha256:7f6e5d4c3b2a...
deleted: sha256:1a2b3c4d5e6f...
Total reclaimed space: 28.4GB
Значення: Docker видалив образи, на які не посилається жоден контейнер. Якщо ви покладаєтесь на швидкий rollback, тримаючи старі образи локально — ви щойно видалили цю страховку.
Рішення: На продакшн вузлах розгляньте зберігання останніх N версій або покладанняся на регістр з гарантованою доступністю та хорошим кешуванням.
Завдання 14: Знайдіть великі томи та хто їх використовує
cr0x@server:~$ docker volume ls
DRIVER VOLUME NAME
local api_db_data
local prometheus_data
local tmp_ci_run_1738
cr0x@server:~$ sudo du -sh /var/lib/docker/volumes/*/_data | sort -h | tail
6.2G /var/lib/docker/volumes/prometheus_data/_data
48G /var/lib/docker/volumes/api_db_data/_data
71G /var/lib/docker/volumes/tmp_ci_run_1738/_data
Значення: Один тимчасовий CI-том — 71GB. Ймовірно це сміття. Том бази даних великий, але, ймовірно, легітимний.
Рішення: Перевірте прив’язки перед видаленням: ідентифікуйте, які контейнери використовують тимчасовий том. Не видаляйте томи баз даних легковажно.
Завдання 15: Зіставте томи з контейнерами (щоб уникнути видалення живого стану)
cr0x@server:~$ docker ps -a --format '{{.ID}} {{.Names}}' | head
a1b2c3d4e5f6 api-prod-1
d4e5f6a1b2c3 ci-runner-1738
...
cr0x@server:~$ docker inspect -f '{{.Name}} -> {{range .Mounts}}{{.Name}} {{end}}' d4e5f6a1b2c3
/ci-runner-1738 -> tmp_ci_run_1738
Значення: Великий тимчасовий том належить конкретному CI-runner контейнеру (можливо вже зупиненому, можливо ще використовуваному).
Рішення: Якщо контейнер зупинений і том справді епhemeral — видаліть контейнер і том. Якщо він працює — виправте завдання, яке пише так багато даних.
Завдання 16: Видаліть підтверджений сирітський том
cr0x@server:~$ docker rm -f ci-runner-1738
ci-runner-1738
cr0x@server:~$ docker volume rm tmp_ci_run_1738
tmp_ci_run_1738
Значення: Контейнер і том видалені; простір на диску має зменшитися.
Рішення: Додайте автоматизацію життєвого циклу для артефактів CI, щоб «тимчасові томи» не ставали постійними мешканцями.
Завдання 17: Одна команда для очищення очевидного сміття (використовуйте з розумом)
cr0x@server:~$ docker system prune --all --volumes --force
Deleted Containers:
...
Deleted Images:
...
Deleted Volumes:
...
Total reclaimed space: 132.6GB
Значення: Ви щойно видалили майже все невикористане, включно з томами. Це може бути катастрофічно, якщо ви помилково класифікували «невикористане».
Рішення: Використовуйте це лише на одноразових хостах (CI, dev-білдери) або коли перевірили безпеку томів. У продакшені віддавайте перевагу прицільному прунінгу.
Завдання 18: Перемістити Docker root на більший диск (доросле вирішення)
Коли ви постійно пруните, ви лікуєте симптоми. Іноді потрібно просто перемістити дані.
cr0x@server:~$ sudo systemctl stop docker
cr0x@server:~$ sudo rsync -aHAX --numeric-ids /var/lib/docker/ /mnt/docker-data/
cr0x@server:~$ sudo mkdir -p /etc/docker
cr0x@server:~$ sudo tee /etc/docker/daemon.json > /dev/null
{
"data-root": "/mnt/docker-data"
}
cr0x@server:~$ sudo systemctl start docker
cr0x@server:~$ docker info --format '{{.DockerRootDir}}'
/mnt/docker-data
Значення: Docker тепер використовує новий data root. Якщо контейнери не стартують, ймовірно, ви пропустили права, SELinux контексти або прапорці rsync.
Рішення: Це операція зміни конфігурації. Виконуйте у вікні технічного обслуговування й перевіряйте на канарці перед масовим запуском.
Три корпоративні міні-історії з полів
Міні-історія №1: Інцидент через хибні припущення (логи «не можуть бути такими великими»)
Компанія була в процесі міграції з VM у контейнери. Ключовий сервіс був стабільний роками, і контейнеризація робилася максимально мінімально: «підняти і перенести, не рефакторити». Це рішення саме по собі не було неправильним. Неправильним було припущення, яке до нього додали.
Вони думали, що логи «обробляються платформою», бо на старому VM образі був logrotate. У Docker додаток все ще писав у stdout/stderr. Платформа це «обробляла» — шляхом запису JSON-логів на диск назавжди, без ротації. Першого дня все було добре. На двадцятий день один вузол почав повертати 500. Оркестратор продовжував пересаджувати контейнери, бо «контейнери — це худоба». Вузол залишався повним, бо пересадка не видаляла лог-файли достатньо швидко, а нові контейнери продовжували писати в ту саму прірву.
Інженер на виклику перевірив df -h на /, побачив 40% вільного і оголосив «не диск». Вони пропустили, що Docker живе на /var, який був на іншому монту. Другий інженер запустив docker system df і нічого особливого не побачив — бо звіт Docker не «зауважив», що один лог-файл займає 20GB.
Виправлення було жорстко простим: вкоротити лог-файл, обмежити розмір логів і знизити рівень логування для гарячого циклу, який був безпечний на VM, бо там логи ротаціювалися. Пост-інцидентний крок був також простим і важливішим: записати, де живуть логи для кожного драйвера логування, і налаштувати алерти на їх зростання. Оце і є «платформова робота» насправді.
Міні-історія №2: Оптимізація, що повернулась бумерангом (кеш BuildKit усюди)
Інша команда пишалась швидкістю CI. Збори тривали кілька хвилин, в основному завдяки відмінному кешуванню BuildKit. Надто відмінному. Їхні билдери також запускали деякі довгоживучі сервіси (бо «у нас є вільні ресурси»), а билдерам дісталися великі локальні SSD. Здавалося ефективно: один тип машин, один золотий образ, все кудись заплановано.
Кеш ріс тихо. Мульти-арх збірки, часті оновлення залежностей і звичка тегувати кожен коміт створили високочастотний кеш. Тиждень це не помітно. Потім велика релізна гілка спричинила шквал збірок і варіантів шарів. Кеш роздувся і викинув диск за край у робочий час.
Більше болючого було не те, що диск заповнився. Більшою проблемою був другорядний ефект: як диск заповнювався, билдерам ставало повільно, завдання таймаутилися, повтори збільшували навантаження, і кеш зростав ще швидше. Система стала самопідживною петлею: «оптимізація» зробила відмову більш вибуховою.
Кінцеве рішення було не «прунь більше». Вони розділили ролі: виділені билд-ноди з плановим обмеженням кешу, виділені рантайми зі строгими правилами утримання образів і явні ліміти на логи. Також вони перестали удавати, що «швидкий билд» — це та сама метрика, що «стабільний билд».
Міні-історія №3: Нудна, але правильна практика, що врятувала ситуацію (квоти й алерти)
Одна фінансово-орієнтована внутрішня платформа мала непопулярну звичку: ставити квоти й пороги алертів на все. Розробники скаржилися, бо квоти здаються бюрократією, поки не зрозумієш зону ураження.
Вони налаштували ротацію логів для драйвера json-file Docker і також задали обмеження journald на хостах, що використовували journald. Налаштували алерти на використання /var/lib/docker, використання інодів і на top-N файлів логів контейнерів. Шум алертів був низьким, бо пороги налаштовано, і до алертів додано рукавиці дій (runbooks).
Одної п’ятниці ввечері сервіс почав висипати помилки через проблему з оновленням облікових даних downstream. На платформах інших команд така ситуація перетворилась би на «диск повний» плюс «додаток впав». На цій платформі файли логів досягли капа, логи ротувалися, диск залишився здоровим, а на виклик прийшов лише один алерт: «зростання помилок сервісу + збільшення об’єму логів». Вони вирішили проблему з обліковими даними. Без паніки з очищенням. Без розкопок файлової системи. Нудна надійність знову перемогла.
Поширені помилки: симптом → корінь → виправлення
1) «df показує вільне місце, але Docker каже, що немає місця»
Симптом: pull/build/start завершується з no space left on device; df -h на / показує багато вільного.
Корінь: Docker root на іншому монту (/var або виділений диск), або ви заповнюєте /tmp під час збірок.
Виправлення: docker info для Docker Root Dir; запустіть df -h на тому монту і на /tmp. Перемістіть data-root або збільшіть правильну файлову систему.
2) «Немає місця», але у вас гігабайти вільні
Симптом: Записи відмовляються; df -h показує вільні GB; помилки тривають.
Корінь: Виснаження інодів (df -i показує 100%) або метадані thin pool заповнені (devicemapper).
Виправлення: Якщо іноди: пруньте кеші з великою кількістю дрібних файлів і відтворіть файлову систему з відповідною щільністю інодів (або використовуйте XFS). Якщо devicemapper: мігруйте на overlay2 або розширте метадані thin pool.
3) «docker system prune нічого не звільнив»
Симптом: Ви прунули, але використання диска майже не змінилося.
Корінь: Винуватцем є логи або journald, або великі іменовані томи, прикріплені до працюючих контейнерів.
Виправлення: Перевірте /var/lib/docker/containers і використання journald; перевірте розміри томів під /var/lib/docker/volumes і зіставте томи з контейнерами.
4) «Ми видалили контейнери, але диск не впав»
Симптом: Видалення контейнерів не звільнило очікуваний простір.
Корінь: Томи зберігаються; образи зберігаються; кеш збірки зберігається; також видалені, але відкриті файли можуть тримати простір, поки процес не завершиться.
Виправлення: Перевірте томи і кеш збірки; якщо підозрюєте видалені-але-відкриті файли, перезапустіть винуватця (іноді демон Docker або рантайм контейнера) після безпечного очищення.
5) «Директорія overlay2 величезна; чи можемо її видалити?»
Симптом: /var/lib/docker/overlay2 домінує у використанні диска.
Корінь: Там живуть образні шари та записувані шари. Ручне видалення ламає стан Docker.
Виправлення: Використовуйте Docker-команди для прунінгу невикористаних образів/контейнерів; якщо стан пошкоджено, плануйте контрольований wipe-and-recreate для одноразових хостів, не для продакшн нод зі станом.
6) «Після переходу на journald логування диск все одно заповнюється»
Симптом: Ви змінили драйвер логування; використання диска продовжує зростати.
Корінь: Значення зберігання journald занадто ліберальні або включено персистентне зберігання журналів без обмежень.
Виправлення: Налаштуйте обмеження за розміром/часом у journald і перевіряйте journalctl --disk-usage.
7) «CI-білдери щотижня заповнюють диск»
Симптом: Вузли билдера заповнюються передбачувано.
Корінь: Утримання кешу BuildKit без обмежень; багато тулчейнів генерують багато унікальних шарів; надто багато тегів/гілок збирається на одному вузлі.
Виправлення: Запланований docker builder prune; відокремити білдери від рантайму; ввести політику утримання і/або періодично реконструювати білдери (immutable infrastructure тут дійсно допомагає).
8) «Простір звільнено, але сервіс все ще не працює»
Симптом: Ви звільнили дисковий простір, але контейнери й досі відмовляються стартувати або поводяться дивно.
Корінь: Пошкоджені метадані Docker, часткові pull-и або помилка на рівні додатку, яка спочатку спричинила надмірне логування.
Виправлення: Перевірте робочий контейнер з відомим добрим образом, перегляньте логи демона і вирішіть первинну проблему додатку (лімітування, storm повторних спроб, помилки аутентифікації). Диск був лише побічним ушкодженням.
Контрольні списки / покроковий план
Аварійний чекліст (продакшн вузол зараз повний)
- Підтвердіть монтаж: запустіть
df -hіdf -iна Docker root і/tmp. - Спочатку зупиніть неконтрольовані логи: знайдіть найбільші файли логів контейнерів; вкоротіть найгірші; зменшіть рівень логування, якщо безпечно.
- Відновіть безпечний простір: виконайте
docker builder prune --allна білдер-нодах; виконайтеdocker image prune -a, якщо розумієте вплив на rollback. - Аудит томів перед дією: ідентифікуйте найбільші томи і зіставте їх з контейнерами. Видаляйте лише підтверджені сирітські томи.
- Перевірте вільний простір: повторно виконайте
df -h. Тримайте принаймні кілька гігабайтів вільними; деякі файлові системи та демони поводяться погано біля 100%. - Стабілізація: перезапускайте дефектні компоненти лише після зняття тиску диска; уникайте флапінгу.
- Напишіть інцидент-ноту: що заповнило диск, як швидко це росло і яка політика запобігає повторенню.
Чекліст укріплення (щоб припинити повторення)
- Встановіть ротацію логів Docker: обмежте розмір і кількість файлів для json-file.
- Встановіть ретеншн для journald: обмежте зберігання і/або час, якщо використовуєте journald.
- Розділяйте обов’язки: білдери і рантайми не повинні бути на одній флоті, якщо ви не любите загадкове зростання.
- Встановіть політику прунінгу: запланований прунінг кешу збірки та правила утримання образів за роллю хоста.
- Перенесіть Docker root на виділене сховище: особливо при малих кореневих FS.
- Алертуйте по інодах і байтах: і додавайте runbook з цими командами.
- Вимірюйте головних порушників: найбільші томи, найбільші логи контейнерів, найбільші образи на хості.
- Проєктуйте на відмови: якщо downstream ламається і тригерить storm повторів, платформа має деградувати без саморуйнування.
Рекомендовані базові налаштування демона Docker (практичні дефолти)
Якщо ви використовуєте драйвер json-file, встановіть ротацію логів. Це найрентабельніший крок контролю диска.
cr0x@server:~$ sudo tee /etc/docker/daemon.json > /dev/null
{
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "5"
}
}
cr0x@server:~$ sudo systemctl restart docker
Значення: Файл логів кожного контейнера ротується приблизно при ~50MB, зберігаючи 5 файлів (~250MB на контейнер у найгіршому випадку).
Рішення: Налаштовуйте розміри відповідно до середовища. У продакшені зазвичай потрібне централізоване логування; локальні логи повинні бути буфером, а не архівом.
Цікаві факти та історичний контекст
- Факт 1: Ранні розгортання Docker часто використовували режим devicemapper loopback за замовчуванням, що було повільно і схильне до «містичних» помилок простору/метаданих під навантаженням.
- Факт 2: Перехід Docker на overlay2 як типовий вибір зробив зберігання швидшим і простішим, але також зробив copy-up поведінку частим сюрпризом для команд, що пишуть у файлову систему контейнера.
- Факт 3: Історично дефолтним драйвером логування Docker був json-file, що був оптимальний для простоти, а не для довготривалої гігієни диска.
- Факт 4: Популярність BuildKit зросла, бо він робив збірки швидшими і більш паралельними, але операційна ціна — управління кешем, особливо на шарінгових билдерах.
- Факт 5: Фраза «no space left on device» — це загальний errno (
ENOSPC), що повертає ядро, і її використовують не лише для «диска повного». - Факт 6: Виснаження інодів — стара Unix-проблема, яка не зникла; контейнери повернули її назад, бо витяг образів і екосистеми мов генерують величезну кількість дрібних файлів.
- Факт 7: Багато операторів важко вивчили, що «контейнери епhemeral» — це не про дані. Томи — це стан, а стан — назавжди, доки ви його не видалите.
- Факт 8: Власна звітність Docker (
docker system df) корисна, але не авторитетна; файлову систему слід вважати істинним джерелом, особливо стосовно логів і тимчасових поза-Docker файлів.
FAQ
1) Чому Docker каже «no space left on device», коли df -h показує простір?
Тому що ви перевірили невірний монтаж, або вичерпані іноди, або досягнута квота/обмеження метаданих. Завжди перевіряйте Docker root dir і виконуйте df -i.
2) Чи безпечно запускати docker system prune -a в продакшені?
Іноді. Команда видаляє невикористані образи, контейнери і мережі. Вона може зламати стратегії швидкого rollback і спричинити повільніші деплої через підкачування образів. Спочатку використовуйте прицільний прунінг.
3) Чи безпечно запускати docker system prune --volumes?
Тільки якщо ви перевірили, що «невикористані» томи справді придатні для видалення. «Unused» означає «не зараз посилається», а не «неважливі». Ось так губиться дані.
4) Чому мої логи контейнерів такі великі?
Бо json-file логування за замовчуванням необмежене, поки ви не встановите max-size і max-file. Також галасливий додаток може генерувати гігабайти на годину під час циклів помилок.
5) Якщо я вкорочу логи контейнера, чи зламається Docker або додаток?
Вкорочення json-файлу логів зазвичай безпечне як аварійний захід. Ви втрачаєте історичні логи, а додаток продовжує писати. Потім налаштуйте ротацію правильно.
6) Чому видалення контейнера не звільняє простір?
Бо простір, ймовірно, у томах, образах або кеші збірки. Також простір видалених файлів може залишатися зайнятим, якщо процес все ще має відкритий дескриптор.
7) Чому /var/lib/docker/overlay2 такий великий, хоча образів небагато?
Overlay2 містить і записувані шари, і вміст витягнутих шарів. Кілька «великих» образів плюс write-heavy контейнери легко можуть домінувати диском.
8) Як найкраще запобігти інцидентам диска на CI-білдерах?
Виділені білдери, запланований docker builder prune, обмежені кеші і періодичне реконструювання білдерів. Трактуйте кеш як споживний ресурс, а не як скарб.
9) Чи можна просто видаляти файли під /var/lib/docker вручну?
Не робіть цього. Ручне видалення часто корумпує стан Docker. Використовуйте Docker-команди або робіть контрольований wipe лише на дійсно одноразових хостах.
10) Скільки вільного простору слід тримати на Docker-хості?
Достатньо, щоб pulls/unpacks і сплески логів не штовхали вас до 100%. Практично: тримайте буфер у кілька гігабайтів і налаштуйте алерти задовго до критичної межі.
Висновок: наступні кроки, які реально запобігають повторенню
Коли Docker закінчує місце, це рідко «Docker великий» і майже завжди «ми не керували нудними речами». Логи, кеші та томи — нудні. Вони також — джерело інцидентів.
Ваші практичні наступні кроки:
- Поставте ліміт на логи сьогодні (ротація json-file і/або ретеншн journald). Це одразу виключає велику категорію відмов.
- Визначте ролі хостів: ноди рантайму не повинні накопичувати кеші збірки; білдери повинні мати плановий прунінг і передбачувані реконструкції.
- Алертуйте по байтах і інодах для Docker root файлової системи, а також на top container log sizes і найбільші томи.
- Перестаньте писати стан у записувані шари: свідомо використовуйте томи, монтуйте tmpfs для справді тимчасових даних і перевіряйте шляхи, куди пишуть ваші додатки.
- Коли очищуєте — будьте хірургами: спочатку кеші і невикористані образи, томи — лише за доказами.
Диск не гламурний. Через це він виграє багато боїв. Зробіть його чиєюсь відповідальністю — бажано вашою, поки це не стало вашими вихідними.