因为没有直接使用fabric8的镜像(https://hub.docker.com/r/fabric8/java-jboss-openjdk8-jdk/~/dockerfile/), 但是又羡慕其自动内存计算的功能, 所以从facric8的把"/deployments"目录下的脚本都活剥出来, 也就是抄袭出来, 打算加到自己的镜像中去.
run-java.sh:
#!/bin/sh # Fail on a single failed command set -eo pipefail # ========================================================== # Generic run script for running arbitrary Java applications # # Source and Documentation can be found # at https://github.com/fabric8io/run-java-sh # # ========================================================== # Error is indicated with a prefix in the return value check_error() { local msg=$1 if echo ${msg} | grep -q "^ERROR:"; then echo ${msg} exit 1 fi } # The full qualified directory where this script is located get_script_dir() { # Default is current directory local dir=`dirname "$0"` local full_dir=`cd "${dir}" ; pwd` echo ${full_dir} } # Try hard to find a sane default jar-file auto_detect_jar_file() { local dir=$1 # Filter out temporary jars from the shade plugin which start with 'original-' local old_dir=$(pwd) cd ${dir} if [ $? = 0 ]; then local nr_jars=`ls *.jar 2>/dev/null | grep -v '^original-' | wc -l | tr -d '[[:space:]]'` if [ ${nr_jars} = 1 ]; then ls *.jar | grep -v '^original-' exit 0 fi cd ${old_dir} echo "ERROR: Neither \$JAVA_MAIN_CLASS nor \$JAVA_APP_JAR is set and ${nr_jars} found in ${dir} (1 expected)" else echo "ERROR: No directory ${dir} found for auto detection" fi } # Check directories (arg 2...n) for a jar file (arg 1) get_jar_file() { local jar=$1 shift; if [ "${jar:0:1}" = "/" ]; then if [ -f "${jar}" ]; then echo "${jar}" else echo "ERROR: No such file ${jar}" fi else for dir in $*; do if [ -f "${dir}/$jar" ]; then echo "${dir}/$jar" return fi done echo "ERROR: No ${jar} found in $*" fi } load_env() { local script_dir=$1 # Configuration stuff is read from this file local run_env_sh="run-env.sh" # Load default default config if [ -f "${script_dir}/${run_env_sh}" ]; then source "${script_dir}/${run_env_sh}" fi # Check also $JAVA_APP_DIR. Overrides other defaults # It's valid to set the app dir in the default script if [ -z "${JAVA_APP_DIR}" ]; then JAVA_APP_DIR="${script_dir}" else if [ -f "${JAVA_APP_DIR}/${run_env_sh}" ]; then source "${JAVA_APP_DIR}/${run_env_sh}" fi fi export JAVA_APP_DIR # Read in container limits and export the as environment variables if [ -f "${script_dir}/container-limits" ]; then source "${script_dir}/container-limits" fi # JAVA_LIB_DIR defaults to JAVA_APP_DIR export JAVA_LIB_DIR="${JAVA_LIB_DIR:-${JAVA_APP_DIR}}" if [ -z "${JAVA_MAIN_CLASS}" ] && [ -z "${JAVA_APP_JAR}" ]; then JAVA_APP_JAR="$(auto_detect_jar_file ${JAVA_APP_DIR})" check_error "${JAVA_APP_JAR}" fi if [ "x${JAVA_APP_JAR}" != x ]; then local jar="$(get_jar_file ${JAVA_APP_JAR} ${JAVA_APP_DIR} ${JAVA_LIB_DIR})" check_error "${jar}" export JAVA_APP_JAR=${jar} else export JAVA_MAIN_CLASS fi } # Check for standard /opt/run-java-options first, fallback to run-java-options in the path if not existing run_java_options() { if [ -f "/opt/run-java-options" ]; then echo `sh /opt/run-java-options` else which run-java-options >/dev/null 2>&1 if [ $? = 0 ]; then echo `run-java-options` fi fi } # Combine all java options get_java_options() { local dir=$(get_script_dir) local java_opts local debug_opts if [ -f "$dir/java-default-options" ]; then java_opts=$($dir/java-default-options) fi if [ -f "$dir/debug-options" ]; then debug_opts=$($dir/debug-options) fi # Normalize spaces with awk (i.e. trim and elimate double spaces) echo "${JAVA_OPTIONS} $(run_java_options) ${debug_opts} ${java_opts}" | awk '$1=$1' } # Read in a classpath either from a file with a single line, colon separated # or given line-by-line in separate lines # Arg 1: path to claspath (must exist), optional arg2: application jar, which is stripped from the classpath in # multi line arrangements format_classpath() { local cp_file="$1" local app_jar="$2" local wc_out=`wc -l $1 2>&1` if [ $? -ne 0 ]; then echo "Cannot read lines in ${cp_file}: $wc_out" exit 1 fi local nr_lines=`echo $wc_out | awk '{ print $1 }'` if [ ${nr_lines} -gt 1 ]; then local sep="" local classpath="" while read file; do local full_path="${JAVA_LIB_DIR}/${file}" # Don't include app jar if include in list if [ x"${app_jar}" != x"${full_path}" ]; then classpath="${classpath}${sep}${full_path}" fi sep=":" done < "${cp_file}" echo "${classpath}" else # Supposed to be a single line, colon separated classpath file cat "${cp_file}" fi } # Fetch classpath from env or from a local "run-classpath" file get_classpath() { local cp_path="." if [ "x${JAVA_LIB_DIR}" != "x${JAVA_APP_DIR}" ]; then cp_path="${cp_path}:${JAVA_LIB_DIR}" fi if [ -z "${JAVA_CLASSPATH}" ] && [ "x${JAVA_MAIN_CLASS}" != x ]; then if [ "x${JAVA_APP_JAR}" != x ]; then cp_path="${cp_path}:${JAVA_APP_JAR}" fi if [ -f "${JAVA_LIB_DIR}/classpath" ]; then # Classpath is pre-created and stored in a 'run-classpath' file cp_path="${cp_path}:`format_classpath ${JAVA_LIB_DIR}/classpath ${JAVA_APP_JAR}`" else # No order implied cp_path="${cp_path}:${JAVA_APP_DIR}/*" fi elif [ "x${JAVA_CLASSPATH}" != x ]; then # Given from the outside cp_path="${JAVA_CLASSPATH}" fi echo "${cp_path}" } # Set process name if possible get_exec_args() { EXEC_ARGS="" if [ "x${JAVA_APP_NAME}" != x ]; then # Not all shells support the 'exec -a newname' syntax.. `exec -a test true 2>/dev/null` if [ "$?" = 0 ] ; then echo "-a '${JAVA_APP_NAME}'" else # Lets switch to bash if you have it installed... if [ -f "/bin/bash" ] ; then exec "/bin/bash" $0 $@ fi fi fi } # Start JVM startup() { # Initialize environment load_env $(get_script_dir) local args cd ${JAVA_APP_DIR} if [ "x${JAVA_MAIN_CLASS}" != x ] ; then args="${JAVA_MAIN_CLASS}" else args="-jar ${JAVA_APP_JAR}" fi echo exec $(get_exec_args) java $(get_java_options) -cp "$(get_classpath)" ${args} $* exec $(get_exec_args) java $(get_java_options) -cp "$(get_classpath)" ${args} $* } # ============================================================================= # Fire up startup $*
java-default-options:
#!/bin/sh # ================================================================= # Detect whether running in a container and set appropriate options # for limiting Java VM resources # # Usage: JAVA_OPTIONS="$(java-default-options.sh)" # Env Vars evaluated: # JAVA_OPTIONS: Checked for already set options # JAVA_MAX_MEM_RATIO: Ratio use to calculate a default maximum Memory, in percent. # E.g. the default value "50" implies that 50% of the Memory # given to the container is used as the maximum heap memory with # '-Xmx'. It is a heuristic and should be better backed up with real # experiments and measurements. # For a good overviews what tuning options are available --> # https://youtu.be/Vt4G-pHXfs4 # https://www.youtube.com/watch?v=w1rZOY5gbvk # https://vimeo.com/album/4133413/video/181900266 # Also note that heap is only a small portion of the memory used by a JVM. There are lot # of other memory areas (metadata, thread, code cache, ...) which addes to the overall # size. There is no easy solution for this, 50% seems to be are reasonable compromise. # However, when your container gets killed because of an OOM, then you should tune # the absolute values # # Check for memory options and calculate a sane default if not given max_memory() { # Check whether -Xmx is already given in JAVA_OPTIONS. Then we dont # do anything here if echo "${JAVA_OPTIONS}" | grep -q -- "-Xmx"; then return fi # Check if explicitely disabled if [ "x$JAVA_MAX_MEM_RATIO" = "x0" ]; then return fi # Check for the 'real memory size' and caluclate mx from a ratio # given (default is 50%) if [ "x$CONTAINER_MAX_MEMORY" != x ]; then local max_mem="${CONTAINER_MAX_MEMORY}" local ratio=${JAVA_MAX_MEM_RATIO:-50} local mx=$(echo "${max_mem} ${ratio} 1048576" | awk '{printf "%d\n" , ($1*$2)/(100*$3) + 0.5}') echo "-Xmx${mx}m" fi } # Switch on diagnostics except when switched off diagnostics() { if [ "x$JAVA_DIAGNOSTICS" != "x" ]; then echo "-XX:NativeMemoryTracking=summary -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UnlockDiagnosticVMOptions" fi } cpu_core_tunning() { local core_limit="${JAVA_CORE_LIMIT}" if [ "x$core_limit" = "x0" ]; then return fi if [ "x$CONTAINER_CORE_LIMIT" != x ]; then if [ "x$core_limit" = x ]; then core_limit="${CONTAINER_CORE_LIMIT}" fi echo "-XX:ParallelGCThreads=${core_limit} " \ "-XX:ConcGCThreads=${core_limit} " \ "-Djava.util.concurrent.ForkJoinPool.common.parallelism=${core_limit}" fi } # Echo options, trimming trailing and multiple spaces echo "$(max_memory) $(diagnostics) $(cpu_core_tunning)" | awk '$1=$1'
debug-options:
#!/bin/sh # Check for debug options and echo them if enabled. Meant to be included by # a run script. debug_options() { if [ "x${JAVA_ENABLE_DEBUG}" != "x" -o "x${JAVA_DEBUG_ENABLE}" != "x" -o "x${JAVA_DEBUG}" != "x" ]; then local debug_port=${JAVA_DEBUG_PORT:-5005} echo "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=${debug_port}" fi } ## Echo options, trimming trailing and multiple spaces echo "$(debug_options)" | awk '$1=$1'
container-limits:
#!/bin/sh # Detected container limits # If found these are exposed as the following environment variables: # # - CONTAINER_MAX_MEMORY # - CONTAINER_CORE_LIMIT # # This script is meant to be sourced. ceiling() { awk -vnumber="$1" -vdiv="$2" ' function ceiling(x){ return x%1 ? int(x)+1 : x } BEGIN{ print ceiling(number/div) } ' } # Based on the cgroup limits, figure out the max number of core we should utilize core_limit() { local cpu_period_file="/sys/fs/cgroup/cpu/cpu.cfs_period_us" local cpu_quota_file="/sys/fs/cgroup/cpu/cpu.cfs_quota_us" if [ -r "${cpu_period_file}" ]; then local cpu_period="$(cat ${cpu_period_file})" if [ -r "${cpu_quota_file}" ]; then local cpu_quota="$(cat ${cpu_quota_file})" # cfs_quota_us == -1 --> no restrictions if [ "x$cpu_quota" != "x-1" ]; then ceiling "$cpu_quota" "$cpu_period" fi fi fi } max_memory() { # High number which is the max limit unti which memory is supposed to be # unbounded. 512 TB for now. local max_mem_unbounded="562949953421312" local mem_file="/sys/fs/cgroup/memory/memory.limit_in_bytes" if [ -r "${mem_file}" ]; then local max_mem="$(cat ${mem_file})" if [ ${max_mem} -lt ${max_mem_unbounded} ]; then echo "${max_mem}" fi fi } limit="$(core_limit)" if [ x$limit != x ]; then export CONTAINER_CORE_LIMIT="${limit}" fi unset limit limit="$(max_memory)" if [ x$limit != x ]; then export CONTAINER_MAX_MEMORY="$limit" fi unset limit