diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6b468b6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.class diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ff1fb0a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +# Follows guidance from http://www.projectatomic.io/docs/docker-image-author-guidance/ + +# Base image off of the official Ubuntu-based image +FROM azul/zulu-openjdk:8 + +MAINTAINER Ron Kurr + +# Create non-root user +RUN groupadd --system microservice --gid 444 && \ +useradd --uid 444 --system --gid microservice --home-dir /home/microservice --create-home --shell /sbin/nologin --comment "Docker image user" microservice && \ +chown -R microservice:microservice /home/microservice + +# default to being in the user's home directory +WORKDIR /home/microservice + +# Set standard Java environment variables +ENV JAVA_HOME /usr/lib/jvm/zulu-8-amd64 +ENV JDK_HOME /usr/lib/jvm/zulu-8-amd64 + +# show the JVM version, by default +CMD ["java", "-version"] + +# remember to switch to the non-root user in child images +# Switch to the non-root user +# USER microservice diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e06d208 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..e6e775e --- /dev/null +++ b/README.md @@ -0,0 +1,140 @@ +# Overview +This project is a simple Docker image that provides access to the +[Azul Systems JDK](http://www.azul.com/downloads/zulu/). It is intended +for **running** JVM applications, not building and testing them. If you +need to build a JVM application, [look at this project](https://github.com/kurron/docker-azul-jdk-8-build). + + +# Prerequisites +* a working [Docker](http://docker.io) engine +* a working [Docker Compose](http://docker.io) installation + +# Building +Type `./build.sh` to build the image. + +# Installation +Docker will automatically install the newly built image into the cache. + +# Tips and Tricks + +## Launching The Image +Use `./test.sh` to exercise the image. + +## Example Usage +There are samples on how to use the image in the `examples` folder and we will +highlight some options here as well. + +The basic idea is to use a Bash script to launch the JVM so you can apply +the appropriate switches that are useful in a containerized environment. You +should copy that script into your image and make the script the entrypoint +to your image. + +The `Dockerfile`: +``` +FROM kurron/docker-azul-jdk-8:latest + +MAINTAINER Ron Kurr + +ADD launch-jvm.sh /home/microservice/launch-jvm.sh +RUN chmod a+x /home/microservice/launch-jvm.sh +ADD Hello.class /home/microservice/Hello.class + +# Switch to the non-root user +USER microservice + +# Run the simple program +ENTRYPOINT ["/home/microservice/launch-jvm.sh", "Hello"] +``` +The `Bash script` for a single core host: +``` +#!/bin/bash + +JVM_DNS_TTL=${1:-30} + +CMD="${JAVA_HOME}/bin/java \ + -server \ + -XX:+UnlockExperimentalVMOptions \ + -XX:+UseCGroupMemoryLimitForHeap \ + -XX:+ScavengeBeforeFullGC \ + -XX:+CMSScavengeBeforeRemark \ + -XX:+UseSerialGC \ + -XX:MinHeapFreeRatio=20 \ + -XX:MaxHeapFreeRatio=40 \ + -XX:GCTimeRatio=4 \ + -XX:AdaptiveSizePolicyWeight=90 + -Dsun.net.inetaddr.ttl=${JVM_DNS_TTL} \ + $*" + +echo ${CMD} +exec ${CMD} +``` + +The `Bash script` for a multi-core host: +``` +#!/bin/bash + +JVM_DNS_TTL=${1:-30} +JVM_GC_THREADS=${2:-2} + +CMD="${JAVA_HOME}/bin/java \ + -server \ + -XX:+UnlockExperimentalVMOptions \ + -XX:+UseCGroupMemoryLimitForHeap \ + -XX:+ScavengeBeforeFullGC \ + -XX:+CMSScavengeBeforeRemark \ + -XX:ParallelGCThreads=${JVM_GC_THREADS} \ + -XX:+UseConcMarkSweepGC \ + -XX:+CMSParallelRemarkEnabled \ + -XX:+UseCMSInitiatingOccupancyOnly \ + -XX:CMSInitiatingOccupancyFraction=70 \ + -Dsun.net.inetaddr.ttl=${JVM_DNS_TTL} \ + $*" + +echo ${CMD} +exec ${CMD} +``` + +Please note that it is **very important to use `exec` to launch your script** +or you will have signal issues. + +You can control how much CPU and RAM the container see via Docker's +`--cpus`, `--memory` and `--memory-swap` switches. + +## Observed JVM Memory Behavior +Using [VisualVM](https://visualvm.github.io/) I was able to watch the JVM's heap +and have the following observations. Test were run with +`OpenJDK Runtime Environment (Zulu 8.21.0.1-linux64) (build 1.8.0_131-b11)`. + +1. Docker's `--memory` switch sets the cgroup settings +1. `exec` into a container and run `mount | grep cgroup | grep memory`, `more /sys/fs/cgroup/memory/memory.limit_in_bytes` to see the cgroup value +1. JVM's `-XX:+UseCGroupMemoryLimitForHeap` only respects the cgroup settings when explicit settings are **not** provided +1. setting `-Xms` and `-Xmx` can exceed the cgroup setting and what Docker thinks you are using for memory +1. not specifing heap settings cause the JVM to allocate a much smaller heap, anecdotally about half of the Docker allocation + +Your situation will dictate what runtime switches to use. A scheduler, such as Kubernetes, +will only understand the cgroup settings so you can either let the JVM figure out the heap +based on what the scheduler assigns it or specify the heap settings explicitly. If you +specify the heap by hand and get it wrong by exceeding the amount of memory the scheduler +thinks you want to use, you could cause an OOM situation with other containers. +Eventually, the JVM will catch up with the container world but until that day, we'll have +to manage memory settings very carefully. + +# Troubleshooting + +# License and Credits +This project is licensed under the +[Apache License Version 2.0, January 2004](http://www.apache.org/licenses/). + +* [Guidance for Docker Image Authors](http://www.projectatomic.io/docs/docker-image-author-guidance/) +* [Java RAM Usage in Containers: Top 5 Tips Not to Lose Your Memory](http://blog.jelastic.com/2017/04/13/java-ram-usage-in-containers-top-5-tips-not-to-lose-your-memory/) +* [Java and Memory Limits in Containers: LXC, Docker and OpenVZ](http://blog.jelastic.com/2016/05/03/java-and-memory-limits-in-containers-lxc-docker-and-openvz/) +* [OpenJDK and Containers](https://developers.redhat.com/blog/2017/04/04/openjdk-and-containers/) +* [Java VM Options You Should Always Use in Production](http://blog.sokolenko.me/2014/11/javavm-options-production.html) +* [Exec form ENTRYPOINT example](https://docs.docker.com/engine/reference/builder/#exec-form-entrypoint-example) +* [Java SE support for Docker CPU and memory limits](https://blogs.oracle.com/java-platform-group/java-se-support-for-docker-cpu-and-memory-limits) + +# List of Changes + +* removed Docker, Docker Compose and Ansible from the image. Use the build image instead. +* use `azul/zulu-openjdk:8u131` as the base image to be more Kubernetes friendly +* update to OpenJDK 64-Bit Server VM (Zulu 8.21.0.1-linux64) (build 25.131-b11, mixed mode) diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..ed87e8b --- /dev/null +++ b/build.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +docker pull azul/zulu-openjdk:8 +docker-compose build + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a0e027f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,5 @@ +azul-jdk: + build: . + container_name: "azul-jdk" + net: "host" + command: java -version diff --git a/examples/multi-core/Dockerfile b/examples/multi-core/Dockerfile new file mode 100644 index 0000000..8465ef1 --- /dev/null +++ b/examples/multi-core/Dockerfile @@ -0,0 +1,15 @@ +# Follows guidance from http://www.projectatomic.io/docs/docker-image-author-guidance/ + +FROM dockerazuljdk8_azul-jdk:latest + +MAINTAINER Ron Kurr + +ADD launch-jvm.sh /home/microservice/launch-jvm.sh +RUN chmod a+x /home/microservice/launch-jvm.sh +ADD Hello.class /home/microservice/Hello.class + +# Switch to the non-root user and the home directory +USER microservice + +# Run the simple program +ENTRYPOINT ["/home/microservice/launch-jvm.sh", "Hello"] diff --git a/examples/multi-core/Hello.java b/examples/multi-core/Hello.java new file mode 100644 index 0000000..141ae80 --- /dev/null +++ b/examples/multi-core/Hello.java @@ -0,0 +1,5 @@ +class Hello { + public static void main( String[] args ) { + System.out.println( "Hello, World!" ); + } +} diff --git a/examples/multi-core/build.sh b/examples/multi-core/build.sh new file mode 100755 index 0000000..a4c8fee --- /dev/null +++ b/examples/multi-core/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +javac Hello.java +docker-compose build diff --git a/examples/multi-core/docker-compose.yml b/examples/multi-core/docker-compose.yml new file mode 100644 index 0000000..cc180f8 --- /dev/null +++ b/examples/multi-core/docker-compose.yml @@ -0,0 +1,4 @@ +multi-core-jdk: + build: . + container_name: "multi-core-jdk" + net: "host" diff --git a/examples/multi-core/launch-jvm.sh b/examples/multi-core/launch-jvm.sh new file mode 100755 index 0000000..6cf218f --- /dev/null +++ b/examples/multi-core/launch-jvm.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +set -e + + +# Showcases settings described in http://blog.sokolenko.me/2014/11/javavm-options-production.html and +# https://developers.redhat.com/blog/2017/04/04/openjdk-and-containers/ +# Since we are running in a container, the heap dump and RMI settings have been omitted. + +# This is a sample to show how you might invoke the JVM using settings that are +# approprivate for a multi-core environment. We're using the new CGroup-aware +# memory settings. + +JVM_DNS_TTL=${1:-30} +JVM_GC_THREADS=${2:-2} + +# If you want to be explicit about memory settings +#-XX:MaxRam=${JVM_MAX_RAM} \ +#-Xms${JVM_HEAP_MIN} \ +#-Xmx${JVM_HEAP_MAX} \ +#-XX:MaxMetaspaceSize=${JVM_METASPACE} \ + +# Useful in debugging +# -XX:+PrintFlagsFinal \ + +CMD="${JAVA_HOME}/bin/java \ + -server \ + -XX:+UnlockExperimentalVMOptions \ + -XX:+UseCGroupMemoryLimitForHeap \ + -XX:+ScavengeBeforeFullGC \ + -XX:+CMSScavengeBeforeRemark \ + -XX:ParallelGCThreads=${JVM_GC_THREADS} \ + -XX:+UseConcMarkSweepGC \ + -XX:+CMSParallelRemarkEnabled \ + -XX:+UseCMSInitiatingOccupancyOnly \ + -XX:CMSInitiatingOccupancyFraction=70 \ + -Dsun.net.inetaddr.ttl=${JVM_DNS_TTL} \ + $*" + +echo ${CMD} +exec ${CMD} diff --git a/examples/multi-core/test.sh b/examples/multi-core/test.sh new file mode 100755 index 0000000..a380fdf --- /dev/null +++ b/examples/multi-core/test.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +CMD="docker run --cpus 2 \ + --interactive \ + --name single-core-jdk \ + --rm \ + --tty \ + --memory 268435546 \ + --memory-swap 0 \ + multicore_multi-core-jdk:latest" +echo $CMD +$CMD diff --git a/examples/single-core-jmx-ansible/Dockerfile b/examples/single-core-jmx-ansible/Dockerfile new file mode 100644 index 0000000..c244322 --- /dev/null +++ b/examples/single-core-jmx-ansible/Dockerfile @@ -0,0 +1,21 @@ +# Follows guidance from http://www.projectatomic.io/docs/docker-image-author-guidance/ + +FROM dockerazuljdk8_azul-jdk:latest + +MAINTAINER Ron Kurr + +#ADD launch-jvm.sh /home/microservice/launch-jvm.sh +#RUN chmod a+x /home/microservice/launch-jvm.sh +#ADD Hello.class /home/microservice/Hello.class + +USER root + +RUN apt-get install --yes software-properties-common +RUN apt-add-repository --yes ppa:ansible/ansible +RUN apt-get update --yes +RUN apt-get install --yes ansible + +# Switch to the non-root user and the home directory +USER microservice + +CMD ["/usr/bin/ansible", "all", "--inventory=localhost,", "--verbose", "--connection=local", "-m setup"] diff --git a/examples/single-core-jmx-ansible/Hello.java b/examples/single-core-jmx-ansible/Hello.java new file mode 100644 index 0000000..c5ca261 --- /dev/null +++ b/examples/single-core-jmx-ansible/Hello.java @@ -0,0 +1,11 @@ +class Hello { + public static void main( String[] args ) throws Exception { + java.util.ArrayList bytes = new java.util.ArrayList<>( 1024 ); + + while( true ) { + System.out.println( "Allocating more heap..." ); + bytes.add( new byte[1024 * 1024] ); + Thread.currentThread().sleep( 2000 ); + } + } +} diff --git a/examples/single-core-jmx-ansible/build.sh b/examples/single-core-jmx-ansible/build.sh new file mode 100755 index 0000000..a4c8fee --- /dev/null +++ b/examples/single-core-jmx-ansible/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +javac Hello.java +docker-compose build diff --git a/examples/single-core-jmx-ansible/docker-compose.yml b/examples/single-core-jmx-ansible/docker-compose.yml new file mode 100644 index 0000000..b66f454 --- /dev/null +++ b/examples/single-core-jmx-ansible/docker-compose.yml @@ -0,0 +1,4 @@ +single-core-jdk-jmx-ansible: + build: . + container_name: "single-core-jdk-with-jmx-ansible" + net: "host" diff --git a/examples/single-core-jmx-ansible/launch-jvm.yml b/examples/single-core-jmx-ansible/launch-jvm.yml new file mode 100644 index 0000000..bab840e --- /dev/null +++ b/examples/single-core-jmx-ansible/launch-jvm.yml @@ -0,0 +1,44 @@ +--- +- name: Launch JVM + hosts: localhost + become: no + vars: + container_name: single-core-jdk-jmx-ansible + ram_in_bytes: 33554432 + swap_memory_in_bytes: 0 + dns_ttl: 30 + jmx_port: 2020 + image: singlecorejmxansible_single-core-jdk-jmx-ansible:latest + tasks: + - name: Stopping the container + shell: "docker stop {{ container_name }} || true" + + - name: Removing the container + shell: "docker rm --force=true {{ container_name }} || true" + + - name: Running the container + command: "docker run --cpus 1 + --detach + --name {{ container_name }} + --net host + --rm + --memory {{ ram_in_bytes }} + --memory-swap {{ swap_memory_in_bytes }} + --volume /var/run/docker.sock:/var/run/docker.sock + {{ image }} + java -server + -XX:+UnlockExperimentalVMOptions + -XX:+UseCGroupMemoryLimitForHeap + -XX:+ScavengeBeforeFullGC + -XX:+CMSScavengeBeforeRemark + -XX:+UseSerialGC + -XX:MinHeapFreeRatio=20 + -XX:MaxHeapFreeRatio=40 + -XX:GCTimeRatio=4 + -XX:AdaptiveSizePolicyWeight=90 + -Dsun.net.inetaddr.ttl={{ dns_ttl }} + -Dcom.sun.management.jmxremote.port={{ jmx_port }} + -Dcom.sun.management.jmxremote.rmi.port={{ jmx_port }} + -Dcom.sun.management.jmxremote.authenticate=false + -Dcom.sun.management.jmxremote.ssl=false + Hello" diff --git a/examples/single-core-jmx-ansible/test.sh b/examples/single-core-jmx-ansible/test.sh new file mode 100755 index 0000000..4ff4297 --- /dev/null +++ b/examples/single-core-jmx-ansible/test.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +#RAM_IN_BYTES=${1:-67108864} +#USER=$(whoami) +#ansible-playbook --connection=local --user ${USER} --ask-pass --extra-vars "ram_in_bytes=${RAM_IN_BYTES}" launch-jvm.yml + +docker run --rm --tty --interactive singlecorejmxansible_single-core-jdk-jmx-ansible:latest diff --git a/examples/single-core-jmx/Dockerfile b/examples/single-core-jmx/Dockerfile new file mode 100644 index 0000000..8465ef1 --- /dev/null +++ b/examples/single-core-jmx/Dockerfile @@ -0,0 +1,15 @@ +# Follows guidance from http://www.projectatomic.io/docs/docker-image-author-guidance/ + +FROM dockerazuljdk8_azul-jdk:latest + +MAINTAINER Ron Kurr + +ADD launch-jvm.sh /home/microservice/launch-jvm.sh +RUN chmod a+x /home/microservice/launch-jvm.sh +ADD Hello.class /home/microservice/Hello.class + +# Switch to the non-root user and the home directory +USER microservice + +# Run the simple program +ENTRYPOINT ["/home/microservice/launch-jvm.sh", "Hello"] diff --git a/examples/single-core-jmx/Hello.java b/examples/single-core-jmx/Hello.java new file mode 100644 index 0000000..c5ca261 --- /dev/null +++ b/examples/single-core-jmx/Hello.java @@ -0,0 +1,11 @@ +class Hello { + public static void main( String[] args ) throws Exception { + java.util.ArrayList bytes = new java.util.ArrayList<>( 1024 ); + + while( true ) { + System.out.println( "Allocating more heap..." ); + bytes.add( new byte[1024 * 1024] ); + Thread.currentThread().sleep( 2000 ); + } + } +} diff --git a/examples/single-core-jmx/build.sh b/examples/single-core-jmx/build.sh new file mode 100755 index 0000000..a4c8fee --- /dev/null +++ b/examples/single-core-jmx/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +javac Hello.java +docker-compose build diff --git a/examples/single-core-jmx/docker-compose.yml b/examples/single-core-jmx/docker-compose.yml new file mode 100644 index 0000000..cf77f11 --- /dev/null +++ b/examples/single-core-jmx/docker-compose.yml @@ -0,0 +1,4 @@ +single-core-jdk-jmx: + build: . + container_name: "single-core-jdk-with-jmx" + net: "host" diff --git a/examples/single-core-jmx/launch-jvm.sh b/examples/single-core-jmx/launch-jvm.sh new file mode 100755 index 0000000..606e50e --- /dev/null +++ b/examples/single-core-jmx/launch-jvm.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +set -e + + +# Showcases settings described in http://blog.sokolenko.me/2014/11/javavm-options-production.html and +# https://developers.redhat.com/blog/2017/04/04/openjdk-and-containers/ +# Since we are running in a container, the heap dump and RMI settings have been omitted. + +# This is a sample to show how you might invoke the JVM using settings that are +# approprivate for a single core environment. We're using the new CGroup-aware +# memory settings. + +JVM_DNS_TTL=${1:-30} +JVM_HEAP=${2:-32m} +JVM_JMX_PORT=${3:-2020} + +# If you want to be explicit about memory settings +#-XX:MaxRam=${JVM_MAX_RAM} \ +#-XX:MaxMetaspaceSize=${JVM_METASPACE} \ + +# Useful in debugging +# -XX:+PrintFlagsFinal \ + +# -Xms${JVM_HEAP} \ +# -Xmx${JVM_HEAP} \ + +CMD="${JAVA_HOME}/bin/java \ + -server \ + -XX:+UnlockExperimentalVMOptions \ + -XX:+UseCGroupMemoryLimitForHeap \ + -XX:+ScavengeBeforeFullGC \ + -XX:+CMSScavengeBeforeRemark \ + -XX:+UseSerialGC \ + -XX:MinHeapFreeRatio=20 \ + -XX:MaxHeapFreeRatio=40 \ + -XX:GCTimeRatio=4 \ + -XX:AdaptiveSizePolicyWeight=90 + -Dsun.net.inetaddr.ttl=${JVM_DNS_TTL} \ + -Dcom.sun.management.jmxremote.port=${JVM_JMX_PORT} \ + -Dcom.sun.management.jmxremote.rmi.port=${JVM_JMX_PORT} \ + -Dcom.sun.management.jmxremote.authenticate=false \ + -Dcom.sun.management.jmxremote.ssl=false \ + $*" + +echo ${CMD} +exec ${CMD} diff --git a/examples/single-core-jmx/test.sh b/examples/single-core-jmx/test.sh new file mode 100755 index 0000000..d74cfc4 --- /dev/null +++ b/examples/single-core-jmx/test.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +RAM_IN_BYTES=${1:-67108864} + +CMD="docker run --cpus 1 \ + --interactive \ + --name single-core-jdk-jmx \ + --net host \ + --rm \ + --tty \ + --memory ${RAM_IN_BYTES} \ + --memory-swap 0 \ + --volume /var/run/docker.sock:/var/run/docker.sock \ + singlecorejmx_single-core-jdk-jmx:latest" +echo $CMD +$CMD diff --git a/examples/single-core/Dockerfile b/examples/single-core/Dockerfile new file mode 100644 index 0000000..8465ef1 --- /dev/null +++ b/examples/single-core/Dockerfile @@ -0,0 +1,15 @@ +# Follows guidance from http://www.projectatomic.io/docs/docker-image-author-guidance/ + +FROM dockerazuljdk8_azul-jdk:latest + +MAINTAINER Ron Kurr + +ADD launch-jvm.sh /home/microservice/launch-jvm.sh +RUN chmod a+x /home/microservice/launch-jvm.sh +ADD Hello.class /home/microservice/Hello.class + +# Switch to the non-root user and the home directory +USER microservice + +# Run the simple program +ENTRYPOINT ["/home/microservice/launch-jvm.sh", "Hello"] diff --git a/examples/single-core/Hello.java b/examples/single-core/Hello.java new file mode 100644 index 0000000..141ae80 --- /dev/null +++ b/examples/single-core/Hello.java @@ -0,0 +1,5 @@ +class Hello { + public static void main( String[] args ) { + System.out.println( "Hello, World!" ); + } +} diff --git a/examples/single-core/build.sh b/examples/single-core/build.sh new file mode 100755 index 0000000..a4c8fee --- /dev/null +++ b/examples/single-core/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +javac Hello.java +docker-compose build diff --git a/examples/single-core/docker-compose.yml b/examples/single-core/docker-compose.yml new file mode 100644 index 0000000..199362b --- /dev/null +++ b/examples/single-core/docker-compose.yml @@ -0,0 +1,4 @@ +single-core-jdk: + build: . + container_name: "single-core-jdk" + net: "host" diff --git a/examples/single-core/launch-jvm.sh b/examples/single-core/launch-jvm.sh new file mode 100755 index 0000000..a585c7c --- /dev/null +++ b/examples/single-core/launch-jvm.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +set -e + + +# Showcases settings described in http://blog.sokolenko.me/2014/11/javavm-options-production.html and +# https://developers.redhat.com/blog/2017/04/04/openjdk-and-containers/ +# Since we are running in a container, the heap dump and RMI settings have been omitted. + +# This is a sample to show how you might invoke the JVM using settings that are +# approprivate for a single core environment. We're using the new CGroup-aware +# memory settings. + +JVM_DNS_TTL=${1:-30} + +# If you want to be explicit about memory settings +#-XX:MaxRam=${JVM_MAX_RAM} \ +#-Xms${JVM_HEAP_MIN} \ +#-Xmx${JVM_HEAP_MAX} \ +#-XX:MaxMetaspaceSize=${JVM_METASPACE} \ + +# Useful in debugging +# -XX:+PrintFlagsFinal \ + +CMD="${JAVA_HOME}/bin/java \ + -server \ + -XX:+UnlockExperimentalVMOptions \ + -XX:+UseCGroupMemoryLimitForHeap \ + -XX:+ScavengeBeforeFullGC \ + -XX:+CMSScavengeBeforeRemark \ + -XX:+UseSerialGC \ + -XX:MinHeapFreeRatio=20 \ + -XX:MaxHeapFreeRatio=40 \ + -XX:GCTimeRatio=4 \ + -XX:AdaptiveSizePolicyWeight=90 + -Dsun.net.inetaddr.ttl=${JVM_DNS_TTL} \ + $*" + +echo ${CMD} +exec ${CMD} diff --git a/examples/single-core/test.sh b/examples/single-core/test.sh new file mode 100755 index 0000000..601f4e7 --- /dev/null +++ b/examples/single-core/test.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +CMD="docker run --cpus 1 \ + --interactive \ + --name single-core-jdk \ + --rm \ + --tty \ + --memory 268435546 \ + --memory-swap 0 \ + --volume /var/run/docker.sock:/var/run/docker.sock \ + singlecore_single-core-jdk:latest" +echo $CMD +$CMD diff --git a/tag-and-push.sh b/tag-and-push.sh new file mode 100755 index 0000000..97ad01e --- /dev/null +++ b/tag-and-push.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# use the time as a tag +UNIXTIME=$(date +%s) + +# docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] +docker tag dockerazuljdk8_azul-jdk:latest kurron/docker-azul-jdk-8:latest +docker tag dockerazuljdk8_azul-jdk:latest kurron/docker-azul-jdk-8:${UNIXTIME} +docker images + +# Usage: docker push [OPTIONS] NAME[:TAG] +docker push kurron/docker-azul-jdk-8:latest +docker push kurron/docker-azul-jdk-8:${UNIXTIME} diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..4782d61 --- /dev/null +++ b/test.sh @@ -0,0 +1,12 @@ +#!/bin/bash + + + +CMD="docker run --cpus 1 \ + --interactive \ + --name zulu-test \ + --rm \ + --tty \ + dockerazuljdk8_azul-jdk:latest" +echo $CMD +$CMD