
Приложение компактное, а контейнер вокруг него весит во много раз больше. Внутри — целый Ubuntu: apt, bash, curl и пара сотен пакетов, из которых делу служат считанные проценты. Индустрия так жила годами, но рост числа уязвимостей и требования регуляторов поменяли правила: всё больше команд собирают distroless-образы — контейнеры вообще без дистрибутива. Арифметика простая: минус лишние пакеты — минус поводы для атаки. У чистоты, правда, есть цена, и берут её отладкой в проде и слепыми зонами сканеров.

Базовый образ Debian или Ubuntu тащит за собой сотни пакетов: менеджер пакетов, шелл, сетевые утилиты, компиляторные зависимости, man-страницы. Приложению на Go или Java всё это без надобности — рантайм оно приносит с собой. Сканеру уязвимостей, впрочем, всё равно, нужны пакеты или нет: он видит каждый и добросовестно рапортует о десятках CVE, из которых по-настоящему опасных — единицы. В итоге команда регулярно пересобирает образ ради обновлений библиотек, которыми никто никогда не пользовался.
Хуже то, что весь этот скарб выручает не только админов. Допустим, злоумышленник получил удалённое исполнение кода. Рядом готовые bash и curl — и контейнер превращается в комфортабельный плацдарм: скачай инструмент, подними reverse shell, обустройся. Логика минимизации поверхности атаки та же, что у отключения лишних сервисов на сервере: эксплуатировать можно только то, что в системе есть. Чего нет — того не взломаешь.

Путь к минимуму промышленность проходила по ступенькам. Сначала появились slim-версии популярных дистрибутивов — те же пакеты, но без документации и локалей. Следующей сенсацией стал Alpine: крошечная база около пяти мегабайт со своим пакетным менеджером. Правда, с musl вместо glibc — а значит, с сюрпризами совместимости. Параллелью пошла multi-stage сборка: в первом, тяжёлом, контейнере компилируем, во второй, пустой, перекладываем один только бинарник. Для статически слинкованных программ на Go или Rust второй стадией может стать вообще scratch — образ из одного файла.
Логичный финал — distroless от Google: ни шелла, ни пакетного менеджера, зато есть необходимый минимум — glibc, корневые сертификаты, данные о часовых поясах, файл пользователей. Есть варианты под Java, Python и Node.js. Компания Chainguard двинулась дальше: минимальные образы с постоянной пересборкой плюс собственный мини-дистрибутив Wolfi, изначально спроектированный под контейнеры.

Первый подвох проявляется в самый неподходящий момент — во время инцидента. Течёт память, инженер заходит в контейнер посмотреть процессы и открытые соединения — и обнаруживает, что ps, top, netstat и даже ls здесь отсутствуют как класс. Заглянуть внутрь нечем. Это и есть счёт за чистоту.
В Kubernetes ситуацию смягчили эфемерные контейнеры: kubectl debug подключает к работающему поду временный toolbox с полным набором утилит, не трогая саму нагрузку. За пределами Kubernetes выручает копирование статического busybox в запущенный контейнер либо отладочный сайдкар, который делит с приложением сетевое пространство имён. Есть и стратегический ответ — наблюдаемость: метрики, трейсинг, eBPF-агенты на узлах кластера, структурные логи. Инструменты диагностики живут рядом с нагрузкой, а не внутри неё. Новая гигиена, ничего не поделаешь.

Второй подвох техничнее. Классические сканеры уязвимостей ищут компоненты по базе пакетного менеджера: читают список установленных пакетов из dpkg, apk или rpm и сверяют с базами CVE. В distroless такой базы нет. Старый сканер торжественно докладывает: «уязвимостей не обнаружено» — и дарит команде опасное чувство ложного покоя.
Современные инструменты — Trivy или связка Syft и Grype — умеют больше: разбирают слои образа, находят бинарники и зависимости языковых экосистем и собирают SBOM, инвентаризационную ведомость компонентов. Но самый честный SBOM — тот, что рождается на этапе сборки, где известен каждый коммит. Поэтому distroless обычно идёт в комплекте с безопасностью цепочки поставок: подпись образов через cosign, закрепление по хэшу вместо плавающего тега, фиксация происхождения сборки по SLSA. Парадокс налицо: чем чище образ, тем больше доверия требует инструмент, который его проверяет.

В России контейнерная инфраструктура развивается под знаком технологической независимости. Ограничения доступа к зарубежным реестрам подтолкнули компании к зеркалированию базовых образов в собственные хранилища: облачные реестры Yandex Cloud и VK Cloud, корпоративные развёртывания Harbor и встроенных реестров GitLab. Минимальные проверенные образы собирает платформа Deckhouse от Flant — она поставляет их в составе собственного дистрибутива Kubernetes. Сканирование образов и реестров стало отдельным продуктовым направлением: известный пример — Kaspersky Container Security, похожие функции встроены и в облачные реестры.
Госсектору и сертифицированным средам — Astra Linux, реестр отечественного ПО — нужно документируемое происхождение каждого компонента. Минималистичный образ с коротким SBOM в эту логику ложится лучше монолитного: меньше сторонних пакетов, прозрачнее поставка. Дальше, судя по всему, будет только строже: внутренние каталоги одобренных базовых образов и требования к SBOM в закупках станут нормой — каковыми они давно являются в зрелых инженерных культурах.
Distroless — не догма, а точка на шкале компромиссов. Чужому коробочному коду и legacy минимализация мало что даст без поддержки вендора, а вот честный сканер и регулярные пересборки — дадут. Для собственных сервисов минимализм уже мейнстрим: multi-stage сборка, компактная база, SBOM на выходе, отладка снаружи. По сути, безопасность — это количество деталей, которые могут сломаться. Деталей меньше — ночных инцидентов меньше, зато выше цена неготовности, когда что-то всё же ломается. Команды, заранее выстроившие культуру внешней диагностики и глубинного сканирования, получают образы, в которых злоумышленнику просто не за что зацепиться.