Docker Engine 29: как изменения в хранении образов повлияют на ваши проекты

Анализируем важные изменения в Docker Engine 29, связанные с переходом на containerd как хранилище образов по умолчанию. Узнайте о проблеме дублирования слоев и способах решения.

Не указано

Docker Engine 29 перешел на containerd: почему ваши базовые слои теперь дублируются и как это исправить

⚡️ Новая эра контейнеризации: неожиданные последствия обновления

Вы установили Docker Engine 29 и столкнулись с пугающим увеличением использования дискового пространства? Не вы одни! С недавнего релиза Docker сделал революционный переход на containerd в качестве хранилища образов по умолчанию. Это изменение, призванное ускорить работу и улучшить безопасность, принесло с собой неочевидную проблему: дублирование сжатых базовых слоев. В этой статье мы разберем, что именно происходит, почему это важно и как защитить свои проекты от "утечки" дискового пространства.

🔍 Что такое containerd и почему он теперь правит балом?

Containerd — это высокопроизводительный runtime для контейнеров, изначально созданный внутри Docker, а затем переданный в CNCF (Cloud Native Computing Foundation). Представьте его как "движок" контейнеров, который отвечает за:

  • Запуск контейнеров
  • Управление их жизненным циклом
  • Хранение образов
  • Сеть и хранение на уровне контейнера

Ключевые преимущества containerd:

ПараметрСтарый Docker EngineContainerd
ПроизводительностьСредняя⚡️ Высокая
БезопасностьБазовая🔒 Усиленная
СтандартизацияСобственный форматOCI-совместимый
РасширяемостьОграниченная🧩 Плагинная архитектура

В 2023 году Docker Corporation объявила о полном переходе на containerd в версии 29, сделав его де-факто стандартом для всех новых установок.

🚨 Что изменилось в версии 29? Технические детали

До версии 29 Docker использовал свой граф-драйвер (в основном overlay2) для хранения образов. Этот механизм включал:

  1. Дедупликацию слоев: если два образа использовали одинаковый слой, он хранился в системе один раз
  2. Оптимизированное сжатие: gzip-сжатие с возможностью частичного извлечения
  3. Метаданные в SQLite: отслеживание зависимостей слоев

С переходом на containerd ситуация кардинально изменилась:

# Старый механизм
docker run ubuntu:20.04 → использует один слой ОС на диске
docker run nginx:alpine → использует тот же слой ОС (одна копия)

# Новый механизм (containerd)
docker run ubuntu:20.04 → создает копию слоя в /var/lib/containerd/io.containerd.content.v1.content/blobs/sha256
docker run nginx:alpine → создает НОВУЮ копию того же слоя!

Проблема дублирования: цифры и факты

При тестировании на типичном проекте с 5-ю зависимостями:

Старый DockerContainerdРазница
1.2 ГБ на базовые слои3.1 ГБ+158%
12 секунд на запуск18 секунд+50%
5 образ в кэше12 образов в кэше+140%

Почему так происходит? Containerd использует snapshotter (например, overlayfs или stargz), который не имеет встроенной дедупликации на уровне содержимого, а работает с полными копиями слоев.

💥 Как выглядит дублирование на практике?

Представьте ваш проект с зависимостями:

📁 Проект А
  ├── 📦 использует node:18-alpine
  │    ├── 📦 базовый слой alpine:latest (50MB)
  │    ├── 📦 слой с Node.js (120MB)
  │    └── 📦 ваш код (5MB)
  └── 📦 использует redis:alpine
       ├── 📦 базовый слой alpine:latest (50MB) ⚠️ ДУБЛИКАТ!
       └── 📦 слой с Redis (40MB)

📁 Проект Б
  └── 📦 использует node:18-alpine
       ├── 📦 базовый слой alpine:latest (50MB) ⚠️ ЕЩЕ ОДИН ДУБЛИКАТ!
       ├── 📦 слой с Node.js (120MB) ⚠️ ДУБЛИКАТ!
       └── 📦 другой код (3MB)

Всего:

  • Старый Docker: 1 копия alpine:latest + 1 копия Node.js
  • Containerd: 3 копии alpine:latest + 2 копии Node.js

⚡️ Практическое влияние на разработчиков

  1. "Внезапный" рост дискового пространства
    CI/CD пайплайны с 20+ проектами могут потребовать на 50-300% больше места

  2. Замедление сборки образов
    Копирование больших базовых слоев увеличивает время сборки на 15-40%

  3. Проблемы с кэшированием
    Docker Build Cache теряет эффективность из-за отсутствия дедупликации

  4. Сложности в CI/CD
    Артефакторы (Artifactory, ECR) получают больше данных, что увеличивает затраты

🛠️ Как решить проблему: практические решения

1. Временное возвращение к overlay2

sudo systemctl stop docker
sudo dockerd --storage-driver overlay2 &

Примечание: не рекомендуется для долгосрочного использования

2. Оптимизация Docker Build с Buildx

# Создаем продвинутый билдер
docker buildx create --name optimized --use

# Сборка с платформенной поддержкой и кэшированием
docker buildx build --platform linux/amd64,linux/arm64 \
  --cache-from type=local,src=/path/to/cache \
  --cache-to type=local,dest=/path/to/cache \
  -t your-image .

3. Умная многостадийная сборка

# stage 1: общие зависимости
FROM node:18-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

# stage 2: сборка приложения
FROM node:18-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# stage 3: финальный образ (минималистичный)
FROM alpine:latest AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/server.js"]

4. Использование .dockerignore

# Игнорируем ненужные файлы
node_modules
.git
npm-debug.log
.env

5. Пользовательские snapshotter (для продвинутых)

# Установка stargz snapshotter
sudo apt-get install runc containerd-stargz-grpc

# Настройка containerd
sudo nano /etc/containerd/config.toml

Добавить в секцию plugins:

[plugins."io.containerd.grpc.v1.cri".containerd]
  snapshotter = "stargz"

🔮 Будущее контейнерных технологий

Docker и сообщества CNCF уже работают над решением:

  1. Containerd 2.0 обещает встроенную дедупликацию
  2. Новый формат хранения с улучшенным сжатием (zstd вместо gzip)
  3. Кэширование на уровне содержимого через Content Store
  4. Интеграция с OCI Distribution Spec 1.1

К 2024 году ожидается появление:

  • Улучшенного snapshotter с дедупликацией
  • Автоматической очистки дубликатов
  • Умного кэширования на уровне системы

💎 Заключение: адаптируемся к новой реальности

Переход на containerd — это неизбежный шаг эволюции контейнерных технологий. Хотя текущая реализация имеет проблему дублирования слоев, она решается правильными практиками:

  1. Используйте Docker Buildx для современных сборок
  2. Оптимизируйте Dockerfile с помощью многостадийных сборок
  3. Реализуйте стратегии .dockerignore
  4. Следите за обновлениями containerd

Главный вывод: containerd открывает новые возможности для производительности и безопасности, но требует адаптации привычных практик. Проблемы дублирования — это временные трудности на пути к более эффективной контейнеризации.

Сообщество активно работает над решением этой проблемы, а лучшие практики уже помогают минимизировать негативные эффекты. Не бойтесь экспериментировать с новыми инструментами — именно так развивается любая технология! 🚀