Distroless контейнеры

22da3274117bb5af6c0eeb6a1e5e110a

Distroless контейнеры — это контейнеры, содержащие только нужные для работы приложения файлы. Из контейнера убираются не используемые программой файлы дистрибутива с целью уменьшить его размер и снизить площадь атаки. Вместо сотен или тысяч ненужных файлов дистрибутива остаются лишь файлы, требуемые для работы. Этот подход изначально был предложен Google.

Если у читателя есть опыт сборки контейнеров он скорее всего сталкивался с «контейнером» scratch. Достаточно написать FROM scratch в Dockerfile и мы получим абсолютно пустую файловую систему и сможем запустить свою программу без файлов вообще. Чтобы работать без системы вообще программа должна быть полностью статически собрана. Она должна быть написана на языке, допускающем такую сборку. Например go, c, c++, rust. Некоторые функции операционной системы в такой сборке не будут работать. Например: нельзя будет сменить пользователя (нет /etc/passwd), использовать локальное время (нет timezone), использовать локаль (нет файлов локали) и даже нельзя будет сделать https запрос (не установлены сертификаты). 

На языке допускающим статическую сборку, ради размера image, можно все вышеперечисленное сделать руками. Давайте взглянем, что уже сделано и возможно бесплатно облегчим ваши контейнеры на десяток мегабайт.

Google Distroless Container

Этот набор контейнеров появился раньше всех. Находится он тут:  https://github.com/GoogleContainerTools/distroless. Он содержит контейнеры базирующиеся на debian. В набор входят сборки для статически линкуемых языков, а также для java, python 3 и nodejs. Есть примеры для go и rust. На базе этого набора собираются стандартные контейнеры для kubernetes по этому все проверено и надежно.

Chainguard Images

Chainguard собирает небольшие и безопасные контейнеры. Репозиторий тут:  https://github.com/chainguard-images. Как базу они используют apko и melange на котором собирается дистрибутив alpine. Основные контейнеры — это сборки c динамическими glibc и musl. Сборок с поддержкой различных runtime гораздо больше, чем в предыдущем проекте. Тут:  https://github.com/chainguard-images/images из интересного есть: php и jenkins. Не все имиджи находятся в состоянии stable.

Chiseled Ubuntu

Canonical делает для Microsoft специальные имиджи для .net. Утилита chisel убирает с релизного имиджа Ubuntu все ненужное. Если вы используете .net можете попробовать использовать эти контейнеры как основу сборку вашего проекта. На ».net blog» есть подробный пост про это:  https://devblogs.microsoft.com/dotnet/dotnet-6-is-now-in-ubuntu-2204/. Имиджей для других платформ в собранном виде я не нашел.

Slimtoolkit

Утилита https://slimtoolkit.org реализует иной подход. Разработчик строит обычный контейнер на базе удобного ему дистрибутива. Утилита запускает его и запоминает какие файлы и системные вызовы были использованы. После завершения запуска она копирует все затронутые файлы в новый контейнер, строит профили безопасности для apparmor и seccomp, а также записывает все использованные сертификаты. В документации утверждается, что такой подход сокращает имиджи в 20 с лишним раз.

Во время моих тестов уменьшение имиджа было куда скромнее в 5–6 раз. Также довольно неудобно, при использовании slim придется всегда собирать только ей и всегда запускать свой контейнер. Есть вариант в докере и в виде сервиса, но все равно это не очень удобно.

Будут ли проблемы при использовании distroless контейнеров? Да! Я столкнулся как минимум с двумя:

  1. Сложно отлаживать. Нельзя просто зайти в shell на контейнере (на pod) и выполнить команды. Не конфиг посмотреть!  Даже ps не сделать.

  2. Не все программы готовы работать в таком спартанском окружении. Одна система упорно пыталась открыть файл в /var/log хотя и ничего туда не писала. Slim, однако почему-то это игнорировал и /var/log в результирующий image не включал. Пришлось добавлять руками.

Заключение

Стоит ли использовать distroless контейнеры? Думаю да! Как минимум можно попробовать собраться с новым базовым имиджем и протестировать сборку ваших существующих контейнеров. В случае .net работоспособность гарантируется самим Microsoft.

Если вы используете nodejs, python или java возьмите контейнер с готовым runtime, например от chainguard и попробуйте пересобрать существующие Dockerfile. Велика вероятность, что все заработает из коробки.

© Habrahabr.ru