Buy @ Amazon

Is your Java app, container ready?

 If you miss this, you will end up in exclaiming, "But it works in my machine!!..", when your app crashes in production environment that is containerized. This is one of those situations, that remind us that tech is hard and demands preparation.

Containers are for modern apps that run on modern platform. If you are having apps that are dependent on JRE prior to version 8.x, you are dealing with legacy apps that aren't container ready. 

Simplistically speaking (which is enough for this context), a container is in reality a single process which provides isolation by leverage cgroups and namespaces of Linux operating systems. Unfortunately though, these doesn't isolate CPU and Memory of the host. If configured for a container, the container-orchestrator (say, Docker Swarm) keeps a tab at the usage in real-time against this configuration and when a container constantly breaches the configured threshold, it marks the container as unhealthy and kills the process it considers as rogue, thus crashing your application.

Now the way JVM works by default is that it tunes and manages itself by looking at 2 key environmental metrics -- the CPU and the memory. Any JVM older than Java 8.x is not container aware and thus will access metrics from the host operating system and not from the container itself. Do you now see the problem? By ignoring the fact that it is running in a limited container environment (which typically is a subset of the host OS) and imagining that it has all the host CPU and memory for itself, its operational strategy will go wrong leading to application crashes.

Starting JRE 8.x (where `x` depends on your vendor), the support for containers were introduced. The JVM can recognize the memory and CPU configurations of the container in which it is running. But you got to enable it for your JVM to make it container-aware. 

In case of Oracle JVM, you do it with below jvm settings:

  • Memory : Set the following flags:
    • XX:+UseCGroupMemoryLimitForHeap
    • XX:+UnlockExperimentalVMOptions
    • XX:MaxMetaspaceSize=<your_cgroup_limit>MB
  • CPU : Manually overwrite the following parameters based on your cgroup limits configured for the app:
    • XX:ParallelGCThreads
    • XX:ConcGCThreads

References