Oracle by Example brandingConfigure and Test JDK 10 Docker Container Integration

section 0Before You Begin

This 15-minute tutorial shows you how to set processor and memory constraints in a Docker container and test if Java recognizes the constraints. It also shows you how to generate OutOfMemoryError exceptions programmatically and test Docker container integration with Java.

Background

Docker is a popular technology for containerizing Java Virtual Machine (JVM) applications. When deployed, it offers consistent environments for development, deployment, and proper isolation between applications.

In Java Platform, Standard Edition Development Kit 9 (JDK 9) and earlier, the JVM didn’t recognize the resource constraints in a Docker container, because it fetched processor and memory configurations from the underlying host instead of the Docker container. This issue was resolved in JDK 10, and the JVM now automatically recognizes the constraints set by a Docker container, tunes itself, and presents the available resources to the Java application that is running inside the Docker.

It is important to note that this issue is currently being addressed in JDK 8.

To help you understand how Docker integration was enhanced in JDK 10, the examples in this tutorial show commands for JDK 8 and JDK 10.

What Do You Need?


section 1Set the Processor Constraints to Test JDK 8 Docker Container Integration

  1. Open a Linux terminal and log in as a root user.
  2. Browse to the docker_java_obe/core_check directory.
  3. Check the number of available runtime processors for the host machine.

    # lscpu | grep "CPU"

    In this example, the number of available processors is 4.

    CPU op-mode(s):        32-bit, 64-bit
    CPU(s):                4
    On-line CPU(s) list:   0-3
    CPU family:            6
    Model name:            Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz
    CPU MHz:               2295.021
    NUMA node0 CPU(s):     0-3
  4. Open the Dockerfile file in the Linux text editor.

    # vi Dockerfile

  5. To ensure that the Docker container uses JDK 8 to build the image, press Insert and set the FROM openjdk: field to 8.

    After you edit the file, the content should look similar to this:

    FROM openjdk:8;
    ADD CoreCheck.java .
    WORKDIR .
    RUN javac CoreCheck.java
    CMD ["java", "-showversion", "CoreCheck" ]
  6. Save the file and exit.
  7. Build a Docker image named corecheck8.

    # docker build -t corecheck8 .

    The output should look similar to this sample.

  8. Run the corecheck8 Docker image.

    # docker run corecheck8

    In this example, the number of available processors is 4.

    openjdk version "1.8.0_181"
    OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-1~deb9u1-b13)
    OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
    4
  9. In the Docker container, run the corecheck8 Docker image with the processor share set to 2048, to provide two CPU time allocations for the Java application inside the Docker.

    # docker run --cpu-shares 2048 corecheck8

    In this example, the total number of available processors is 4.

    openjdk version "1.8.0_181"
    OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-1~deb9u1-b13)
    OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
    4

    Ideally, the output should have been 2, which is half of the available processor time (2048/1024). JDK 8 doesn’t recognize the Docker container limits because the JVM reads the processor configuration from the OS of the host machine, not from the Docker container.


section 2Set the Processor Constraints to Test JDK 10 Docker Container Integration

  1. Open the Dockerfile file in the text editor.

    # vi Dockerfile

  2. To ensure that the Docker container uses JDK 10 to build the image, press Insert and set the FROM openjdk: field to 10.

    After you edit the file, the content should look similar to this:

    FROM openjdk:10
    ADD CoreCheck.java .
    WORKDIR .
    RUN javac CoreCheck.java
    CMD ["java", "-showversion", "CoreCheck" ]
  3. Save the file and exit.
  4. Build a Docker image named corecheck10.

    # docker build -t corecheck10 .

    The output should look similar to this sample.

  5. Run the corecheck10 Docker image.

    # docker run corecheck10

    In this example, the number of available processors is 4.

    openjdk version "10.0.2" 2018-07-17
    OpenJDK Runtime Environment (build 10.0.2+13-Debian-1)
    OpenJDK 64-Bit Server VM (build 10.0.2+13-Debian-1, mixed mode)
    4
  6. In the Docker container, run the corecheck10 Docker image with the processor share set to 2048, to provide two CPU time allocations for the Java application inside the Docker.

    # docker run --cpu-shares 2048 corecheck10

    In this example, the total number of available processors is 2, and it’s half of the available processor time (2048/1024).

    openjdk version "10.0.2" 2018-07-17
    OpenJDK Runtime Environment (build 10.0.2+13-Debian-1)
    OpenJDK 64-Bit Server VM (build 10.0.2+13-Debian-1, mixed mode)
    2

    JDK 10 is a Docker-aware version and recognizes the processor limits within the Docker container. The JVM reads the processor configuration from the Docker container, not from the host machine.


section 3Set the Memory Constraints to Test JDK 8 Docker Container Integration

  1. Browse to the docker_java_obe/memory_check directory.
  2. Check the total available physical memory of the host machine.

    # free

    In this example, the total available physical memory is 14745848 KB.

                  total        used        free      shared  buff/cache   available
    Mem:       14745848      323896    11484064       17232     2937888    14235580
    Swap:       7167984           0     7167984
  3. Open the Dockerfile file in the text editor.

    # vi Dockerfile

  4. Press Insert and set the FROM openjdk: field to 8.

    After you edit the file, the content should look similar to this:

    FROM openjdk:8
    ADD MemoryCheck.java .
    WORKDIR .
    RUN javac MemoryCheck.java
    CMD ["java", "-showversion", "MemoryCheck" ]
  5. Save the file and exit.
  6. Build a Docker image named memorycheck8.

    # docker build -t memorycheck8 .

    The output should look similar to this sample.

  7. Run the memorycheck8 Docker image.

    # docker run memorycheck8

    In this example, the available memory is 3357540352 B, which is equal to approximately one-fourth of the physical memory ((14745848*1024)/4).

    openjdk version "1.8.0_181"
    OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-1~deb9u1-b13)
    OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
    
    3357540352
  8. In the Docker container, run the memorycheck8 image with the memory limit set to 100 MB.

    # docker run --memory 100m memorycheck8

    In this example, the available memory is 3357540352 B.

    openjdk version "1.8.0_181"
    OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-1~deb9u1-b13)
    OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
    
    3357540352

    Ideally, the output should have been approximately 50 MB (100/2), which is half of the Docker memory limit that you set. JDK 8 doesn’t recognize the Docker container limits because the JVM reads the memory configuration from the OS of the host machine, not from the Docker container.


