Java 8でも安心。Dockerに対するCPU・メモリ対応。(2018年11月現在)

8u191でDocker対応がバックポートされたので、頭の整理と確認をしておいた。

## まとめ

Java 11使っておけばそもそも安心なんだけど、Java 8でも8u191以降を使えば安心

## 課題だったこと

DockerでJavaを動かすときJavaが「そのコンテナに割り当てられたCPU・メモリ」じゃなくて「Dockerが動いてるHostのCPU・メモリ」を見てしまうことが課題だった。

## Java 10以降

Java 10以降なら「そのコンテナに割り当てられたCPU・メモリ」を見る対応が入ってるから安心になった。

## Java 8は?

Java 8で入ってた対応は8u131のこれ:

詳しくはここに書いてある:

メモリ用のオプションが追加されたので、それをつければメモリの認識は大丈夫。CPUは一部対応。という話。

そのメモリ用のオプションは将来的につけなくても大丈夫にする予定だったからExperimental扱い(そして実際にJava 10以降でも8でもつけなくてよくなった)。という感じ。

## 8u191

そして、Java 10の対応が8u191でバックポートされたのでJava 8でも8u191以降なら安心になった。今の最新は8u192かな。

(∩´∀`)∩ワーイ

## 追加されてるオプション

  • -XX:-UseContainerSupportをつけるとこのコンテナサポートをオフにできる。
  • -XX:ActiveProcessorCount=countを指定すると自分でプロセッサーカウントを設定できる。

## 参照

## 確かめる

てことで確かめてみる。いつも通り、確認したいこととは関係ないところで色々勉強になったや。

  • 8u181
    • 制限なしでどうなるかを見ておく(ベースライン)
    • コンテナ制限を見てないことを確認
    • メモリオプションつけたらメモリは認識されることを確認
  • 8u192
    • 制限なしでどうなるかを見ておく(ベースライン)
    • コンテナ制限を見てることを確認
  • 11 (11.0.1.13)
    • 制限なしでどうなるかを見ておく(ベースライン)
    • コンテナ制限を見てることを確認

くらいでいいかな。8u191以降のOpenJDKのDockerイメージはまだ出てないみたいなので、AdoptOpenJDKで確認することにした。初めて使う!

実行環境はこんな感じ

❯ docker version
Client:
 Version:      18.03.1-ce
 API version:  1.37
 Go version:   go1.9.5
 Git commit:   9ee9f40
 Built:        Thu Apr 26 07:17:38 2018
 OS/Arch:      linux/amd64
 Experimental: false
 Orchestrator: swarm

Server:
 Engine:
  Version:      18.03.1-ce
  API version:  1.37 (minimum version 1.12)
  Go version:   go1.9.5
  Git commit:   9ee9f40
  Built:        Thu Apr 26 07:15:45 2018
  OS/Arch:      linux/amd64
  Experimental: false

❯ docker-compose version
docker-compose version 1.23.1, build b02f1306
docker-py version: 3.5.0
CPython version: 3.6.7
OpenSSL version: OpenSSL 1.1.0f  25 May 2017

## 実行する内容

これを実行する。こんなところ気にしたことなかったからavailableProcessorsとかmaxMemoryとか初めて使った。バージョンはRuntime.Versionってのがあったから使おうとしたら導入されたのがJava 9やったから使えんかったw

public class A {
  public static void main(String[] args) {
    System.out.println("Version: " + System.getProperty("java.version"));
    System.out.println("availableProcessors: " + Runtime.getRuntime().availableProcessors());
    System.out.println("maxMemory: " + Runtime.getRuntime().maxMemory()/1024/1024 + "M");
  }
}

## 設定周り

docker直接でやっても良かったんだけど、docker-composeでごにょごにょやった。

# use v2 because v3 stop supporting cpu and memory options.
version: "2.4"

x-common: &common
  command: sh -c "javac A.java -d /tmp && cd /tmp && java A"
  environment:
    JAVA_TOOL_OPTIONS: ""
  working_dir: /work
  volumes:
    - .:/work

services:

  # jdk8u181
  jdk8u181-base: &jdk8u181-base
    image: adoptopenjdk/openjdk8:jdk8u181-b13-alpine
    <<: *common
  jdk8u181-limit: &jdk8u181-limit
    <<: *jdk8u181-base
    cpus: 2
    mem_limit: 512m
  jdk8u181-limit-option:
    <<: *jdk8u181-limit
    environment:
      JAVA_TOOL_OPTIONS: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap"

  # jdk8u192
  jdk8u192-base: &jdk8u192-base
    image: adoptopenjdk/openjdk8:jdk8u192-b12-alpine
    <<: *common
  jdk8u192-limit:
    <<: *jdk8u192-base
    cpus: 2
    mem_limit: 512m

  # jdk-11
  jdk-11-base: &jdk-11-base
    image: adoptopenjdk/openjdk11:jdk-11.0.1.13-alpine
    <<: *common
  jdk-11-limit:
    <<: *jdk-11-base
    cpus: 2
    mem_limit: 512m

### Compose file v2を使ってる理由

v3ではcpusmem_limit周りの機能が削除されてるから。悲しみ。

docker-compose におけるメモリ使用量の制限方法 - reboooot.net

結局、v3はSwarm Mode用だから、それ使わんならv2使いなよってことらしい。Docker社っぽいやり方だなw

How to specify Memory & CPU limit in version 3 · Issue #4513 · docker/compose · GitHub

### YAMLのAnchorについて

YAMLのAnchorはこの辺を参考に:

Don’t Repeat Yourself with Anchors, Aliases and Extensions in Docker Compose Files

Compose fileのExtension fields (x-)についてはここを参考に:

Compose file version 2 reference | Docker Documentation

今回は遊びだから適当に使ったけど、実際に仕事とかで使うときは「DRYにしすぎて意味がわからない」ってならないようにしたいね。

### JAVA_TOOL_OPTIONS

AdoptOpenJDKのイメージにはJAVA_TOOL_OPTIONSが設定されてるので、今回の検証ではそれを一旦空にしてから動かしてる。

@sugarlifeさんありがとうございます!OpenJDKのソースコード初めて読んだw

ちなみに設定されている値はこんな感じ。勉強になるー。

javacとかjavaを実行したときに毎回ログに出るからうざいなと思って消せないか探してみたけど

[JDK-8039152] Need a way to suppress message when picking up JAVA_TOOL_OPTIONS - Java Bug System

This will not be implemented, as it may introduce a vulnerability

ってことで脆弱性につながるから実装しないってことみたい。申し訳ございませんでした。納得。

## 実行スクリプト

docker-compose upするとログが混ざるから、こんなスクリプトを用意した。

#!/bin/bash

list=(
  jdk8u181-base
  jdk8u181-limit
  jdk8u181-limit-option
  jdk8u192-base
  jdk8u192-limit
  jdk-11-base
  jdk-11-limit
)

for item in ${list[@]}; do
  echo "# $item"
  docker-compose run --rm $item
  echo ""
done

## 結果

ちなみに、JAVA_TOOL_OPTIONSが2回出てるのはjavacの分とjavaの分。

❯ ./check.sh                                                                                                                                                                                           
# jdk8u181-base                                                                                                                                                                                        
Picked up JAVA_TOOL_OPTIONS:                                                                                                                                                                           
Picked up JAVA_TOOL_OPTIONS:
Version: 1.8.0_181
availableProcessors: 4
maxMemory: 3504M

# jdk8u181-limit
Picked up JAVA_TOOL_OPTIONS: 
Picked up JAVA_TOOL_OPTIONS: 
Version: 1.8.0_181
availableProcessors: 4
maxMemory: 3504M

# jdk8u181-limit-option
Picked up JAVA_TOOL_OPTIONS: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
Picked up JAVA_TOOL_OPTIONS: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
Version: 1.8.0_181
availableProcessors: 4
maxMemory: 114M

# jdk8u192-base
Picked up JAVA_TOOL_OPTIONS: 
Picked up JAVA_TOOL_OPTIONS: 
Version: 1.8.0_192
availableProcessors: 4
maxMemory: 3504M

# jdk8u192-limit
Picked up JAVA_TOOL_OPTIONS: 
Picked up JAVA_TOOL_OPTIONS: 
Version: 1.8.0_192
availableProcessors: 2
maxMemory: 123M

# jdk-11-base
Picked up JAVA_TOOL_OPTIONS: 
Picked up JAVA_TOOL_OPTIONS: 
Version: 11.0.1
availableProcessors: 4
maxMemory: 3942M

# jdk-11-limit
Picked up JAVA_TOOL_OPTIONS: 
Picked up JAVA_TOOL_OPTIONS: 
Version: 11.0.1
availableProcessors: 2
maxMemory: 123M

想定通りの結果だね。今日のソースコードはここ。

github.com

## 本筋とは関係ないところで勉強になったこと

  • AdoptOpenJDK使った
  • availableProcessorsmaxMemoryを知った
  • Runtime.VersionJava 9からだと知った(以前に一度確認したことがあったような気がしなくもない
  • JAVA_TOOL_OPTIONSの存在を知った
  • OpenJDKのソースコード初めて読んだ
  • JAVA_TOOL_OPTIONSが使われてることをログから消すことはできないってことを知った
  • Compose fileのCPU・メモリ制限がv2までで、v3はSwarm Modeサポート用だと知った
  • YAMLのAnchorについて勉強しなおした
  • Compose fileのExtension fieldsの存在を知った

面白かったー(∩´∀`)∩ワーイ