Текущий образ предоставляет нам 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Еще как! Теперь он весит всего 76,7 МБ, на целых 600 Мб меньше!
node-distroless 7b4db3b7f1e5 76.7MB
Все круто, но есть один важный момент. Когда контейнер запущен, и надо его проверить, подключиться можно с помощью:
$ docker exec -ti <insert_docker_id> bashПодключение к работающему контейнеру и запуск bash очень похоже на создание SSH-сессии.
Но поскольку distroless — это урезанная версия исходной операционной системы, там нет ни дополнительных бинарников, ни, собственно, shell!
Как подключиться к запущенному контейнеру, если нет shell?
Самое интересное, что никак.
Это не очень хорошо, так как исполнять в контейнере можно только бинарники. И единственный, который можно запустить — это Node.js:
$ docker exec -ti <insert_docker_id> nodeНа самом деле в этом есть и плюс, ведь если вдруг какой-то злоумышленник сможет получить доступ к контейнеру, он причинит намного меньше вреда, чем если бы у него был доступ к shell. Иными словами, меньше бинарников — меньше вес и выше безопасность. Но, правда, ценой более сложной отладки.
Тут надо бы оговориться, что подключать и отлаживать контейнеры на prod-окружении не стоит. Лучше положиться на правильно настроенные системы логирования и мониторинга.
Но что, если нам-таки нужен дебаггинг, и при этом мы хотим, чтобы docker-образ имел наименьший размер?
#лонгрид