section 4Set the Memory Constraints to Test JDK 10 Docker Container Integration

  1. Open the Dockerfile file in the text editor.
  2. # vi Dockerfile

  3. Press Insert and set the FROM openjdk: field to 10.

    After you edit the file, the content should look similar to this:

    FROM openjdk:10
    ADD MemoryCheck.java .
    WORKDIR .
    RUN javac MemoryCheck.java
    CMD ["java", "-showversion", "MemoryCheck" ]
  4. Save the file and exit.
  5. Build a Docker image named memorycheck10.

    # docker build -t memorycheck10 .

    The output should look similar to this sample.

  6. Run the memorycheck10 Docker image.

    # docker run memorycheck10

    In this example, the available memory is 3776970752 B, which is equal to approximately one-fourth of the physical memory ((14745848*1024)/4).

    openjdk version "10.0.2" 2018-07-17
    OpenJDK Runtime Environment (build 10.0.2+13-Debian-1)
    OpenJDK 64-Bit Server VM (build 10.0.2+13-Debian-1, mixed mode)
    3776970752
  7. In the Docker container, run the memorycheck10 image with the memory limit set to 100 MB.

    # docker run --memory 100m memorycheck10

    In this example, the available memory is 50724864 B (approximately 50 MB), which is half of the value of the Docker memory limit (100 MB) that you set.

    openjdk version "10.0.2" 2018-07-17
    OpenJDK Runtime Environment (build 10.0.2+13-Debian-1)
    OpenJDK 64-Bit Server VM (build 10.0.2+13-Debian-1, mixed mode)
    50724864

    JDK 10 is a Docker-aware version and recognizes the memory limits within the Docker container. The JVM reads the memory configuration from the Docker container, not from the host machine.


section 5Generate OutOfMemoryError to Test JDK 8 Docker Container Integration

  1. Browse to the docker_java_obe/oom_check directory.
  2. Open the Dockerfile file in the text editor.

    # vi Dockerfile

  3. Press Insert and set the FROM openjdk: field to 8.

    After you edit the file, the content should look similar to this:

    FROM openjdk:8
    ADD TestOOM.java .
    WORKDIR .
    RUN javac TestOOM.java
    CMD ["java","-showversion","TestOOM" ]
  4. Save the file and exit.
  5. Build a Docker image named oom8.

    # docker build -t oom8 .

    The output should look similar to this sample.

  6. Run the oom8 Docker image.

    # docker run oom8

    In this example, the output prints All good, which indicates that the JVM did not run out of heap memory space.

    openjdk version "1.8.0_181"
    OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-1~deb9u1-b13)
    OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
    
    All good
  7. In the Docker container, run the oom8 Docker image with the memory constraint set to 100 MB, to exhaust the heap memory space.

    # docker run --memory 100m oom8

    In this example, the output prints nothing.

    openjdk version "1.8.0_181"
    OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-1~deb9u1-b13)
    OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
    
    

    Ideally, the JVM should have thrown an OutOfMemoryError exception. Instead, it claimed more memory and went over the Docker limits. Because the JVM didn’t throw an exception, the Docker ended the Java process inside the container. JDK 8 doesn't recognize the memory constraints set inside a Docker container.


section 6Generate OutOfMemoryError to Test JDK 10 Docker Container Integration

  1. Open the Dockerfile file in the text editor.

    # vi Dockerfile

  2. Press Insert and set the FROM openjdk: field to 10.

    After you edit the file, the content should look similar to this:

    FROM openjdk:10
    ADD TestOOM.java .
    WORKDIR .
    RUN javac TestOOM.java
    CMD ["java","-showversion","TestOOM" ]
  3. Save the file and exit.
  4. Build a Docker image named oom10.

    # docker build -t oom10 .

    The output should look similar to this sample.

  5. Run the oom8 Docker image.

    # docker run oom10

    In this example, the output prints All good, which indicates that the JVM did not run out of heap memory space.

    openjdk version "10.0.2" 2018-07-17
    OpenJDK Runtime Environment (build 10.0.2+13-Debian-1)
    OpenJDK 64-Bit Server VM (build 10.0.2+13-Debian-1, mixed mode)
    All good
  6. In the Docker container, run the oom10 Docker image with the memory constraint set to 100 MB, to exhaust the heap memory space.

    # docker run --memory 100m oom10

    In this example, the output prints OutOfMemoryError.

    openjdk version "10.0.2" 2018-07-17
    OpenJDK Runtime Environment (build 10.0.2+13-Debian-1)
    OpenJDK 64-Bit Server VM (build 10.0.2+13-Debian-1, mixed mode)
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
            at TestOOM.main(TestOOM.java:3)

    JDK 10 is a Docker-aware version. The JVM recognizes the memory limits inside a Docker container and throws an OutOfMemoryError exception when it runs out of heap memory space.


more informationWant to Learn More?