Многоэтапные сборки

Тема дорожной карты · Docker & Containers

Многоэтапные сборки в Dockerfile представляют собой мощный инструмент для создания эффективных и безопасных контейнерных образов. Этот подход позволяет объединить несколько этапов сборки в одном файле, что упрощает процесс разработки и уменьшает размер финального образа. Многоэтапные сборки особенно полезны для уменьшения поверхности атаки и ускорения процесса сборки, что делает их незаменимыми в современной разработке программного обеспечения.

Как это работает

Многоэтапные сборки в Dockerfile используются для объявления нескольких этапов сборки с помощью ключевого слова FROM. Каждый этап может быть назван, что позволяет легко идентифицировать и использовать их в процессе сборки. Для переноса артефактов между этапами используется команда COPY --from=.

BuildKit, современный и более эффективный сборщик, по умолчанию используется начиная с версии 23.0. Он поддерживает многоэтапные сборки, кэширование и монтирование секретов. Команда RUN --mount=type=cache,target=/root/.npm позволяет сохранять кэш npm/pnpm между сборками, что значительно ускоряет процесс повторной сборки. Команда RUN --mount=type=secret,id=mytoken позволяет безопасно инжектить секреты, которые не попадают в слой образа.

Для управления переменными окружения на этапах сборки используются команды ARG и ENV. ARG используется для переменных окружения на этапах сборки, в то время как ENV используется для переменных окружения в финальном образе. Команда HEALTHCHECK определяет, как Docker проверяет, работает ли контейнер, и используется для определения состояния здоровья контейнера.

Когда применять

Многоэтапные сборки особенно полезны в ситуациях, когда необходимо уменьшить размер финального образа и уменьшить поверхность атаки. Например, можно использовать тяжёлую стадию builder с компиляторами и SDK, а затем перенести только необходимые артефакты в лёгкую стадию runtime, содержащую только готовый бинарник или ассеты. Это позволяет значительно уменьшить размер финального образа.

BuildKit и --mount=type=cache особенно полезны в случаях, когда сборка качает пакеты, что драматически уменьшает время сборки в CI/CD. Мульти-платформенные сборки через buildx позволяют создавать образы для нескольких архитектур, таких как x86_64 и arm64 (Raspberry Pi, M-series Mac, Graviton). Команда HEALTHCHECK особенно полезна для долгих сервисов, так как она позволяет Docker корректно определить, когда контейнер готов к работе.

Типичные ошибки

Одним из самых распространённых недоразумений при использовании многоэтапных сборок является использование команды ARG для секретов. Это может привести к утечке секретов в истории команд или в выводе команды docker inspect. Вместо этого следует использовать команду RUN --mount=type=secret,id=mytoken для безопасного инжекта секретов.

Ещё одной распространённой ошибкой является сброс кэша после каждого apt update. Это происходит, когда следующая инструкция всегда меняется, что приводит к сбросу кэша. Для решения этой проблемы следует группировать apt-команды в одну инструкцию RUN.

Забывание установки переменной окружения DOCKER_BUILDKIT=1 на старом Docker также может привести к ошибкам, таким как "unknown flag" на --mount. Для решения этой проблемы следует убедиться, что переменная окружения DOCKER_BUILDKIT установлена в значение 1.

Наконец, неправильная настройка команды HEALTHCHECK также может привести к ошибкам. Например, если команда HEALTHCHECK выполняется каждые 30 секунд с начальной задержкой в 90 секунд, контейнер может быть помечен как unhealthy ещё до того, как он полностью завершит свою инициализацию.

Связанные понятия

Полезные ресурсы