Java 8/9 brought support for -XX:+UseCGroupMemoryLimitForHeap
(with -XX:+UnlockExperimentalVMOptions
). This sets -XX:MaxRAM
to the cgroup memory limit. Per default, the JVM allocates roughly 25% of the max RAM, because -XX:MaxRAMFraction
defaults to 4.
Example:
MaxRAM = 1g
MaxRAMFraction = 4
JVM is allowed to allocate: MaxRAM / MaxRAMFraction = 1g / 4 = 256m
Using only 25% of the quota seems like waste for a deployment which (usually) consists of a single JVM process. So now people set -XX:MaxRAMFraction=1
, so the JVM is theoretically allowed to use 100% of the MaxRAM.
For the 1g example, this often results in heap sizes around 900m. This seems a bit high - there is not a lot of free room for the JVM or other stuff like remote shells or out-of-process tasks.
So is this configuration (-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1
) considered safe for prod or even best practice? Or should I still hand pick -Xmx
, -Xms
, -Xss
and so on?
They're not suitable for production usage! Therefore, it will require some tweaking so that your Docker engine can handle the load once in production environment. Moreover, your engine will be in charge of running the containers and nothing more.
Used properly, a Docker based system is both secure and efficient. Add in techniques like those mentioned above and you can reach a higher level of security than a pure VM based solution. So the answer is "yes" — Docker is safe for production.
Containerization involves bundling an application together with all of its related configuration files, libraries and dependencies required for it to run in an efficient and bug-free way across different computing environments. The most popular containerization ecosystems are Docker and Kubernetes.
We did some simple testing which showed that setting -XX:MaxRAM=$QUOTA
and -XX:MaxRAMFraction=1
results in killed containers under load. The JVM allocates more than 900M heap, which is way too much. -XX:MaxRAMFraction=2
seems safe(ish).
Keep in mind that you may want to leave headroom for other processes like getting a debug shell (docker exec
) or diagnostics in the container.
Edit: we've written up what we've learned in detail in an article. Money quotes:
TL'DR: Java memory management and configuration is still complex. Although the JVM can read cgroup memory limits and adapt memory usage accordingly since Java 9/8u131, it’s not a golden bullet. You need to know what
-XX:+UseCGroupMemoryLimitForHeap
does and you need to fine tune some parameters for every deployment. Otherwise you risk wasting resources and money or getting your containers killed at the worst time possible.-XX:MaxRAMFraction=1
is especially dangerous. Java 10+ brings a lot of improvements but still needs manual configuration. To be safe, load test your stuff.
and
The most elegant solution is to upgrade to Java 10+. Java 10 deprecates
-XX:+UseCGroupMemoryLimitForHeap
(11) and introduces-XX:+UseContainerSupport
(12), which supersedes it. It also introduces-XX:MaxRAMPercentage
(13) which takes a value between 0 and 100. This allows fine grained control of the amount of RAM the JVM is allowed to allocate. Since+UseContainerSupport
is enabled by default, everything should work out of the box.
Edit #2: we've written a little bit more about -XX:+UseContainerSupport
Java 10 introduced
+UseContainerSupport
(enabled by default) which makes the JVM use sane defaults in a container environment. This feature is backported to Java 8 since 8u191, potentially allowing a huge percentage of Java deployments in the wild to properly configure their memory.
The recent oracle-jdk-8(8u191) brings the following options to allow Docker container users to gain more fine grained control over the amount of system memory that will be used for the Java Heap:
-XX:InitialRAMPercentage
-XX:MaxRAMPercentage
-XX:MinRAMPercentage
Three new JVM options have been added to allow Docker container users to gain more fine grained control over the amount of system memory that will be used for the Java Heap:
-XX:InitialRAMPercentage -XX:MaxRAMPercentage -XX:MinRAMPercentage These options replace the deprecated Fraction forms (-XX:InitialRAMFraction, -XX:MaxRAMFraction, and -XX:MinRAMFraction).
See https://www.oracle.com/technetwork/java/javase/8u191-relnotes-5032181.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With