Как уменьшить размер Docker-образа для Java-приложений
Декабрь 15, 2023
Контейнеры значительно облегчили разработку, тестирование, и деплой облачно-нативных приложений, а существующие технологии автоматической сборки контейнеров еще сильнее ускорили эти процессы. Но если не следить за размером контейнера, ИТ-команда может столкнуться с ростом потребления облачных ресурсов и другими проблемами.
В этой статье мы расскажем об эффективных методах уменьшения Docker-образов, на основе которых можно строить легковесные контейнеры для Java-приложений.
Оптимизация базового образа ОС
Выбор Linux-дистрибутива для Docker-образа
Первый и самый действенный шаг к уменьшению размера Docker-образа — выбор базового образа ОС. Размер Linux-дистрибутива, используемого для контейнеризации приложений, может варьироваться от 79 МБ (CentOS) до 3 МБ (Alpine Linux), что существенно влияет на размер итогового образа. Однако помимо размера при выборе Linux-дистрибутива следует ориентироваться и на другие важные факторы, такие как:
- Регулярные обновления. Поскольку контейнеры являются неотъемлемой частью корпоративной ИТ-инфраструктуры, требования информационной безопасности распространяются и на них. Контейнеры необходимо обновлять (как слой JDK, так и Linux), чтобы оперативно устранять известные уязвимости. Поэтому выбор нужно сделать в пользу Linux-дистрибутива, чьи разработчики своевременно внедряют патчи безопасности в свой продукт.
- Реализация библиотеки C (libc). Большинство современных Linux-дистрибутивов основаны на реализации стандартной библиотеки C под названием glibc, некоторые (такие как Alpine) – на musl. Использование дистрибутива на musl помогает значительно сократить размер контейнера, но переход на ОС с другой имплементацией libc в основе может вызвать проблемы с совместимостью и непредсказуемое поведение приложения.
- Наличие техподдержки на территории России. У некоторых Linux-дистрибутивов есть только поддержка от сообщества, что не оптимально для корпоративной разработки, поскольку решения проблемы можно ждать несколько недель. С другой стороны, зарубежные вендоры из-за угрозы санкций больше не оказывают поддержку своих продуктов в России, поэтому использовать их в корпоративной разработке также не рекомендуется. Альтернативу зарубежным решениям можно найти в Едином реестре российского ПО.
Axiom JDK разрабатывает и поддерживает Axiom Runtime Container Pro, который входит в реестр российского ПО. Решение основано на легковесном Axiom Linux с поддержкой двух вариантов libc (улучшенный musl и glibc) и рантайме Axiom JDK Pro Lite, оптимизированном для деплоя в облаке.
Сокращение количества Linux-пакетов
Какой бы Linux-дистрибутив вы ни выбрали, его можно кастомизировать. В большинстве случаев базовые Linux-образы содержат множество дополнительных модулей. Удалите пакеты, которые не нужны для работы вашего приложения — так вы еще сильнее уменьшите размер образа.
Можно пойти другим путем: используйте минималистичный Linux-дистрибутив и вместо того, чтобы удалять ненужные библиотеки, добавьте только необходимые, скачав их из Linux-репозиториев.
Оптимизация Java-слоев
Thin JAR-файлы
Традиционным способом упаковки Java-приложений является создание так называемых fat JAR-файлов, содержащих файлы классов и приложение со всеми зависимостями. В итоге мы получаем исполняемый файл, которому для запуска необходима лишь среда исполнения (JRE).
Но мы можем уменьшить размер исполняемого файла, создав thin JAR с приложением без зависимостей. Разработчики кладут зависимости в отдельные слои в образе, а сверху кладут thin JAR. Это позволяет, во-первых, хранить зависимости в локальном репозитории и не перемещать приложение со всеми зависимостями из среды разработки в среду тестирования или в прод, а во-вторых, иметь один общий редко обновляемый набор слоев зависимостей и обновлять только самый тонкий слой, что сильно экономит время.
JRE для деплоя
Для разработки Java-приложений требуется среда разработки и исполнения Java Development Kit (JDK), включающая в себя виртуальную машину Java (JVM), среду исполнения (JRE) и инструменты разработчика (дебаггер, компилятор и т.д.). Однако для запуска приложения нужна только JRE, включающая JVM и некоторые классы для выполнения кода.
Иногда разработчики помещают JDK в контейнеры, предназначенные для прода, тем самым необоснованно увеличивая их размер. Для прода больше подходят JRE-образы. Сравните: образ JDK с дополнительными инструментами, такими как jlink, занимает около 160 МБ, в то время как JRE (на базе Axiom JDK Pro Lite) весит около 40 МБ!
jlink для создания кастомного JRE
Начиная с версии Java 9, JDK разделена на модули (наборы взаимосвязанных пакетов с дескриптором модуля). Сами Java-приложения также можно организовать в виде модулей. Благодаря этой особенности Java-платформы разработчики с помощью инструмента jlink могут создавать кастомные JRE-образы, содержащие только модули, необходимые их приложению. Итоговый контейнер на базе кастомной JRE может занимать в три раза меньше памяти, чем стандартный контейнер.
Полезные Docker-инструменты
Лучшая практика по работе с Dockerfile — минимизация количества слоев. Каждая команда в Dockerfile создает новый слой образа, тем самым увеличивая его размер. Поэтому при возможности команды следует объединять, например, вместо двух RUN do something
и RUN do something else
написать RUN do something && do something else
.
Также для работы с Docker есть инструменты, помогающие уменьшить размер образа:
- .dockerignore позволяет разработчикам указать файлы и папки, которые не должны попасть в итоговый образ. Таким образом можно ускорить процесс сборки, уменьшить потребление памяти и повысить безопасность, устранив риск попадания в образ конфиденциальных данных.
- docker-slim автоматически оптимизирует размер образа. Инструмент создает временный образ и анализирует, какие файлы необходимы приложению. Итоговый однослойный образ, содержащий только нужные файлы, может быть в 30 раз меньше изначального. Но использовать docker-slim нужно с осторожностью, поскольку он может ошибиться в расчетах и не учесть необходимые файлы из-за динамизма Java.
- docker-squash «сплющивает» N последних слоев в один, благодаря чему временные или удаленные файлы не попадут в итоговый образ.
Заключение
Как видите, методов уменьшения Docker-образов много: даже если вы используете лишь некоторые из них, экономия памяти будет существенной.
Для достижения мгновенного результата без существенных изменений конфигурации можно мигрировать на микроконтейнеры Axiom Runtime Container Pro — так вы одновременно уменьшите потребление облачных ресурсов и внедрите в проект отечественную технологию с техподдержкой, что особенно актуально для объектов КИИ, ГИС и финтеха, которые в соответствии с требованиями законодательства должны быть переведены на российское ПО к 2025 году.
Свяжитесь с нами — наши инженеры подробно расскажут об Axiom Runtime Container Pro и других продуктах линейки Axiom JDK, предоставят демо-версии и помогут с миграцией.