Copyright © 2017, Oracle and/or its affiliates. All rights reserved.
CON4429 -‐ Java in a World of Containers
[email protected] @PaulSandoz [email protected] Director, Java Virtual Machine @MikaelVidstedt
1
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
2
Producing images and running containers with JDK 9
Size analysis of JDK Docker Images
A quick look at startup Tme
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Java 8 Docker image • Official Java 8 SE (Server JRE) available on the docker store • See also DockerFiles on GitHub
3
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
In a world of containers we expect… • Many distribuTons of Java runTmes • Forces that push towards – Smaller images – Faster execuTon using less resources (and respecTng resource constraints)
4
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Java has plans for a world of containers • Official OpenJDK builds will make it easier to distribute Java runTmes • Java 9 tooling can produce custom Java runTmes that are smaller • Current and future Java tooling will produce applicaTon-‐specific Java runTmes that startup faster
5
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Producing Docker images with a JDK • Very easy to create a DockerFile that copies (or adds) a tarball of a JDK – A resulTng Docker image will be large (> 300MB)
• Not necessarily good for development or execuTon – More stuff than required to build or run an applicaTon
6
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
JDK 9 is modular • JDK 9 is modular and introduces modules to the Java plagorm • A module is a set of packages designed for reuse • Modules improve the reliability and maintainability of your programs • JDK 9 is itself composed of 79 modules
7
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
JDK 9 and custom Java runTmes • JDK 9 comes with jlink, a tool that can create custom Java runTmes – Such as, a Java runTme consisTng of just the java.base module
• Note: the Java applicaTon need not be modular
8
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Project Portola and Alpine Linux • The OpenJDK Portola Project aims to provide a port of the JDK to the Alpine Linux distribuTon • Early access builds of the JDK port are available • jlink can be used to create custom Java runTmes for Alpine Linux
9
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Demo Crea%ng Docker images with Alpine Linux, Java, and jlink
10
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Running JDK 9 in Docker containers • The JDK has not necessarily been a model ciTzen and respecTng resource constraints when running in a container • JDK 9 has a few improvements to respect resource constraints – These improvements have been back ported to a JDK 9 release
11
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
RespecTng memory limits • The JDK respects group memory limits set for the container (see docker run memory constraints) -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
12
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
RespecTng CPU constraints • The JDK respects some CPU constraints set for the container (see docker run cpuset constraint) • java.lang.Runtime.availableProcessors reports correct number of CPUs
13
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Stable execuTon • The JVM ensures stable execuTon when resources change • G1 Garbage Collector operates on acTve CPU count discovered at JVM startup
14
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Ongoing improvements planned for future releases • JDK-‐8146115 “Improve Docker container detecTon and resource configuraTon usage” • More robust container detecTon logic – EvaluaTng support for further docker run flags --cpus --cpu-quota --cpu-period --cpu-shares
• New -XX:ActiveProcessorCount flag • Total and Avail memory extracted from cgroup /proc file system
15
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Ongoing improvements planned for future releases • JDK-‐8186248 “Allow selecTng Heap % of available RAM” • Draq JEP: Container aware Java hrp://openjdk.java.net/jeps/8182070 – Provide Java API access to container metrics
16
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Demo Running Java (jshell), in a docker container, and respec%ng resource constraints
17
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
For a more comprehensive demonstraTon… • See tutorial on running and monitoring a Java applicaTon in a Kubernetes cluster • Docker images can be created and published using Wercker
18
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Size Analysis Viewer discre%on advised: Bar charts ahead!
19
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Docker Image • Docker image using DockerFile – FROM oraclelinux:7 – ADD jdk-‐9+181-‐linux-‐x64_bin.tar.gz
• Let’s opTmize!
20 Si
ze (M
B)
0
100
200
300
400
500
600
700
800
Full JDK
568
229
oraclelinux:7JDK
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
• Full JDK – Default JDK (not jlink:ed)
• java.base – jlink —add-modules java.base
• “nery” – A set of modules expected to be sufficient for many Java applicaTons • jlink --add-modules java.base, java.logging, java.management, java.xml, jdk.management, jdk.unsupported
– Note: Does not include the nery applicaTon code!
21
Streamlining the JRE using jlink
Size
(MB)
0
100
200
300
400
500
600
700
800
Full JDK “netty” java.base
4660
568
229229229
oraclelinux:7JDK
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Streamlining the base image
• oraclelinux:7 (229 MB) – Contains Everything™ …and then some – Certainly more than Java needs
• oraclelinux:7-‐slim (118 MB) – Streamlined to bare necessiTes – Saves 111 MB
• Further opTmizaTon -‐ Strip out individual files – Analyze shared libraries/dependency graph and strip out unneeded files
22
oraclelinux:7 vs oraclelinux:7-‐slim
Size
(MB)
0
100
200
300
400
500
600
700
800
orac
lelinu
x:7 +
Full J
DK
orac
lelinu
x:7-sl
im +
Full J
DK
orac
lelinu
x:7 +
java.b
ase
orac
lelinu
x:7-sl
im +
java.b
ase
orac
lelinu
x:7 +
“nett
y”or
aclel
inux:7
-slim
+ “n
etty”
60
60
46
46
568
568
118
229
118
229
118
229
BaseJDK
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Small. Simple. Secure. Alpine Linux is a security-‐oriented, lightweight Linux distribuTon based on musl libc and busybox. – hrps://www.alpinelinux.org
23
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Docker Base Images
24
Docker base image sizes
Size
(MB)
0
25
50
75
100
125
150
175
200
225
250
275
300
oraclelinux:7 oraclelinux:7-slim alpine:3.6
3.966
117.6
229
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Java Images Based on alpine:3.6
25
Size
(MB)
0
50
100
150
200
250
300
350
400
Full JDK java.base “netty”
alpine:3.6JDK
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
• default: no special opTons • --compress=2 – ZIP compression of resources
• --strip-debug – Remove all debug informaTon – Don’t try this at home!
26
OpTmizing java.base with jlink opTons
Size
(MB)
0
5
10
15
20
25
30
35
40
45
50
default
—compress=2
—compress=2
—strip-debug
3134
46
444
alpine:3.6JDK
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
…but wait, there’s more! • What’s the theoreTcal minimum? • What’s actually in a java.base JRE?
27
Files Size (bytes) lib/modules 23,529,047 lib/server/libjvm.so 21,197,904 <other files> 1,545,818 Sum 46,272,769
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
JVM Size
28
Note: Numbers/sizes are approximate
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
JVM Size – JIT Compiler(s)
29
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
JVM Size – GC(s)
30
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
JVM Size – Let’s keep one GC: Serial
31
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
JVM Size -‐ Other
32
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
• The “minimal” VM weighs in at just under 5MB – STll fully Java compliant
• But – Lacks many/most of the addiTonal features • No JIT compiler • Only Serial GC • Very few debugging/serviceability features
• Probably not a good match for producTon use-‐cases, but an interesTng data point
33
The “minimal” VM
Size of JVM variants
Size
(MB)
0.0
5.0
10.0
15.0
20.0
25.0
server minimal
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
• HelloWorld in ~20MB – Including the Alpine base image
• More extreme Java runTmes available can bring this down even further (with some limitaTons) – SubstrateVM from Oracle Labs
34
A “minimal” Docker image
“minimal” VM + java.base
Size
(MB)
0.0
10.0
20.0
30.0
40.0
default —compress=2 —strip-debug
10.512.9
25.3
4.84.84.8
4.04.04.0
alpine:3.6libjvm.soJDK
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
• Not every class in a module is necessarily used by the applicaTon • Finding out which classes to use is non-‐trivial – Indeterminism (halTng problem) – ReflecTon
• Area of research, stay tuned
#classes Size (bytes) All java.base classes 5714 19,178,884 Classes used by HelloWorld 506 8,796,290
9% 46%
35
Future: Stripping out unused classes
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Sharing across instances
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Sharing Across Instances • Micro-‐services and Docker encourages running many processes on the same machine • Chances are many instances will be running the exact same applica%on • OS shared libraries allows for sharing naTve data • libc, libjvm.so all get shared automaTcally by the OS & Docker – Assuming same layer/file/inode
• What about Java class data?
37
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Class Data Sharing (CDS) – Dump Tme • Dump Tme process / “training run” – Preload a set of classes – Classes are parsed into their Java VM private internal representaTons (class metadata) • Metadata is split into read-‐only (RO) and read-‐write (RW) parts, and allocated in separate memory regions
– All loaded class metadata is saved to a file (the shared archive)
• New in JDK 9: Applica%on Class Data Sharing (AppCDS) – ApplicaTon classes are supported
38
CDS archive
C.class
B.class A.class
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
• Archive is memory-‐mapped • RO pages shared, RW pages are shared copy-‐on-‐write • Classes read from mapped memory without overhead of searching, reading & parsing from JAR files • Like shared libraries, archive can be shared across Docker containers
39
Class Data Sharing (CDS) -‐ RunTme
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Example: WebLogic Server Base Domain AppCDS Benefits -‐ Startup Tme and Footprint
40
• Sharing & savings increases with every instance • With 10 instances there is ~10% saving in total memory footprint
Footprint
Size
(MB)
- N
ote:
Log
arith
mic
!1
10
100
1000
10000
Unique Shared Total
4,137
66
4,073 4,652
20
4,634 No AppCDSAppCDS
Startup Time
Tim
e (s
)
0
1
2
3
4
5
6
7
8
9
10
11
12
No AppCDS AppCDS
7.7
11.4
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Summary – OpTmizing a Java Docker Image • The naïve Java Docker image is large -‐ 229MB base + 568MB JDK = 797MB • Can be significantly reduced – Using an appropriate base image • 117MB for oraclelinux:7-‐slim • 4MB for alpine:3.6
– CreaTng a custom jlinked JRE • ~60MB for “nery” • ~46MB for “java.base”
• HelloWorld can be packaged with a full JVM in ~30MB • AppCDS enables sharing class data across JVM instances and Docker containers
41
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
A quick look at startup Tme
42
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Ahead-‐of-‐Time (AOT) compilaTon • Does with JIT compiled Java code what AppCDS does with Java class data – Pre-‐compile to shared library: jaotc --output libHelloWorld.so HelloWorld.class – Use in subsequent runs: java -XX:AOTLibrary=libHelloWorld.so HelloWorld
• Experimental funcTonality introduced in JDK 9 – Only on linux-‐x64, other plagorms to follow
• Benefits – Startup performance – Reduces Tme to peak performance – Saves on footprint by sharing across instances
• Not-‐so-‐secret plan: use for enabling Java-‐based JIT compiler – OpenJDK Project “Metropolis” aims to move JVM funcTonality to Java
43
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Docker+Java startup Tme
• Host java – Create socket – Setup java arguments for ProcessBuilder – Start docker image with Java app
• Docker java – Create socket and connect to host – Send message and exit
44
Example Applica%on
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
ExecuTon Analysis
0
200
400
600
800
1000
1200
1400
Host DockerRun DockerExec
AverageStartupTimefor50clientsinms
JavanoCDSorAOT
JavawithAPPCDS&AOT
GO
SVM
45
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
====================================================================== CDS AOT GC Average start-up time for 50 iterations ====================================================================== NO NO Parallel 296.776495 task-clock (msec) # 1.644 CPUs utilized ( +- 0.78% ) NO NO ParallelOld 299.844332 task-clock (msec) # 1.653 CPUs utilized ( +- 0.82% ) NO NO G1 385.857827 task-clock (msec) # 1.948 CPUs utilized ( +- 1.22% ) NO NO Serial 268.299592 task-clock (msec) # 1.597 CPUs utilized ( +- 0.81% ) NO YES Parallel 184.101911 task-clock (msec) # 1.118 CPUs utilized ( +- 1.20% ) NO YES ParallelOld 192.454881 task-clock (msec) # 1.128 CPUs utilized ( +- 1.01% ) NO YES G1 289.153747 task-clock (msec) # 1.541 CPUs utilized ( +- 1.38% ) NO YES Serial 169.313077 task-clock (msec) # 1.047 CPUs utilized ( +- 0.80% ) YES NO Parallel 229.502306 task-clock (msec) # 2.069 CPUs utilized ( +- 0.76% ) YES NO ParallelOld 232.277575 task-clock (msec) # 2.144 CPUs utilized ( +- 0.90% ) YES NO G1 301.349409 task-clock (msec) # 2.221 CPUs utilized ( +- 1.16% ) YES NO Serial 206.965560 task-clock (msec) # 1.975 CPUs utilized ( +- 0.69% ) YES YES Parallel 128.244920 task-clock (msec) # 1.337 CPUs utilized ( +- 1.06% ) YES YES ParallelOld 126.970865 task-clock (msec) # 1.303 CPUs utilized ( +- 1.01% ) YES YES G1 200.728556 task-clock (msec) # 1.647 CPUs utilized ( +- 1.35% ) YES YES Serial 91.769762 task-clock (msec) # 1.104 CPUs utilized ( +- 1.64% )
46
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 47
Q&A
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Stay connected
• Join us: DevOps Corner (Developer Lounge – Moscone West) • Learn more: openjdk.java.net | wercker.com/java • Follow: @OpenJDK, @wercker #JavaOne #DevOps
48
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | ConfidenTal – Oracle Internal/Restricted/Highly Restricted
# A JDK 9 development image for building FROM alpine:3.6 # Add the musl-‐based JDK 9 distribution RUN mkdir /opt # Download from http://jdk.java.net/9/ ADD jdk-‐9-‐ea+181_linux-‐x64-‐musl_bin.tar.gz /opt # Set up env variables ENV JAVA_HOME=/opt/jdk-‐9 ENV PATH=$PATH:$JAVA_HOME/bin CMD ["java", "-‐version"]
Example DockerFile (jdk-9-alpine.Dockerfile) for building an image with JDK 9
50
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | ConfidenTal – Oracle Internal/Restricted/Highly Restricted
#!/bin/sh rm -‐fr jdk-‐9-‐base-‐ea+181_linux-‐x64-‐musl docker run -‐-‐rm \ -‐-‐volume $PWD:/out \ jdk-‐9-‐alpine \ jlink -‐-‐module-‐path /opt/jdk-‐9/jmods \ -‐-‐add-‐modules java.base \ -‐-‐compress 2 \ -‐-‐no-‐header-‐files \ -‐-‐output /out/jdk-‐9-‐base-‐ea+181_linux-‐x64-‐musl
Example script (link.sh) using jlink to produce a smaller JDK 9 distribuTon
51
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | ConfidenTal – Oracle Internal/Restricted/Highly Restricted
# Make a docker image with a jlink'ed JDK 9 FROM alpine:3.6 # Add jlink'ed JDK 9 ADD jdk-‐9-‐base-‐ea+181_linux-‐x64-‐musl /opt/jdk-‐9 # Set up env variables ENV JAVA_HOME=/opt/jdk-‐9 ENV PATH=$PATH:$JAVA_HOME/bin CMD ["java", "-‐version"]
Example DockerFile (jdk-9-base-alpine.Dockerfile) for building an image with a custom JDK 9 distribuTon
52
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | ConfidenTal – Oracle Internal/Restricted/Highly Restricted
# Build an image with JDK 9 docker build -‐t jdk-‐9-‐alpine -‐f jdk-‐9-‐alpine.Dockerfile . # Create a custom JDK 9 distribution with just the java.base module bash link.sh # Build an image with the custom JDK 9 distribution docker build -‐t jdk-‐9-‐base-‐alpine -‐f jdk-‐9-‐base-‐alpine.Dockerfile . # Run the image docker run -‐-‐rm jdk-‐9-‐base-‐alpine java -‐-‐list-‐modules
Commands to build images
53
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | ConfidenTal – Oracle Internal/Restricted/Highly Restricted
long javaMaxMem() { return Runtime.getRuntime().maxMemory(); } import java.nio.file.*; long sysMaxMem() throws IOException { return Files.lines(Paths.get("/sys/fs/cgroup/memory/memory.limit_in_bytes")) .mapToLong(Long::valueOf) .findFirst().getAsLong(); }
jshell snippets (snippets.txt)
54
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | ConfidenTal – Oracle Internal/Restricted/Highly Restricted
# Run without resource restrictions docker run \ -‐-‐rm -‐it -‐-‐volume $PWD:/in jdk-‐9-‐alpine \ jshell /in/snippets.txt # Run with resource restrictions but no Java configutation docker run -‐m=384M -‐-‐cpuset-‐cpus=0 \ -‐-‐rm -‐it -‐-‐volume $PWD:/in jdk-‐9-‐alpine \ jshell /in/snippets.txt # Run with resource restrictions and Java configutation docker run -‐m=384M -‐-‐cpuset-‐cpus=0 \ -‐-‐rm -‐it -‐-‐volume $PWD:/in jdk-‐9-‐alpine \ jshell /in/snippets.txt \ -‐J-‐XX:+UnlockExperimentalVMOptions -‐J-‐XX:+UseCGroupMemoryLimitForHeap \ -‐R-‐XX:+UnlockExperimentalVMOptions -‐R-‐XX:+UseCGroupMemoryLimitForHeap
jshell in Docker execuTon commands
55
Top Related