Java и Docker. Часть 1 | OTUS
⚡ Подписка на курсы OTUS!
Интенсивная прокачка навыков для IT-специалистов!
Подробнее

Курсы

Программирование
iOS Developer. Professional Kotlin Backend Developer Flutter Mobile Developer Symfony Framework C++ Developer. Basic Unity Game Developer. Basic Java Developer. Professional
-35%
Highload Architect Unity Game Developer. Professional React.js Developer Специализация Java-разработчик
-25%
Алгоритмы и структуры данных
-16%
Scala-разработчик C# Developer. Professional
-23%
Разработчик голосовых ассистентов и чат-ботов Team Lead Архитектура и шаблоны проектирования NoSQL Web-разработчик на Python Golang Developer. Professional PostgreSQL Vue.js разработчик Супер-практикум по использованию и настройке GIT Разработчик IoT Подготовка к сертификации Oracle Java Programmer (OCAJP) Программист С HTML/CSS
Инфраструктура
Инфраструктурная платформа на основе Kubernetes Microservice Architecture Базы данных Highload Architect Reverse-Engineering. Professional
-8%
Network engineer. Basic Administrator Linux.Basic MongoDB Infrastructure as a code MS SQL Server Developer Cloud Solution Architecture Мониторинг и логирование: Zabbix, Prometheus, ELK Супер-практикум по использованию и настройке GIT Разработчик IoT Экcпресс-курс «ELK» Супер-интенсив "Tarantool" Экспресс-курс «CI/CD или Непрерывная поставка с Docker и Kubernetes» Экспресс-курс «Введение в непрерывную поставку на базе Docker»
Корпоративные курсы
Безопасность веб-приложений Экосистема Hadoop, Spark, Hive Пентест. Практика тестирования на проникновение Node.js Developer Java QA Engineer. Basic
-18%
Reverse-Engineering. Professional
-8%
DevOps практики и инструменты NoSQL Reverse-Engineering. Basic Cloud Solution Architecture Внедрение и работа в DevSecOps Супер-практикум по работе с протоколом BGP Game QA Engineer Супер - интенсив по Kubernetes Дизайн сетей ЦОД Экспресс-курс «IaC Ansible» Экспресс-курс по управлению миграциями (DBVC) Экспресс-курс "Версионирование и командная работа с помощью Git" Основы Windows Server
Специализации Курсы в разработке Подготовительные курсы Подписка
+7 499 938-92-02

Java и Docker. Часть 1

Java_Deep_19.2-5020-b3b56b.png

Сейчас Java всё чаще используется в контейнерах, обычно в Docker. Формально в Docker можно положить любую версию Java, и это даже как-то будет работать. Однако когда вышла Java 8, про работу в Docker ещё никто и не думал. В результате Java-приложение хоть и работает, но не понимает, что находится в ограниченном окружении. Не видит ограничение Docker-а на использование процессора и памяти.

Это приводит к весьма неприятным последствиям. Например, приложение не учитывает ограничение на процессоры и может создавать пулы с большим количеством потоков или не видит ограничение по памяти и неожиданно закрывается Docker-ом при превышении лимита.

Работа в контейнере начала улучшаться, начиная c Java 9 (есть и обратные порты в Java 8), в релизе Java 10 был добавлен новый параметр UseContainerSupport. Этот параметр сообщает Java-приложению, что оно запущено в контейнере и необходимо учитывать наложенные ограничения, а не использовать все ресурсы операционной системы без ограничений.

Давайте посмотрим, как это работает. По умолчанию UseContainerSupport включён, т. е. приложение видит ограничения контейнера. Положим в контейнер простое приложение, которое выводит количество доступных процессоров:

Runtime.getRuntime().availableProcessors().

Соберём образ и запустим контейнер такой командой:

docker run --memory=100m --cpus 2 java-docker

Вводим ограничение для контейнера: память 100 Мб и 2 процессора. В контейнере запускается такая команда:

CMD java -XX:+PrintFlagsFinal -version | grep MaxHeapSize

Получаем результат:

size_t MaxHeapSize    = 52428800

Это примерно 52 Мб, т. е. примерно половина лимита контейнера.Теперь посмотрим на доступные процессоры:

CMDjava -jartestJavaAppl.jar

Возвращает:

Runtime.getRuntime().availableProcessors(): 2

Видим, что Java-приложение учитывает в своей работе лимиты, заданные контейнером. Давайте повторим эксперимент, но на этот раз отключим режим UseContainerSupport — это фактически вернёт нас во времена Java 8. Ограничения контейнера те же. Смотрим память:

CMD java -XX:-UseContainerSupport -XX:+PrintFlagsFinal -version | grep MaxHeapSize

Получаем:

size_tMaxHeapSize   = 8415870976

Java не видит ограничение в 100 Мб и пытается использовать память «на всю котлету». А теперь смотрим, что происходит с процессором:

CMD java -XX:-UseContainerSupport -jar testJavaAppl.jar

Получаем:

Runtime.getRuntime().availableProcessors(): 12

И по процессорам Java пытается использовать все системные ресурсы, игнорируя ограничения Docker-а. Очевидно, что для корректной работы Java-приложения в Docker-е желательно использовать версию Java 10 или новее.

В следующей заметке затронем другие аспекты работы Java-приложения в контейнере. А более подробно посмотрим на это дело на открытом вебинаре «Java и Docker».

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться