Хотите раскрыть творческий потенциал вашего ребенка? Ребенок любит фантазировать и придумывать что-то новое? Проводит все свободное время за компьютером или планшетом? Пора направить его интерес в правильное русло! Приглашаем детей и их родителей на пробный детский урок.
Многоэтапная сборка Docker: от bloated-образов к безопасным production-ready контейнерам. Почему root убивает вашу безопасность – Блог Академии ТОП
Рассказываем, как сократить вес Docker-образов, ускорить CI/CD и повысить безопасность: multi-stage сборка, отказ от root, кейсы для разных языков .
Контейнеры упростили разработку и деплой, но вместе с удобством пришли новые проблемы: раздутые образы, медленные пайплайны и дыры в безопасности. В этой статье мы разберемся, как оптимизировать Docker-образы и превратить их в надежные инструменты, готовые к продакшену.
Материал будет полезен backend-разработчикам, DevOps-инженерам, тимлидам, системным администраторам и junior-специалистам, изучающим Docker и CI/CD.
Проблема «тяжелых» Docker-образов: почему это важно
Однажды вы запускаете сборку и с удивлением обнаруживаете, что образ вашего скромного приложения весит больше одного гигабайта. Ситуация не редка, особенно если речь идет о Node.js или Python, где в образ могут попасть десятки лишних зависимостей, исходники и даже инструменты для сборки, которые в продакшене не нужны.
Большие Docker-образы — это не просто неудобство. Это прямой удар по скорости CI/CD, по затратам на трафик, по времени деплоя и, самое главное, по безопасности.
Каждый лишний слой, каждая утилита или библиотека — потенциальная точка атаки. А если вы еще запускаете такой контейнер от root-пользователя — это уже не просто ошибка, а приглашение для злоумышленника.
Пример. Приложение на Node.js после стандартной сборки весит 1.2 ГБ. Почему?
В образ попали:
node_modules, включая dev-зависимости;
исходный код, тесты, логи;
сборочные инструменты — webpack и eslint;
base image на основе ubuntu, а не alpine.
Результат — медленные деплои, переполненный кеш на серверах, проблемы при прохождении аудитов. А теперь представьте, что вы работаете в команде и таких проектов — десятки. Умножьте это на стоимость трафика и скорость работы пайплайна — и станет ясно, что размер Docker-образа имеет значение.
Нужно решить эту проблему. Для начала — признать ее и усвоить, что Docker-файл — это тот же код, к которому нужно применять архитектурный подход.
Форма заявки недоступна в AMP версии. Перейти к полной версии
Что такое multi-stage build в Docker и зачем он нужен
Большинство разработчиков знают, что Dockerfile можно написать просто: указать базовый образ, установить зависимости, скопировать код, запустить. Но именно такой подход и приводит к появлению «монстров» по 2–3 гигабайта. К счастью, у Docker есть мощный инструмент, который позволяет делить сборку на этапы — multi-stage build.
Принцип прост: на первом этапе вы собираете приложение, на втором — упаковываете только нужные файлы. Это как сначала сшить костюм, а потом — выбросить все лекала, нитки и обрезки ткани.
Как это выглядит на примере оптимизации Go приложения:
FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
RUN go build -o app
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/app .
CMD ["./app"]
Multi-stage build в Docker — фундамент для продакшен-образов. Он внедряется за один день, а пользу приносит на месяцы вперед.
Освоить все тонкости работы с Docker вы можете на курсе Академии ТОП «DevOps-инженер». Кроме того, вы научитесь писать скрипты и приложения, которые помогут разработчикам, тестировщикам и системным администраторам автоматизировать рутинные процессы и получите востребованную и высокодоходную специальность.
Безопасность Docker: почему запуск контейнера от root — это ошибка
Запускать контейнер от root-пользователя — почти то же самое, что и доверять всем внешним зависимостям и библиотекам как себе. Это риск, который редко оправдан. Если хакер найдет уязвимость в приложении, работающем от root, он получит права суперпользователя в контейнере. А выход за его пределы — вопрос времени.
Сценарий под названием container escape — не миф, а зафиксированная проблема безопасности. Особенно опасны образы, в которых установлены ненужные системные утилиты — curl, wget, bash, nano. Именно они становятся инструментом для атак.
Правильный путь — использовать USER в Dockerfile и создавать отдельного пользователя с минимальными правами. Пример:
RUN addgroup app && adduser -S -G app app
Теперь даже если злоумышленник проберется внутрь, его действия будут ограничены. В связке с multi-stage билдом это превращает ваш образ в почти неприступную крепость.
Запуск контейнера без root — это не опция, а стандарт, к которому нужно стремиться по умолчанию.
Практические кейсы оптимизации Docker-образов
Ниже примеры оптимизации образов на разных технологиях.
Node.js: исходный образ весил 1.2 ГБ, содержал все зависимости, dev-инструменты, тесты. После применения multi-stage build и перехода на node:slim — 85 МБ. Разница более чем в 10 раз.
Python: вместо установки всех зависимостей из requirements.txt использовали разделение на requirements-dev.txt и requirements-prod.txt. Кроме того, в финальный образ включали только runtime-библиотеки и очищали кеш pip. Без оптимизации вес образа — 700 МБ, с — 400 МБ.
Spring Boot (Java): изначально использовался OpenJDK full с Maven внутри. Образ весил 1.1 ГБ. После перехода на сборку через Gradle и копирования только jar-файла во второй stage, а также смены базового образа на eclipse-temurin:17-jre-alpine — минус 600 МБ.
Оптимизация Docker-образов для разных языков — это не про тонкие настройки, а про эффективный подход. Каждый лишний файл — это потенциальная уязвимость и пустая трата ресурсов.
Мы собрали подборку курсов для людей с разным уровнем подготовки
ПерейтиПродвинутые техники Docker-сборки
Когда базовые принципы освоены, время сделать следующий шаг и вывести образы на новый уровень. Для этого воспользуемся .dockerignore. Этот файл —как .gitignore, но для Docker. Если вы не исключите файлы node_modules, .git, tests и логи, они попадут внутрь образа. И увеличат его размер на сотни мегабайт.
Пример содержимого файла .dockerignore:
node_modules
.git
tests
*.log
Кеширование слоев — еще один важный момент. Не секрет, что Docker строит образы поэтапно. Если сначала вы устанавливаете зависимости, а потом копируете код, при каждом изменении кода зависимости не пересобираются. Это сокращает время сборки с минут до секунд.
И, наконец, базовые образы. Вместо Ubuntu или Debian используйте Alpine или Distroless. Первый — суперлегкий (около 5 МБ), но работает на musl, а не glibc, поэтому некоторые библиотеки могут быть несовместимы. Второй — вообще без shell и package manager, что идеально для продакшена, но несколько усложняет отладку и требует тщательной подготовки окружения.
Выбор базового образа для Docker — это компромисс между весом, функциональностью и безопасностью. Делаем этот выбор осознанно.
Курс Академии ТОП «Python разработчик с нуля до PRO» идеально подходит тем, кто хочет расширить свои навыки от разработки backend на Python до контейнеризации и развертывания приложений.
Чек-лист: как собрать production-ready Docker-образ
Оптимизированный production-ready Docker-образ — всегда результат строгого соблюдения инженерной дисциплины. Если вы хотите, чтобы он не просто работал, а был надежным, быстрым и безопасным — проверьте его по списку:
Размер финального образа — не превышает 500 МБ.
Используется multi-stage build для отделения build-time зависимостей.
В образе только runtime-библиотеки — никаких дев-утилит.
Контейнер запускается не от root.
Используется .dockerignore.
Базовый образ — slim, alpine или distroless.
Все зависимости зафиксированы (версии, хеши).
Применены обновления безопасности.
Пройден анализ уязвимостей (например, docker scan, trivy, snyk).
Docker — мощный инструмент, но только в умелых руках он превращается в безопасный и производительный механизм доставки приложений. Не надо собирать образы по наитию — внедряйте стандарты и подходы, которые работают. Multi-stage, отказ от root, правильные базовые образы — минимум, без которого контейнеризация теряет смысл.
Источники и полезные ссылки:
https://docs.docker.com/build/building/multi-stage
https://github.com/GoogleContainerTools/distroless
https://snyk.io/blog/10-docker-image-security-best-practices
https://docs.docker.com/engine/scan
Об эксперте
Михаил Шмаров — преподаватель Python и DevOps в Академии ТОП. Автор учебных программ и методик обучения современным языкам программирования и инструментам разработки. Автор учебника The Ultimate Docker Mastery Guide for DevOps Engineers.