Copyright © 2018, Oracle and/or its affiliates. All rights reserved. |
Java in a World of Containers
コンテナ環境でJavaイメージを⼩さくする⽅法!
⽇本オラクル株式会社
伊藤 敬
@itakash
2018年12⽉11⽇ #OraCodeJP
⾃⼰紹介
伊藤 敬 @itakash
⽇本オラクル(株)所属
Java Cloud Serviceなどの製品担当
Javaコミュニティ活動等々
Copyright © 2018, Oracle and/or its affiliates. All rights reserved. |
Java in a World of Containers
3
コンテナの世界で期待されるのは
• 安全性とセキュリティはますます重要に
• スプロール現象
• 多数のインスタンス
• 異なるアプリケーションの混合
• 異なるアーキテクチャの混合
• 異なるコンテナ構成の混合
4
https://citelighter-cards.s3.amazonaws.com/p17k6i1bqs3okg8gnisklkg1k0_51924.png
Java in a World of Containers
• 管理されたランタイム・⾔語環境
• ハードウェア・OS に⾮依存
• JVM によって保証されたセキュリティと安全性
• 信頼性:設計⽬標 -> 互換性の維持
• 可搬性:実⾏環境が変更されても、JVM が安定した運⽤を保つ
• 豊富なエコシステム
5
コンテナ環境にとってJavaが持つ特長は理想的
• コミットメント:
コンテナ環境において最も適切な選択肢であることを維持する
でも現実には、
JavaのDockerイメージってデカくて使いづらい!
JavaのDockerイメージサイズ (〜JDK10)
• デフォルトのJDK を含むDockerイメージはデカい!
• 約 600MB
• 229MB:OS のベースイメージ
• 343MB:JDK
7
JRE とモジュール
• デフォルトのJDK を含むDockerイメージはデカい!
• 約 600MB
• 229MB OS のベースイメージ
• 343MB の JDK
• 必須モジュール
• java.{lang,util,…}.*,
javax.management.*, …
• 必須ではないモジュール
• java.xml, corba, javaws, …
8
JRE とモジュール
• デフォルトのJDK を含む Docker イメージは⼤きい
• 約 600MB
• 229MB OS のベースイメージ
• 343MB の JDK
• 必須モジュール
• java.{lang,util,…}.*,
javax.management.*, …
• 必須ではないモジュール
• java.xml, corba, javaws, …
• どこまで⼩さくできるか??
9
11
530MB
297MB
Copyright © 2018, Oracle and/or its affiliates. All rights reserved. |
カスタムJRE の作成
10
java.corba
java.se
java.se.ee
java.transaction
java.xml.ws
java.sql
java.sql.rowset
java.xml.bind
java.jnlp
java.activation
java.desktop
java.management.rmi
java.xml.crypto
java.transfer
java.compiler java.rmi
java.xml
java.instrument java.logging
java.management
java.naming
java.scripting
java.security.jgss
java.base
java.prefs
java.security.sasl
java.xml.ws.annotation
java.smartcardio
Java SE モジュール
ダイヤグラム
11
java.corba
java.se
java.se.ee
java.transaction
java.xml.ws
java.sql
java.sql.rowset
java.xml.bind
java.jnlp
java.activation
java.desktop
java.management.rmi
java.xml.crypto
java.transfer
java.compiler java.rmi
java.xml
java.instrument java.logging
java.management
java.naming
java.scripting
java.security.jgss
java.base
java.prefs
java.security.sasl
java.xml.ws.annotation
java.smartcardio
12
company.application
Java SE モジュール
ダイヤグラム
java.corba
java.se
java.se.ee
java.transaction
java.xml.ws
java.sql
java.sql.rowset
java.xml.bind
java.jnlp
java.activation
java.desktop
java.management.rmi
java.xml.crypto
java.transfer
java.compiler java.rmi
java.xml
java.instrument java.logging
java.management
java.naming
java.scripting
java.security.jgss
java.base
java.prefs
java.security.sasl
java.xml.ws.annotation
java.smartcardio
13
company.application
Java SE モジュール
ダイヤグラム
Java のカスタムランタイム:カスタムJRE
14
java.sql
java.sql.rowset
java.activation
java.transfer
java.xml
java.logging
java.naming
java.base
company.application
カスタムJRE とモジュール
• JDK 9 でモジュールシステムが導⼊ (“Jigsaw”)
• JDK ⾃体をモジュール化
• カスタム JRE を⽣成するツール: jlink
• アプリが必要とするモジュールや機能だけを含む
• 最も⼩さい JRE は java.base のみを含む
• 多くのアプリケーションの稼働はこれだけでカバーできる
15
jlink と jdeps の利⽤
• カスタム JRE の作成は簡単:
$JAVA_HOME/bin/jlink --output myjre --add-modules java.base
• jdeps でアプリが利⽤するモジュールを特定する
$JAVA_HOME/bin/jdeps HelloWorld.class
• 重要:アプリケーション⾃体のモジュール化は不要
16
Custom JRE
my.module
java.managem
ent
java.base
jdeps
jdeps でアプリが利⽤するモジュールを特定する
# $JAVA_HOME/bin/jdeps lib/tomcat-api.jar
tomcat-api.jar -> java.base
tomcat-api.jar -> java.instrument
tomcat-api.jar -> java.naming
...
17
マルチステージビルドを利⽤し、
カスタム JRE の Dockerイメージを作成
# Multi-Stage example using jlink to produce small Java runtime
FROM oraclelinux:latest AS java-build
ADD openjdk-11+28_linux-x64_bin.tar.gz /opt/jdk
ENV PATH=/opt/jdk/jdk-11/bin:$PATH
WORKDIR /jlink
RUN jlink --output my-jre --add-modules java.base
FROM oraclelinux:latest
WORKDIR /workdir
COPY --from=java-build /jlink/my-jre /opt/my-jre
ENV PATH /opt/my-jre/bin:$PATH
CMD [”java”, “-version”]
18
Copyright © 2018, Oracle and/or its affiliates. All rights reserved. |
イメージサイズの最適化
19
カスタムの Java ランタイム
• デフォルトのJDK を含む Docker イメージ
は⼤きい: ~530 MB
• 必要なもの
• java.{lang,util,…}.*, javax.management.*, …
• 必要ではないもの
• corba, jaxws, …
• JDK 9 でモジュールシステムが導⼊
(“Jigsaw”)
• JDK ⾃体をモジュール化
• カスタムの JRE を⽣成するツール
• アプリが必要とするモジュールや機能だけを含む
20
Java Docker image Size
Size(MB)
0
150
300
450
600
Size (MB)
297
234
oraclelinux:7
JDK
JRE サイズの最適化
• java.base のみ
• 多くのアプリケーションにとって⼗分
• Netty
• 多くの(過半数?)のアプリにとって
⼗分なモジュール:
• java.base,java.logging,java.management,
java.xml,jdk.management,jdk.unsupported
• ただし、Netty ⾃体は含まれていない
• 更に最適化することが可能
• jlink --compress (25%+ の圧縮)
21
JRE Sizes
Size(MB)
0
50
100
150
200
250
300
Full JDK java.base “netty”
60
48
297
ベースイメージ(OS)サイズの最適化
• Dockerイメージが⼤きくなる要因の
⼀つ
• OSのフルイメージから機能削除
• 最低限:Java が実⾏出来る
• ”slim” イメージ
• ユーザスペースの機能の殆どを除いた
もの
22
Docker image sizes (java.base)
Size(MB)
0
50
100
150
200
250
300
oraclelinux:7 oraclelinux:7-slim
48
48
117
234 Base Image
java.base
Alpine Linux と musl libc
Alpine Linux:
musl libc と busybox ベースの
セキュリティを中⼼した軽量
Linux ディストリビューション
⼩さくてシンプル、安全
https://www.alpinelinux.org
23
musl libc:
標準Cライブラリ(libc)互換のC
ライブラリ
標準に準拠しつつ安全
⾼速でシンプル、かつ軽量な
libc実装
https://www.musl-libc.org
OpenJDK Project “Portola”
• Alpine/musl 対応の JDK 提供を実現
するプロジェクト
• Alpine Linux は極端に軽い
(4.4MB)
• ご興味あれば是⾮チェック!
• http://openjdk.java.net/projects/portola
• http://hg.openjdk.java.net/portola/portola
• portola-dev@openjdk.java.net
• Early access binaries:
http://jdk.java.net/12
24
Docker image sizes (java.base)
Size(MB)
0
75
150
225
300
oraclelinux:7 oraclelinux:7-slim alpine:3.8
48
48
48
4.4
117
234
Base Image
java.base
One more thing…
• 理論的な最低限
• java.base のみの JRE には何が含まれているか
26
Files Size (bytes)
lib/modules 23,529,047
lib/server/libjvm.so 21,197,904
<その他のファイル> 1,545,818
合計 46,272,769
JVM ランタイム・ライブラリ
JVM のサイズ
27
(近似計算)
JVM のサイズ ‒ JIT コンパイラ
28
JVM のサイズ ‒ GC
29
JVM のサイズ ‒ ⼀番軽い GC: Serial
30
JVM のサイズ ‒ その他
31
• 5MB 未満!
• Java SE の仕様を準拠
• しかし: 機能は乏しい
• JIT なし
• Serial GC のみ
• デバッグや保守性などの機能は殆
どなし
• 現実的ではないが、研究など
の⽬的には役に⽴つ
“最⼩” JVM
3
2
Size of JVM variants
Size(MB)
0.0
5.0
10.0
15.0
20.0
25.0
server minimal
• 約20MB のHelloWorld
• Alpine ベースイメージ込み
• 最⼩イメージより⼩さな JVM
も存在する(制限付き)
• Oracle Labs の SubstrateVM
https://www.oracle.com/technetwork
/java/jvmls2015-wimmer-2637907.pdf
“最⼩” のDocker向けJavaイメージ
3
3
“minimal” VM + java.base
Size(MB)
0.0
10.0
20.0
30.0
40.0
default —compress=2 —strip-debug
10.5
12.9
25.3
4.84.84.8
4.04.04.0
alpine:3.6
libjvm.so
JDK
これで限界?
これで限界?
• まだできることがあります!
インスタンス間ファイル共有
• マイクロサービス・ベースのシステムにおいてコンテナの利⽤する
場合、同じマシン上で多数のプロセスを実⾏する
• 全く同じアプリを実⾏するインスタンスが多い可能性が⾼い
• ネイティブ データは OS のライブラリによって共⽤される
• libc, libjvm.so などは OS と Docker によって共⽤される
• 前提:同じ layer/file/inode
• 例:共⽤された Docker イメージに含まれている JRE やボリュームを利⽤し
た明⽰的な共⽤
• docker run –v /shared/java:/jre … (container 1)
• docker run –v /shared/java:/jre … (container 2, etc.)
• Javaクラスのデータは?
36
• OS の共⽤ライブラリに類似した
Javaクラス、データを共有する
仕組み
• クラス、データはメモリにマップ
• 共有されたメモリからクラスを直
接読み込む
• ROページ:共有
RW ページ:copy-on-write
• Jar ファイルの検索や分析処理の負
荷はない
• アーカイヴは複数の Docker コン
テナによって共⽤される
Class Data Sharing (CDS)
3
7
38
JDK 12 起動時間 (CDS アーカイブ)
Copyright © 2018, Oracle and/or its affiliates. All rights reserved. |
まとめ
39
まとめ
• デフォルトのままのイメージは⼤きい
• JDK 11: 229MB + 300MB = 529MB
• サイズを極限まで⼩さくする
• jlink でカスタム JRE を作成
• “Netty” は 60MB, “java.base” は 48MB (jlink ‒compressed=2 の場合:~38MB)
• 適切なベースイメージを利⽤
• oraclelinux:7-slim は 117MB, alpine は 4MB
• JVM を含む HelloWorld は 38MB 未満のイメージでデプロイ出来る
• CDS で複数の JVM や Docker コンテナでクラスのデータを共⽤できる
40
Java の Dockerイメージを最適化する
Copyright	©	2018, Oracle	and/or	its	affiliates.	All	rights	reserved.		|
Copyright	©	2018, Oracle	and/or	its	affiliates.	All	rights	reserved.		|

コンテナ環境でJavaイメージを小さくする方法!