Все статьи🇷🇺 Русский
6 мин

Docker build cache съел 38 ГБ: История детективного расследования

Как мы искали причину переполнения диска на production-сервере и почему первые подозреваемые оказались невиновны. Разбираемся с Docker build cache.

dockertroubleshootingproductiondisk-space

🚨 Проблема

Однажды утром получаю алерт с 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%. 🎯