Merge pull request #342 from PaulSandoz/master

Chapter for Docker and Java 9
This commit is contained in:
Mano Marks 2017-10-14 00:46:27 -07:00 коммит произвёл GitHub
Родитель 1a3419b349 31610f18f4
Коммит 1d6ad9f684
3 изменённых файлов: 335 добавлений и 4 удалений

Просмотреть файл

@ -68,11 +68,13 @@ NOTE: `--parallel` switch will not work for Docker Compose version prior to 1.12
NOTE: For Linux, `docker-compose` and `docker` commands need `sudo` access. So prefix all commands with `sudo`.
=== Other Software
. Install https://git-scm.com//[git].
. Install Docker Cloud CLI following the https://docs.docker.com/docker-cloud/installing-cli/[instructions].
. Download Java IDE based upon your choice and install.
.. https://netbeans.org/downloads/[NetBeans 8.2] (`"Java SE"` version)
.. https://www.jetbrains.com/idea/download/[IntelliJ IDEA Community or Ultimate]
.. http://www.eclipse.org/downloads/eclipse-packages/[Eclipse IDE for Java EE Developers]
. Download https://maven.apache.org/download.cgi[Maven] and install.
. Install Docker Cloud CLI following the https://docs.docker.com/docker-cloud/installing-cli/[instructions].
. Download the OpenJDK build of http://download.java.net/java/GA/jdk9/9/binaries/openjdk-9_linux-x64_bin.tar.gz/[JDK 9 for Linux x64].
(See also the http://jdk.java.net/9/[OpenJDK JDK 9 download page].)
. Download the early-access Open JDK build of http://jdk.java.net/9/ea[JDK 9 for Alpine Linux].

Просмотреть файл

@ -0,0 +1,327 @@
:imagesdir: images
== Build a Docker Image with JDK 9
*PURPOSE*: This chapter explains how to create a Docker image with JDK 9.
The prior chapter explained how, in general, to build a Docker image with Java.
This chapter expands on this topic and focuses on JDK 9 features.
=== Create a Docker Image using JDK 9
Create a new directory, for example `docker-jdk9`.
In that directory, create a new text file `jdk-9-debian-slim.Dockerfile`.
Use the following contents:
[source, text]
----
# A JDK 9 with Debian slim
FROM debian:stable-slim
# Download from http://jdk.java.net/9/
# ADD http://download.java.net/java/GA/jdk9/9/binaries/openjdk-9_linux-x64_bin.tar.gz
ADD openjdk-9_linux-x64_bin.tar.gz /opt
# Set up env variables
ENV JAVA_HOME=/opt/jdk-9
ENV PATH=$PATH:$JAVA_HOME/bin
CMD ["jshell", "-J-XX:+UnlockExperimentalVMOptions", \
"-J-XX:+UseCGroupMemoryLimitForHeap", \
"-R-XX:+UnlockExperimentalVMOptions", \
"-R-XX:+UseCGroupMemoryLimitForHeap"]
----
This image uses `debian` slim as the base image and installs the OpenJDK build
of JDK for linux x64 (see the setup section for how to download this into the
current directory).
The image is configured by default to run `jshell` the Java REPL. The
experimental flag `-XX:+UseCGroupMemoryLimitForHeap` is passed to the REPL
process (the frontend Java process managing user input and the backend Java
process managing compilation). This option will ensure container memory
constraints are honored.
Build the image using the command:
docker build -t jdk-9-debian-slim -f jdk-9-debian-slim.Dockerfile .
List the images available using `docker image ls`:
[source, text]
----
REPOSITORY TAG IMAGE ID CREATED SIZE
jdk-9-debian-slim latest 023f6999d94a 4 hours ago 400MB
debian stable-slim d30525fb4ed2 4 days ago 55.3MB
----
Other images may be shown as well but we are interested in these two images for
now. The large difference in size is attributed to JDK 9, which is larger
in size than JDK 8 because it also explicitly provides Java modules that we
shall see more of later on in this chapter.
Run the container using the command:
docker container run -m=200M -it --rm jdk-9-debian-slim
to see the output:
[source, text]
----
INFO: Created user preferences directory.
| Welcome to JShell -- Version 9
| For an introduction type: /help intro
jshell>
----
Query the available memory of the Java process by typing the following
expression into the Java REPL:
Runtime.getRuntime().maxMemory() / (1 << 20)
to see the output:
[source, text]
----
jshell> Runtime.getRuntime().maxMemory() / (1 << 20)
$1 ==> 100
----
Notice that the Java process is honoring memory constraints (see the `--memory`
of `docker run`) and will not allocate memory beyond that specified for the
container.
In a future release of the JDK it will no longer be necessary to specify an
experimental flag (`-XX:+UnlockExperimentalVMOptions`) once the mechanism by
which memory constraints are efficiently detected is stable.
JDK 9 supports the set CPUs constraint (see the `----cpuset-cpus` of
`docker run`) but does not currently support other CPU constraints such as
CPU shares. This is ongoing work http://openjdk.java.net/jeps/8182070[tracked]
in the OpenJDK project.
Note: the support for CPU sets and memory constraints have also been backported
to JDK 8 release 8u131 and above.
To list all the Java modules distributed with JDK 9 run the following command:
docker container run -m=200M -it --rm jdk-9-debian-slim java --list-modules
In total there should be 75 modules:
[source, text]
----
$ docker container run -m=200M -it --rm jdk-9-debian-slim java --list-modules | wc -l
75
----
=== Create a Docker Image using JDK 9 and Alpine Linux
Instead of `debian` as the base image it is possible to use Alpine Linux
with an early access build of JDK 9 that is compatible with the muslc library
shipped with Alpine Linux.
Create a new text file `jdk-9-alpine.Dockerfile`.
Use the following contents:
[source, text]
----
# A JDK 9 with Alpine Linux
FROM alpine:3.6
# Add the musl-based JDK 9 distribution
RUN mkdir /opt
# Download from http://jdk.java.net/9/
# ADD http://download.java.net/java/jdk9-alpine/archive/181/binaries/jdk-9-ea+181_linux-x64-musl_bin.tar.gz
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 ["jshell", "-J-XX:+UnlockExperimentalVMOptions", \
"-J-XX:+UseCGroupMemoryLimitForHeap", \
"-R-XX:+UnlockExperimentalVMOptions", \
"-R-XX:+UseCGroupMemoryLimitForHeap"]
----
This image uses `alpine` 3.6 as the base image and installs the OpenJDK build
of JDK for Alpine Linux x64 (see the link:ch01-setup.adoc[Setup Environments]
chapter for how to download this into the current directory).
The image is configured in the same manner as for the `debian`-based image.
Build the image using the command:
docker build -t jdk-9-alpine -f jdk-9-alpine.Dockerfile .
List the images available using `docker image ls`:
[source, text]
----
REPOSITORY TAG IMAGE ID CREATED SIZE
jdk-9-debian-slim latest 023f6999d94a 4 hours ago 400MB
jdk-9-alpine latest f5a57382f240 4 hours ago 356MB
debian stable-slim d30525fb4ed2 4 days ago 55.3MB
alpine 3.6 7328f6f8b418 3 months ago 3.97MB
----
Notice the difference in image sizes. Alpine Linux by design has been carefully
crafted to produce a minimal running OS image. A cost of such a design is
an alternative standard library https://www.musl-libc.org/[musl libc] that is
not compatible with the C standard library (libc). As a result the JDK requires
modifications to run on Alpine Linux. Such modifications have been proposed
by the OpenJDK http://openjdk.java.net/projects/portola/[Portola Project].
=== Create a Docker Image using JDK 9 and a Java application
Clone the GitHib project https://github.com/PaulSandoz/helloworld-java-9 that
contains a simple Java 9-based project:
git clone https://github.com/PaulSandoz/helloworld-java-9.git
(If you have a github account you may wish to fork it and then clone the fork
so you can make modifications.)
Enter the directory `helloworld-java-9` and build the project from within a
running Docker container with JDK 9 installed:
docker run --volume $PWD:/helloworld-java-9 --workdir /helloworld-java-9 \
-it --rm openjdk:9-jdk-slim \
./mvnw package
(If you have JDK 9 installed locally on the host system you can build directly
with `./mvnw package`.)
In this case we are using the `openjdk:9-jdk-slim` on Docker hub that has been
configured to work with SSL certificates so that the maven wrapper tool can
successfully download the maven tool. This image is not produced or in anyway
endorsed by the OpenJDK project (unlike the JDK 9 distributions that were
previously required). It is anticipated that future releases of the JDK from
the OpenJDK project will have root CA certificates (see issue
https://bugs.openjdk.java.net/browse/JDK-8189131[JDK-8189131])
To build Docker image for this application create a new text file
`helloworld-jdk-9.Dockerfile` with the following contents:
[source, text]
----
# Hello world application with JDK 9 and Debian slim
FROM jdk-9-debian-slim
COPY target/helloworld-1.0-SNAPSHOT.jar /opt/helloworld/helloworld-1.0-SNAPSHOT.jar
# Set up env variables
CMD java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap \
-cp /opt/helloworld/helloworld-1.0-SNAPSHOT.jar org.examples.java.App
----
Build a Docker image containing the simple Java application based of the Docker
image `jdk-9-debian-slim`:
docker build -t helloworld-jdk-9 -f helloworld-jdk-9.Dockerfile .
List the images available using `docker image ls`:
[source, text]
----
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworld-jdk-9 latest eb0539e9529a 19 seconds ago 400MB
jdk-9-debian-slim latest 023f6999d94a 5 hours ago 400MB
jdk-9-alpine latest f5a57382f240 5 hours ago 356MB
openjdk 9-jdk-slim 6dca67f4790e 3 days ago 372MB
debian stable-slim d30525fb4ed2 4 days ago 55.3MB
alpine 3.6 7328f6f8b418 3 months ago 3.97MB
----
Notice how large the application image `helloworld-jdk-9`.
Run the `jdeps` tool to see what modules the application depends on:
docker run -it --rm helloworld-jdk-9 jdeps --list-deps /opt/helloworld/helloworld-1.0-SNAPSHOT.jar
and observe that the application only depends on the `java.base` module.
=== Reduce the size of a Docker Image using JDK 9 and a Java application
The Java application is extremely simple and as a result uses very little of the
functionality shipped with JDK 9 distribution, specifically the application
only depends on functionality present in the `java.base` module. We can create
a custom Java runtime that only contains the `java.base` module and include
that in application Docker image.
Create a custom Java runtime that is small and only contains the `java.base`
module:
docker run --rm \
--volume $PWD:/out \
jdk-9-debian-slim \
jlink --module-path /opt/jdk-9/jmods \
--verbose \
--add-modules java.base \
--compress 2 \
--no-header-files \
--output /out/target/openjdk-9-base_linux-x64
The JDK 9 tool `jlink` is used to create the custom Java runtime. The tool
is executed from with the container containing JDK 9 and directory where the
modules reside, `/opt/jdk-9/jmods`, is declared in the module path. Only the
`java.base` module is selected.
The custom runtime is output to the `target` directory:
[source, text]
----
$ du -k target/openjdk-9-base_linux-x64/
24 target/openjdk-9-base_linux-x64//bin
12 target/openjdk-9-base_linux-x64//conf/security/policy/limited
8 target/openjdk-9-base_linux-x64//conf/security/policy/unlimited
24 target/openjdk-9-base_linux-x64//conf/security/policy
68 target/openjdk-9-base_linux-x64//conf/security
76 target/openjdk-9-base_linux-x64//conf
44 target/openjdk-9-base_linux-x64//legal/java.base
44 target/openjdk-9-base_linux-x64//legal
72 target/openjdk-9-base_linux-x64//lib/jli
16 target/openjdk-9-base_linux-x64//lib/security
19824 target/openjdk-9-base_linux-x64//lib/server
31656 target/openjdk-9-base_linux-x64//lib
31804 target/openjdk-9-base_linux-x64/
----
To build Docker image for this application with the custom Java runtime create a
new text file `helloworld-jdk-9-base.Dockerfile` with the following contents:
[source, text]
----
# Hello world application with custom Java runtime with just the base module and Debian slim
FROM debian:stable-slim
COPY target/openjdk-9-base_linux-x64 /opt/jdk-9
COPY target/helloworld-1.0-SNAPSHOT.jar /opt/helloworld/helloworld-1.0-SNAPSHOT.jar
# Set up env variables
ENV JAVA_HOME=/opt/jdk-9
ENV PATH=$PATH:$JAVA_HOME/bin
CMD java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap \
-cp /opt/helloworld/helloworld-1.0-SNAPSHOT.jar org.examples.java.App
----
Build a Docker image containing the simple Java application based of the Docker
image `debian:stable-slim`:
docker build -t helloworld-jdk-9-base -f helloworld-jdk-9-base.Dockerfile .
List the images available using `docker image ls`:
[source, text]
----
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworld-jdk-9-base latest 7052483fdb77 24 seconds ago 87.7MB
helloworld-jdk9 latest eb0539e9529a 17 minutes ago 400MB
jdk-9-debian-slim latest 023f6999d94a 5 hours ago 400MB
jdk-9-alpine latest f5a57382f240 5 hours ago 356MB
openjdk 9-jdk-slim 6dca67f4790e 3 days ago 372MB
debian stable-slim d30525fb4ed2 4 days ago 55.3MB
alpine 3.6 7328f6f8b418 3 months ago 3.97MB
[source, text]
----
The `helloworld-jdk-9-base` is much smaller and could be reduced further if
Alpine Linux was used instead of Debian Slim.
A realistic application will depend on more JDK modules but it's still possible
to significantly reduce the Java runtime to only the required modules (for
example many applications will not require Corba or RMI nor the compiler tools).

Просмотреть файл

@ -4,7 +4,9 @@ This tutorial offers Java developers an intro-level and self-paced hands-on work
* link:chapters/ch01-setup.adoc[Setup Environments]
* link:chapters/ch02-basic-concepts.adoc[Docker Basic Concepts]
* link:chapters/ch03-build-image.adoc[Build a Docker Image]
* Building
** link:chapters/ch03-build-image.adoc[Build a Docker Image]
** link:chapters/ch03-build-image-java-9.adoc[Build a Docker Image for Java 9]
* link:chapters/ch04-run-container.adoc[Run a Docker Container]
* link:chapters/ch05-compose.adoc[Multi-container application using Docker Compose]
* link:chapters/ch06-swarm.adoc[Multi-container application using Compose and Swarm Mode]