Docker and Java

By Maurizio Farina | Posted on October 2017 | DRAFT

This tutorial wants to collect all useful information about the Java applications running in a container.

Docker Therminology

  • Images: The file system and configuration of application. Official repositories on Docker Hub
    • Base image: image without parent (for example alpine)
    • Child image: image built on on base image (for example application)
  • Docker Registry: a service for storing and accessing Docker images; for example Docker Hub for public images; Docker Store for private images and Docker Registry used for private registry on-premises. It is possible install Docker registry on-premise
  • Docker daemon - The background service running on the host that manages building, running and distributing Docker containers.
  • Containers - Running instances of Docker images. A container includes an application and all its dependencies. It shares the kernel with other containers, and runs as an isolated process in user space on the host OS.
  • Docker Service: in a distributed application a service is just a piece of the app. In Docker ecosystem Services are just "containers in production" for which is possible to design the horizontal scaling (how many replicas of the cointainer should run).
  • Docker Swarm: A group of machines that are running Docker and joined into a cluster. All Docker commands are still the same but they are executed on the cluster by a Swarm Maanager.
  • Docker Stack: a group of services. The stack definition is generally based on the dependence that the services have on each other
  • Moby: An open framework to assemble specialized container systems without reinventing the wheel.
  • LinuxKit, a toolkit for building custom minimal, immutable Linux distributions.

Premise

What happens when a Java application is executed?

JVM detects the host resources to adjust internal parameters. Resources as:

  • CPU: cores and the numbers
  • RAM: amount of available memory

For example, the resources impact on the number of garbage collector threads accordingly.

What happens when a Java application is running in a container?

The container allows to specify limits for memory, cpu, filesystem and networking for the process running inside a container: the Java runtime is unaware of this limits or better is unable to retrieve them. The Java runtime could use more resources than are available and then causing performance degradation or even the process termination.

Java Bug Tracker: JDK-8182070 - Container aware Java runtime

"Enhance the JVM and Core libraries to detect running in a container and adapt to the system resources available to it. This JEP will only support Docker on Linux-x64 although the design should be flexible enough to allow support for other platforms and container technologies. The initial focus will be on Linux low level container technology such as cgroups so that we will be able to easily support other container technologies running on Linux in addition to Docker".

Example

1
docker run -it --name wild_web -m=10m jboss/wildfly

Docker will try to start the new container but most probabily you will see the following message:

1
*** JBossAS process (55) received KILL signal ***

Try to execute the following command:

1
docker inspect --format "{{json .State}}" wild_web

The output

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "Status": "exited",
  "Running": false,
  "Paused": false,
  "Restarting": false,
  "OOMKilled": true,
  "Dead": false,
  "Pid": 0,
  "ExitCode": 0,
  "Error": "",
  "StartedAt": "2017-10-27T16:54:06.75350627Z",
  "FinishedAt": "2017-10-27T16:54:11.145707492Z"
}

Note

When the "-m" parameter is specified the Docker engine allocate the same memory for Ram and SWAP. So, if the Docker container is run with "-m=10m" this means 10Mbyte for RAM and 10Mbyte for Swap. Docker allows to manage different size for RAM and Swap. See User memory constraints.

A good approach is the add -XX:+PrintFlagsFinal -XX:+PrintGCDetails options to JVM to report all GC activities so it will be possible to have this info from "docker logs"

1
docker logs wild_web | grep -i MaxHeapSize

Solutions

Container technology is becoming prevalent in public/private/hybrid cloud based applications. The resource limit options helps to handle correctly the size of infrastructure to allocate.

-Xmx JVM options

A simple solution is to specify -Xmx option in Docker file. A smart approah is using a Docker variable JAVA_OPTIONS to use in Docker file to execute Docker container with the maximum memory allocale.

1
docker run -it --name wild_web -m 800M -e JAVA_OPTIONS='-Xmx800m' jboss/wildfly

OpenJDK - Project Portola

From this post Java SE support for Docker CPU and memory limits it seems the problem about running java in a container it is fixed in OpenJDK.

The OpenJDK 8 - Apline fixs this issue.

1
java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap

Windows Server containers are not supported

To prevent excessive memory allocations, -XX:MaxRAM=... option must be specified with the value that is not bigger than a containers RAM limit.

Follow this official Docker documentation to manage container using resource constraints.