Комментарии 18
JVM до сих пор не имеет средств, позволяющих определить, что она выполняется в контейнеризированной среде и учесть ограничения некоторых ресурсов, таких, как память и процессор.А должна? Если Java будет знать, что она в контейнере, то может получиться сильно связанная система, что не есть хорошо.
поддержу. в этом же фишка JVM, она не должна знать что находится «под ней».
Changes in Java SE 8u121 b34
[linux] Experimental support for cgroup memory limits in container (ie Docker) environments
http://bugs.java.com/view_bug.do?bug_id=8175898
-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
Спасибо, во время )))
Краткое содержание статьи: не ленитесь, используйте -Xmx в любых средах )
Старый добрый "хаваю памяти сколько хочу" :)
Я думал, что почти все сталкивались с этим, если даже я пару раз натыкался.
> Многие разработчики знают, или должны знать, что Java-процессы, исполняемые внутри контейнеров Linux (среди них — docker, rkt, runC, lxcfs, и другие), ведут себя не так, как ожидается.
А что ожидается от виртуальной машины внутри контейнера? — это как бы по определению ортогональные понятия :-)
А что ожидается от виртуальной машины внутри контейнера? — это как бы по определению ортогональные понятия :-)
Вообще если приложение запускается на сервере, то -Xmx должен быть задан в обязательном порядке. Ограничение на metaspace тоже желательно задавать. Другие ограничения по расходу памяти в OpenJDK так же присутствуют (для буферо машинного кода jit, offheap память и т.д.). Но если это все задавать, то какой смысл дублировать это через докер?
Я не проверял последние докеры, но LXC версии 2.x, ограничения у которых тоже реализуется средствами cgroup, корректно определяют доступные ресурсы внутри контейнера:
Debian
lxc 2.0.6-1~bpo8+1
kernel 4.9.13-1~bpo8+1
Посмотрите в сторону обновления докера и ядра.
# main
# free -m
total used free shared buffers cached
Mem: 32078 31807 271 2467 2165 21327
# container
# free -m
total used free shared buffers cached
Mem: 10240 5195 5044 2467 0 0
Debian
lxc 2.0.6-1~bpo8+1
kernel 4.9.13-1~bpo8+1
Посмотрите в сторону обновления докера и ядра.
как-то так:
$ uname --kernel-release
4.8.0-42-generic
$ docker version
Client:
Version: 17.03.0-ce
API version: 1.26
Go version: go1.7.5
Git commit: 3a232c8
Built: Tue Feb 28 08:01:32 2017
OS/Arch: linux/amd64
Server:
Version: 17.03.0-ce
API version: 1.26 (minimum version 1.12)
Go version: go1.7.5
Git commit: 3a232c8
Built: Tue Feb 28 08:01:32 2017
OS/Arch: linux/amd64
Experimental: false
$ docker run -it --memory="128M" debian:8 free -m
WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.
total used free shared buffers cached
Mem: 15925 4578 11347 160 236 1821
-/+ buffers/cache: 2519 13405
Swap: 0 0 0
Покопался в вопросе и таки решил:
LXC информирует контейнер о доступных ресурсах с помощью LXCFS. Если для контейнера это работает из коробки, то для докера нужно в ручную задать перемонтирование соответствующих файлов из /var/lib/lxcfs/proc/ в /proc/, например:
И ура:
Естественно, lxcfs нужно поставить в систему и, возможно, в ручную смонтировать:
У меня на сервере одновременно живёт и LXC и docker, потому лишних телодвижений делать не пришлось
LXC информирует контейнер о доступных ресурсах с помощью LXCFS. Если для контейнера это работает из коробки, то для докера нужно в ручную задать перемонтирование соответствующих файлов из /var/lib/lxcfs/proc/ в /proc/, например:
# like docker-compose
mem_limit: 512m
volumes:
- /var/lib/lxcfs/proc/meminfo:/proc/meminfo
И ура:
# docker exec CT_name free -m
total used free shared buffers cached
Mem: 512 13 499 4322 0 0
Естественно, lxcfs нужно поставить в систему и, возможно, в ручную смонтировать:
# mount | grep lxcfs
lxcfs on /var/lib/lxcfs type fuse.lxcfs (rw,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other)
У меня на сервере одновременно живёт и LXC и docker, потому лишних телодвижений делать не пришлось
да, в таком виде пашет:
$ docker run -it -v /var/lib/lxcfs/proc/meminfo:/proc/meminfo --memory="128M" debian:8 free -m
WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.
total used free shared buffers cached
Mem: 128 2 125 557 0 2
-/+ buffers/cache: 0 127
Swap: 0 0 0
Добавлю к «верному решению проблемы».
Вот такой вариант, как ниже (и в статье), лучше НЕ использовать, так как в зависимости от образа может привести к тому, что Ctrl-C и SIGTERM будет посылаться не java, а bash, что приводит к тому, что контейнер нельзя будет опустить — только убить. Например так себя ведут образы maven
Правильный вариант:
А куда же делся JAVA_OPTIONS, спросите вы?
В джава есть специальная переменная окружения для этого. Называется JAVA_TOOL_OPTIONS. Можно передавать и через `-e`, либо использовать сразу в Dockerfile через `ENV`
Вот такой вариант, как ниже (и в статье), лучше НЕ использовать, так как в зависимости от образа может привести к тому, что Ctrl-C и SIGTERM будет посылаться не java, а bash, что приводит к тому, что контейнер нельзя будет опустить — только убить. Например так себя ведут образы maven
CMD java -XX:+PrintFlagsFinal -XX:+PrintGCDetails $JAVA_OPTIONS -jar java-container.jar
Правильный вариант:
CMD ["java", "-XX:+PrintFlagsFinal", "-XX:+PrintGCDetails", "-jar", "java-container.jar"]
А куда же делся JAVA_OPTIONS, спросите вы?
В джава есть специальная переменная окружения для этого. Называется JAVA_TOOL_OPTIONS. Можно передавать и через `-e`, либо использовать сразу в Dockerfile через `ENV`
Если кто-то читает этот перевод спустя много лет — в оригинальной статье уже появились два обновления: от 15.03.2018 и 21.04.2018 про jdk9 и jdk10.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Java и Docker: это должен знать каждый