Когда приложение Java выполняется внутри контейнера, эргономика JVM (которая отвечает за динамическое назначение ресурсов на основе возможностей хоста) не знает, что оно работает внутри контейнера, и вычисляет количество ресурсов, которые будут использоваться Java-приложение на основе хоста, который выполняет ваш контейнер. Учитывая это, не имеет значения, если вы установите ограничения для своего контейнера, JVM будет использовать ресурсы вашего хоста в качестве базы для выполнения этого вычисления.
В JDK 8u131 + и JDK 9 есть опция экспериментальной виртуальной машины, которая позволяет эргономике JVM считывать значения памяти из групп CG. Чтобы включить его, вы должны передать JVM следующие флаги:
-XX: + UnlockExperimentalVMOptions и -XX: + UseCGroupMemoryLimitForHeap
Если вы включите эти флаги, JVM будет знать, что работает внутри контейнера, и сделает эргономику JVM для расчета ресурсов приложения на основе ограничений контейнера, а не возможностей хоста.
Включение флагов:
$ java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -jar app.jar
Вы можете динамически передавать параметры JVM в свой контейнер с помощью переменных ENV.
Пример:
Команда для запуска вашего приложения будет выглядеть примерно так:
$ java ${JAVA_OPTIONS} -jar app.jar
И команде docker run необходимо передать переменную ENV следующим образом:
$ docker run -e JAVA_OPTIONS="-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" myJavaImage
Надеюсь, это поможет!