Какие издержки (overheads) и ограничения есть у Docker?

«Какие издержки (overheads) и ограничения есть у Docker?» — вопрос из категории Docker, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Несмотря на эффективность, Docker имеет ряд издержек и ограничений по сравнению с нативным запуском или полными виртуальными машинами (VM):

  1. Накладные расходы на изоляцию процессов: Контейнеры используют механизмы ядра Linux (namespaces, cgroups), что создает минимальный, но ненулевой overhead по CPU и памяти по сравнению с запуском процесса напрямую на хосте.

  2. Общее ядро (Kernel): Все контейнеры на хосте используют одно ядро ОС. Это:

    • Плюс: Легковесность, быстрый запуск.
    • Минус: Меньшая изоляция по сравнению с VM. Уязвимость в ядре может затронуть все контейнеры. Нельзя запустить контейнер с ОС, требующей другое ядро (например, Windows-контейнер на Linux-хосте без виртуализации).
  3. Сетевой overhead: Сетевые драйверы Docker (bridge, overlay) добавляют небольшую задержку и могут снизить пропускную способность по сравнению с host-network. Overlay-сети для Swarm/Kubernetes добавляют дополнительную сложность и encapsulation (VXLAN).

  4. Накладные расходы на хранение (Storage): Использование драйверов хранения (overlay2, aufs) может влиять на производительность I/O, особенно при работе с большим количеством маленьких файлов. Volume-монтирования обычно быстрее.

  5. Ограничения безопасности по умолчанию: Контейнер, запущенный с правами root (--privileged или без --user), имеет значительные возможности внутри хоста. Требуется дополнительная настройка (AppArmor, Seccomp, пользовательские namespaces) для hardening.

  6. Управление ресурсами требует явной настройки: Без ограничений через cgroups контейнер может исчерпать ресурсы хоста. Лимиты нужно задавать явно.

# Пример запуска контейнера с ограничениями ресурсов и улучшенной безопасностью
docker run -d 
  --name my-app 
  --cpus="1.5"               # Ограничение CPU (1.5 ядра)
  --memory="512m"            # Ограничение RAM
  --memory-swap="1g"         # Ограничение swap
  --pids-limit 100           # Ограничение числа процессов
  --user 1000:1000           # Запуск от непривилегированного пользователя
  --read-only                # Файловая система только для чтения
  --tmpfs /tmp:rw,noexec,nosuid,size=64m 
  my-application:latest

Для сценариев, где критична производительность, близкая к «железу» (например, HFT, высоконагруженные СУБД), иногда предпочтительнее использовать нативный запуск или специальные runtime (например, gVisor для усиленной изоляции).