TGViewer
DevOps FM DevOps FM @devops_fm · 5.29K subscribers
Post #429 1.31K
2️⃣ Сносим все лишнее из контейнера с помощью distroless

Текущий образ предоставляет нам Node.js, yarn, npm, bash и много других полезных бинарников. Также, он создан на базе Ubuntu. Таким образом, развернув его, мы получаем полноценную операционную систему со множеством полезных бинарников и утилит.

При этом они не нужны нам для запуска контейнера. Единственная нужная зависимость — это Node.js.

Docker-контейнеры должны обеспечивать работу одного процесса и содержать минимально необходимый набор инструментов для его запуска. Целая операционная система для этого не требуется.

Таким образом, мы можем вынести из него все, кроме Node.js.

Но как?

В Google уже пришли к подобному решению — GoogleCloudPlatform/distroless.

Описание к репозиторию гласит:

Distroless-образы содержат только приложение и зависимости для его работы. Там нет менеджеров пакетов, shell'ов и других программ, которые обычно есть в стандартном дистрибутиве Linux.

Это то, что нужно!

Запускаем Dockerfile, чтобы получить новый образ:

FROM node:8 as build
WORKDIR /app
COPY package.json index.js ./
RUN npm install
FROM gcr.io/distroless/nodejs
COPY --from=build /app /
EXPOSE 3000
CMD ["index.js"]

Собираем образ как обычно:

$ docker build -t node-distroless .

Приложение должно нормально заработать. Чтобы проверить, запускаем контейнер:

$ docker run -p 3000:3000 -ti --rm --init node-distroless

И идем на http://localhost:3000. Стал ли образ легче без лишних бинарников?

$ docker images | grep node-distroless
node-distroless 7b4db3b7f1e5 76.7MB

Еще как! Теперь он весит всего 76,7 МБ, на целых 600 Мб меньше!

Все круто, но есть один важный момент. Когда контейнер запущен, и надо его проверить, подключиться можно с помощью:

$ docker exec -ti <insert_docker_id> bash

Подключение к работающему контейнеру и запуск bash очень похоже на создание SSH-сессии.

Но поскольку distroless — это урезанная версия исходной операционной системы, там нет ни дополнительных бинарников, ни, собственно, shell!

Как подключиться к запущенному контейнеру, если нет shell?

Самое интересное, что никак.

Это не очень хорошо, так как исполнять в контейнере можно только бинарники. И единственный, который можно запустить — это Node.js:

$ docker exec -ti <insert_docker_id> node

На самом деле в этом есть и плюс, ведь если вдруг какой-то злоумышленник сможет получить доступ к контейнеру, он причинит намного меньше вреда, чем если бы у него был доступ к shell. Иными словами, меньше бинарников — меньше вес и выше безопасность. Но, правда, ценой более сложной отладки.

Тут надо бы оговориться, что подключать и отлаживать контейнеры на prod-окружении не стоит. Лучше положиться на правильно настроенные системы логирования и мониторинга.

Но что, если нам-таки нужен дебаггинг, и при этом мы хотим, чтобы docker-образ имел наименьший размер?

#лонгрид
  • 👍 13
  • ❤ 1
More from @devops_fm
  1. Oct 5, 2026Как retry может усугубить инцидент Uber недавно опубликовал разбор реального инцидента, в…
  2. Oct 2, 2026🎙 Что послушать на выходных: Kubernetes становится слишком сложным? Пятница — отличный по…
  3. Sep 30, 2026🔔В эфире DevOps FM – срединедельный дайджест новостей! ⏺В Amazon EKS показали, как Pod мо…
  4. Sep 28, 2026Почему Kubernetes API server может съесть память на обычном LIST 👀 Получить список объект…
  5. Sep 25, 2026Redis Streams vs Kafka 📝 Что выбрать для системы обработки событий: Redis Streams или Kaf…
  6. Sep 23, 2026Новостной дайджест от DevOps FM! Делимся свежими новостями и важными изменениями в мире De…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →