CON4429 - Java in a World of Containers
[email protected] @PaulSandoz [email protected] Director, Java Virtual Machine @MikaelVidstedt
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. 1 Agenda
Producing images and running containers with JDK 9 Size analysis of JDK Docker Images A quick look at startup me
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 2 Java 8 Docker image • Official Java 8 SE (Server JRE) available on the docker store • See also DockerFiles on GitHub
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 3 In a world of containers we expect… • Many distribu ons of Java run mes • Forces that push towards – Smaller images – Faster execu on using less resources (and respec ng resource constraints)
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 4 Java has plans for a world of containers • Official OpenJDK builds will make it easier to distribute Java run mes • Java 9 tooling can produce custom Java run mes that are smaller • Current and future Java tooling will produce applica on-specific Java run mes that startup faster
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 5 Producing Docker images with a JDK • Very easy to create a DockerFile that copies (or adds) a tarball of a JDK – A resul ng Docker image will be large (> 300MB) • Not necessarily good for development or execu on – More stuff than required to build or run an applica on
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 6 JDK 9 is modular • JDK 9 is modular and introduces modules to the Java pla orm • 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
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 7 JDK 9 and custom Java run mes • JDK 9 comes with jlink, a tool that can create custom Java run mes – Such as, a Java run me consis ng of just the java.base module • Note: the Java applica on need not be modular
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 8 Project Portola and Alpine Linux • The OpenJDK Portola Project aims to provide a port of the JDK to the Alpine Linux distribu on • Early access builds of the JDK port are available • jlink can be used to create custom Java run mes for Alpine Linux
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 9 Demo
Crea ng Docker images with Alpine Linux, Java, and jlink
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 10 Running JDK 9 in Docker containers • The JDK has not necessarily been a model ci zen and respec ng 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
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 11 Respec ng memory limits • The JDK respects group memory limits set for the container (see docker run memory constraints)
-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 12 Respec ng 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
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 13 Stable execu on • The JVM ensures stable execu on when resources change • G1 Garbage Collector operates on ac ve CPU count discovered at JVM startup
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 14 Ongoing improvements planned for future releases • JDK-8146115 “Improve Docker container detec on and resource configura on usage” • More robust container detec on logic – Evalua ng 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
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 15 Ongoing improvements planned for future releases • JDK-8186248 “Allow selec ng Heap % of available RAM” • Dra JEP: Container aware Java h p://openjdk.java.net/jeps/8182070 – Provide Java API access to container metrics
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 16 Demo
Running Java (jshell), in a docker container, and respec ng resource constraints
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 17 For a more comprehensive demonstra on… • See tutorial on running and monitoring a Java applica on in a Kubernetes cluster • Docker images can be created and published using Wercker
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 18 Size Analysis Viewer discre on advised: Bar charts ahead!
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 19 Docker Image
• Docker image using DockerFile 800 568 – FROM oraclelinux:7 JDK 700 oraclelinux:7 – ADD jdk-9+181-linux-x64_bin.tar.gz 600
500
400
• Let’s op mize! Size(MB) 300
200 229
100
0 Full JDK
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 20 Streamlining the JRE using jlink • Full JDK
– Default JDK (not jlink:ed) 800 568 • JDK java.base 700 oraclelinux:7 – jlink —add-modules java.base 600
• “ne y” 500 – A set of modules expected to be sufficient for many Java applica ons 400
• jlink --add-modules Size(MB) 300 java.base, 60 46 java.logging, java.management, 200 229 229 229 java.xml, jdk.management, 100 jdk.unsupported 0 – Note: Does not include the ne y Full JDK “netty” java.base applica on code!
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 21 Streamlining the base image
800 oraclelinux:7 vs oraclelinux:7-slim 568 700 568 JDK 600 • oraclelinux:7 (229 MB) Base – Contains Everything™ …and then 500 some 400
Size(MB) 300 – Certainly more than Java needs 46 60 200 229 229 229 • 46 60 oraclelinux:7-slim (118 MB) 100 118 118 118 – Streamlined to bare necessi es 0 – Saves 111 MB • Further op miza on - Strip out oraclelinux:7 + “netty” oraclelinux:7 + Full JDK oraclelinux:7 + java.base oraclelinux:7-slim + “netty” individual files oraclelinux:7-slim + Full JDK oraclelinux:7-slim + java.base – Analyze shared libraries/dependency graph and strip out unneeded files Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 22 Small. Simple. Secure.
Alpine Linux is a security-oriented, lightweight Linux distribu on based on musl libc and busybox. – h ps://www.alpinelinux.org
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 23 Docker Base Images
Docker base image sizes 300 275 250
225 229 200 175 150
Size(MB) 125 100 117.6 75 50 25 3.966 0 oraclelinux:7 oraclelinux:7-slim alpine:3.6
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 24 Java Images Based on alpine:3.6
400
350
300 JDK alpine:3.6 250
200
Size(MB) 150
100
50
0 Full JDK java.base “netty”
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 25 Op mizing java.base with jlink op ons
50 • default: no special op ons 46 JDK 45 alpine:3.6 • --compress=2 40
35 34 – ZIP compression of resources 31 30
• --strip-debug 25
– Remove all debug informa on Size(MB) 20 – Don’t try this at home! 15 10
5 4 4 4 0 default —compress=2 —compress=2 —strip-debug
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 26 …but wait, there’s more! • What’s the theore cal minimum? • What’s actually in a java.base JRE?
Files Size (bytes) lib/modules 23,529,047 lib/server/libjvm.so 21,197,904
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 27 JVM Size
Note: Numbers/sizes are approximate
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 28 JVM Size – JIT Compiler(s)
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 29 JVM Size – GC(s)
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 30 JVM Size – Let’s keep one GC: Serial
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 31 JVM Size - Other
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 32 The “minimal” VM • The “minimal” VM weighs in at just Size of JVM variants 25.0 under 5MB – S ll fully Java compliant 20.0 • But 15.0 – Lacks many/most of the addi onal features Size(MB) 10.0 • No JIT compiler • Only Serial GC 5.0 • Very few debugging/serviceability features
0.0 server minimal • Probably not a good match for produc on use-cases, but an interes ng data point
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 33 A “minimal” Docker image • HelloWorld in ~20MB – Including the Alpine base image “minimal” VM + java.base 40.0 • More extreme Java run mes JDK 25.3 libjvm.so available can bring this down even 30.0 alpine:3.6 further (with some limita ons)
– SubstrateVM from Oracle Labs 20.0 12.9 10.5 Size(MB)
10.0 4.8 4.8 4.8
4.0 4.0 4.0 0.0 default —compress=2 —strip-debug
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 34 Future: Stripping out unused classes • Not every class in a module is necessarily used by the applica on • Finding out which classes to use is non-trivial #classes Size (bytes) – Indeterminism (hal ng problem) All java.base classes 5714 19,178,884 Classes used by HelloWorld 506 8,796,290 – Reflec on 9% 46% • Area of research, stay tuned
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 35 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 na ve data • libc, libjvm.so all get shared automa cally by the OS & Docker – Assuming same layer/file/inode • What about Java class data?
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 37 Class Data Sharing (CDS) – Dump me • Dump me process / “training run” – Preload a set of classes – Classes are parsed into their Java VM private internal representa ons (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) A.class • New in JDK 9: Applica on Class Data Sharing (AppCDS) B.class – Applica on classes are supported C.class
CDS archive
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 38 Class Data Sharing (CDS) - Run me • 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
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 39 AppCDS Benefits - Startup me and Footprint Example: WebLogic Server Base Domain Footprint Startup Time 10000 12 11 11.4 4,634 4,073 No AppCDS 4,652 4,137 10 AppCDS 9 1000
8 7 7.7
6 100
Time (s) Time 5 66
4 20 3 10
2 Note:Logarithmic!Size- (MB)
1
0 1 No AppCDS AppCDS Unique Shared Total • Sharing & savings increases with every instance • With 10 instances there is ~10% saving in total memory footprint
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 40 Summary – Op mizing 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 – Crea ng a custom jlinked JRE • ~60MB for “ne y” • ~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
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 41 A quick look at startup me
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 42 Ahead-of-Time (AOT) compila on • 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 func onality introduced in JDK 9 – Only on linux-x64, other pla orms to follow • Benefits – Startup performance – Reduces me 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 func onality to Java
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 43 Docker+Java startup me Example Applica on • 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
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 44 Execu on Analysis
Average Startup Time for 50 clients in ms 1400
1200
1000
800 Java no CDS or AOT
Java with APPCDS & AOT
GO 600 SVM
400
200
0 Host Docker Run Docker Exec
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 45 ======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% )
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 46 Q&A
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 47 Stay connected
• Join us: DevOps Corner (Developer Lounge – Moscone West) • Learn more: openjdk.java.net | wercker.com/java • Follow: @OpenJDK, @wercker #JavaOne #DevOps
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 48
Example DockerFile (jdk-9-alpine.Dockerfile) for building an image with JDK 9
# 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"]
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Confiden al – Oracle Internal/Restricted/Highly Restricted 50 Example script (link.sh) using jlink to produce a smaller JDK 9 distribu on
#!/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
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Confiden al – Oracle Internal/Restricted/Highly Restricted 51 Example DockerFile (jdk-9-base-alpine.Dockerfile) for building an image with a custom JDK 9 distribu on
# 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"]
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Confiden al – Oracle Internal/Restricted/Highly Restricted 52 Commands to build images
# 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
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Confiden al – Oracle Internal/Restricted/Highly Restricted 53 jshell snippets (snippets.txt) 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(); }
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Confiden al – Oracle Internal/Restricted/Highly Restricted 54 jshell in Docker execu on commands
# 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
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Confiden al – Oracle Internal/Restricted/Highly Restricted 55