Docker build cache съел 38 ГБ: История детективного расследования
Как мы искали причину переполнения диска на production-сервере и почему первые подозреваемые оказались невиновны. Разбираемся с Docker build cache.
🚨 Проблема
Однажды утром получаю алерт с production-сервера:
⚠️ Диск заполнен на 82% (41 ГБ из 50 ГБ)
Проект весит локально всего ~700 МБ. Что могло занять 40+ гигабайт на сервере?
Началось расследование...
🔍 Подозреваемый #1: Docker логи
Первая гипотеза
"Наверняка логи! Docker же пишет логи в JSON-файлы, и они без ротации могут разрастись до гигабайт."
Проверяем:
sudo du -sh /var/lib/docker/containers/*/*-json.log
Результат:
du: cannot access '/var/lib/docker/containers/*/*-json.log': No such file or directory
Что? Логов вообще нет? Странно...
Почему так случилось?
Оказалось, что в нашей конфигурации Docker использует драйвер логирования journald, а не json-file. Логи уходят в systemd journal, а не в отдельные файлы.
Проверяем журнал:
sudo journalctl --disk-usage
Archived and active journals take up 139.4M in the file system.
Всего 139 МБ. Не то.
💡 Урок #1
Не все контейнеры используют JSON-логи по умолчанию. Зависит от настройки Docker daemon и дистрибутива Linux.
🔍 Подозреваемый #2: Nginx логи
Вторая попытка
"Ладно, может это Nginx? Access логи могут быть огромными на популярных сайтах."
sudo du -sh /var/log/nginx/*
Результат:
2.8M /var/log/nginx/access.log
9.0M /var/log/nginx/app_access.log
324K /var/log/nginx/app_error.log
4.0K /var/log/nginx/error.log
548K /var/log/nginx/tools_access.log
16K /var/log/nginx/tools_error.log
Итого: ~12 МБ. Смешно.
💡 Урок #2
Даже без logrotate, Nginx логи на небольших проектах не растут до критических размеров. Проблема явно не здесь.
🔍 Подозреваемый #3: Папки проекта
Третья гипотеза
"Может, это node_modules? Или какие-то build-артефакты накопились?"
sudo du -sh ~/project
cd ~/project && du -sh * | sort -rh
Результат:
6.4M /home/admin/project
Всего 6.4 МБ. Проект на сервере даже меньше, чем локально (нет node_modules).
🔍 Проверка очевидного
На этом этапе начинаем сомневаться в собственных глазах. Проверяем общую картину:
sudo du -sh /var/log /var/cache /home /usr /opt /var/lib/docker 2>/dev/null
164M /var/log
97M /var/cache
6.5M /home
1.1G /usr
16K /opt
346M /var/lib/docker ← Это интересно
Стоп. Docker занимает всего 346 МБ? Но диск-то заполнен на 41 ГБ!
Где остальные 39 гигабайт?
🎯 Настоящий виновник: Docker Build Cache
Прорыв в расследовании
Команда, которая всё прояснила:
docker system df -v
И вот что мы увидели:
Images space usage:
REPOSITORY SIZE
project-frontend 333MB
Containers space usage:
CONTAINER ID SIZE
a1b285cdab00 4.1kB
Build cache usage: 38.77GB ← !!!
38.77 ГИГАБАЙТ BUILD CACHE!
Что это такое?
Docker BuildKit кеширует слои образов для ускорения повторных сборок. Каждый раз, когда вы запускаете docker-compose up -d --build, создаются новые кеш-слои:
- Базовый образ Node.js (~500 МБ)
- Зависимости npm (~100 МБ)
- Build артефакты Next.js (~100 МБ)
- И так далее...
За 12 дней активной разработки и деплоев накопилось 150+ кеш-слоёв:
CACHE ID SIZE CREATED
qme90qh0zi44 1.03GB 12 days ago
huc1kcr0u8pe 562MB 12 days ago
trhcf0wunnw4 210MB 6 days ago
p0a0ayd9iij9 562MB 6 days ago
sbj6h9vhjuze 1.03GB 6 days ago
opq3zxhck5c6 1.03GB 3 days ago
# ... ещё 140+ строк
Почему кеш не очищается автоматически?
По умолчанию Docker НЕ удаляет build cache. Это сделано намеренно для ускорения сборок. Но на production-сервере с ограниченным диском это может стать проблемой.
✅ Решение
Очистка кеша (одной командой!)
docker builder prune -a -f
Результат:
Total reclaimed space: 38.77GB
Проверяем диск:
df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 50G 3.2G 47G 7% / ← С 82% до 7%!
Освободили почти 40 ГБ! 🎉
Что делает эта команда?
-a— удаляет ВСЕ неиспользуемые кеш-слои (не только "dangling")-f— force, без подтвержденияbuilder prune— очищает именно BuildKit cache (новый движок сборки)
Старый синтаксис vs новый
# ❌ Старый способ (может не сработать)
docker system prune -a -f
# ✅ Новый способ (Docker BuildKit)
docker builder prune -a -f
С Docker версии 23+ используется BuildKit по умолчанию, и кеш хранится отдельно.
🔄 Автоматизация
Чтобы проблема не повторилась, настраиваем автоматическую очистку:
sudo crontab -e
Добавляем:
# Очистка Docker build cache каждое воскресенье в 4:00
0 4 * * 0 docker builder prune -a -f
# Опционально: полная очистка неиспользуемых ресурсов
0 4 * * 0 docker system prune -f --filter "until=168h"
Альтернатива: Ограничение размера кеша
В /etc/docker/daemon.json:
{
"builder": {
"gc": {
"enabled": true,
"defaultKeepStorage": "10GB"
}
}
}
После перезапуска Docker:
sudo systemctl restart docker
Теперь кеш автоматически очищается при превышении 10 ГБ.
📊 Мониторинг дискового пространства
Создаём скрипт для регулярных проверок:
#!/bin/bash
# check-docker-space.sh
echo "=== Docker System Usage ==="
docker system df
echo -e "\n=== Build Cache Details ==="
docker builder du
echo -e "\n=== Disk Usage ==="
df -h /
Добавляем в cron:
# Проверка каждый день в 3:00, отправка на email
0 3 * * * /home/admin/check-docker-space.sh | mail -s "Docker Space Report" admin@example.com
💡 Что мы узнали
1. Docker Build Cache — скрытая угроза
На dev-машине с терабайтным диском вы его не заметите. Но на production VPS с 50 ГБ — критично.
2. Проверяйте неочевидное
Логи и образы — это очевидно. Build cache — нет. Всегда начинайте с:
docker system df -v
3. Автоматизация обязательна
Ручная очистка работает раз. Автоматизация — постоянно.
4. Мониторинг важнее оптимизации
Лучше получить алерт при 80% заполнения, чем искать проблему при 99%.
🎯 Финальный чеклист
После этого инцидента мы внедрили:
- ✅ Еженедельная очистка build cache через cron
- ✅ Ограничение размера кеша через daemon.json (10 ГБ)
- ✅ Мониторинг дискового пространства с алертами
- ✅ Логирование Docker с ротацией (на будущее)
- ✅ Документация для команды о проблеме
🔗 Полезные команды
# Проверка использования диска Docker
docker system df -v
# Проверка только build cache
docker builder du
# Очистка build cache
docker builder prune -a -f
# Полная очистка (осторожно!)
docker system prune -a --volumes -f
# Мониторинг в реальном времени
watch -n 5 'docker system df'
📚 Дополнительные материалы
Мораль истории: Не всегда виновны те, кого подозреваешь первыми. Docker build cache — молчаливый, но прожорливый житель production-серверов. Настройте автоочистку сейчас, а не когда диск заполнится на 99%. 🎯