From 76d8f91bbbaba1fdfdd01144d9642c74b53dca95 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 17 Feb 2021 09:44:16 +0100 Subject: [PATCH] feature(container): Refactor Dockerfile basing on openjdk:11-jre Instead of using the upstream Payara image we build on the OpenJDK image which is also used by Solr. That way we reduce image pulls. We also optimize the domain1 configuration to be more production ready. Relates to #5292 --- conf/container/Dockerfile | 145 ++++++++++++++---- .../scripts/{ => app}/bootstrap-job.sh | 0 .../container/scripts/{ => app}/config-job.sh | 0 .../scripts/{ => app}/default.config | 0 .../scripts/{ => app}/init_2_conf_payara.sh | 13 +- .../scripts/{ => app}/init_3_enabledev.sh | 0 .../scripts/{ => app}/metadata-update.sh | 0 conf/container/scripts/system/entrypoint.sh | 11 ++ .../system/init_1_generate_deploy_commands.sh | 62 ++++++++ .../scripts/system/startInForeground.sh | 73 +++++++++ 10 files changed, 272 insertions(+), 32 deletions(-) rename conf/container/scripts/{ => app}/bootstrap-job.sh (100%) rename conf/container/scripts/{ => app}/config-job.sh (100%) rename conf/container/scripts/{ => app}/default.config (100%) rename conf/container/scripts/{ => app}/init_2_conf_payara.sh (94%) rename conf/container/scripts/{ => app}/init_3_enabledev.sh (100%) rename conf/container/scripts/{ => app}/metadata-update.sh (100%) create mode 100644 conf/container/scripts/system/entrypoint.sh create mode 100644 conf/container/scripts/system/init_1_generate_deploy_commands.sh create mode 100644 conf/container/scripts/system/startInForeground.sh diff --git a/conf/container/Dockerfile b/conf/container/Dockerfile index 007acf69f4d..29d64ed6f8f 100644 --- a/conf/container/Dockerfile +++ b/conf/container/Dockerfile @@ -7,42 +7,128 @@ # THIS FILE IS TO BE USED WITH MAVEN DOCKER BUILD: # mvn -Pcontainer clean package docker:build -FROM payara/server-full:@payara.version@-jdk11 +# Using same base image as Solr (https://hub.docker.com/_/solr), reducing pulls +FROM openjdk:11-jre LABEL maintainer="FDM FZJ " +# Default payara ports to expose +# 4848: admin console +# 9009: debug port (JPDA) +# 8080: http +# 8181: https +EXPOSE 4848 9009 8080 8181 -ENV DATA_DIR=/data\ - DOCROOT_DIR=/docroot\ - METADATA_DIR=/metadata\ - SECRETS_DIR=/secrets\ - DUMPS_DIR=/dumps\ - DOMAIN_DIR=${PAYARA_DIR}/glassfish/domains/${DOMAIN_NAME}\ - JREBEL_LIB=${HOME_DIR}/jrebel/lib/libjrebel64.so\ +ENV HOME_DIR="/opt/payara" +ENV PAYARA_DIR="${HOME_DIR}/appserver" \ + SCRIPT_DIR="${HOME_DIR}/scripts" \ + CONFIG_DIR="${HOME_DIR}/config" \ + DEPLOY_DIR="${HOME_DIR}/deployments" \ + DATA_DIR="/data" \ + DOCROOT_DIR="/docroot" \ + METADATA_DIR="/metadata" \ + SECRETS_DIR="/secrets" \ + DUMPS_DIR="/dumps" \ + PASSWORD_FILE="${HOME_DIR}/passwordFile" \ + ADMIN_USER="admin" \ + ADMIN_PASSWORD="admin" \ + DOMAIN_NAME="domain1" \ + PAYARA_ARGS="" +ENV PATH="${PATH}:${PAYARA_DIR}/bin" \ + DOMAIN_DIR="${PAYARA_DIR}/glassfish/domains/${DOMAIN_NAME}" \ + JVM_ARGS="" \ + MEM_MAX_RAM_PERCENTAGE="70.0" \ + MEM_XSS="512k" \ + PREBOOT_COMMANDS="${CONFIG_DIR}/pre-boot-commands.asadmin" \ + POSTBOOT_COMMANDS="${CONFIG_DIR}/post-boot-commands.asadmin" \ + DEPLOY_PROPS="" \ # Make heap dumps on OOM appear in DUMPS_DIR - JVM_ARGS="-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=\${ENV=DUMPS_DIR}"\ + ENABLE_DUMPS=0 \ + JVM_DUMPS_ARGS="-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=\${ENV=DUMPS_DIR}" \ # Documenting development options (see init_3_enabledev.sh) - ENABLE_JMX=0\ - ENABLE_JDWP=0\ - ENABLE_JREBEL=0 + ENABLE_JMX=0 \ + ENABLE_JDWP=0 \ + ENABLE_JREBEL=0 \ + JREBEL_LIB="${HOME_DIR}/jrebel/lib/libjrebel64.so" -# Create basic pathes +ARG PAYARA_VERSION="@payara.version@" +ARG TINI_VERSION=0.19.0 +ARG ESH_VERSION=0.3.1 +ARG ESH_CHECKSUM="" +ARG PKGS="jq imagemagick curl unzip" +ARG ASADMIN="${PAYARA_DIR}/bin/asadmin --user=${ADMIN_USER} --passwordfile=${PASSWORD_FILE}" + +### PART 1: SYSTEM ### USER root -RUN mkdir -p ${DATA_DIR} ${METADATA_DIR} ${DOCROOT_DIR} ${SECRETS_DIR} ${DUMPS_DIR} && \ +WORKDIR / +RUN true && \ + # Download tini + curl -sSfL -o /tini "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini" && \ + curl -sSfL -o /tini.sha256 "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini.sha256sum" && \ + # Check and install tini + sha256sum -c /tini.sha256 && \ + chmod +x /tini && \ + # Create pathes + mkdir -p ${HOME_DIR} ${PAYARA_DIR} ${DEPLOY_DIR} ${CONFIG_DIR} ${SCRIPT_DIR} && \ + mkdir -p ${DATA_DIR} ${METADATA_DIR} ${DOCROOT_DIR} ${SECRETS_DIR} ${DUMPS_DIR} && \ + # Create user + addgroup --gid 1000 payara && \ + adduser --system --uid 1000 --no-create-home --shell /bin/bash --home "${HOME_DIR}" --gecos "" --ingroup payara payara && \ + echo payara:payara | chpasswd && \ + # Set permissions + chown -R payara: ${HOME_DIR} && \ chown -R payara: ${DATA_DIR} ${METADATA_DIR} ${DOCROOT_DIR} ${SECRETS_DIR} ${DUMPS_DIR} -# Install prerequisites -RUN apt-get -qq update && \ - apt-get -qqy install jq imagemagick curl wget unzip && \ - rm -rf /var/lib/apt/lists/* - -# Install esh template engine from Github -RUN wget --no-verbose -O esh https://raw.githubusercontent.com/jirutka/esh/v0.3.0/esh && \ - echo 'fe030e23fc1383780d08128eecf322257cec743b esh' | sha1sum -c - && \ - chmod +x esh && mv esh /usr/local/bin +RUN true && \ + # Download & check esh template script + curl -sSfL -o /usr/bin/esh https://raw.githubusercontent.com/jirutka/esh/v${ESH_VERSION}/esh && \ + echo '1e0bd783f930cba13d6708b11c1ac844bbb1eddd02ac1666fc10d47eb9517bd7 /usr/bin/esh' | sha256sum -c - && \ + chmod +x /usr/bin/esh && \ + # Download & unzip JRebel to $JREBEL_LIB = ${HOME_DIR}/jrebel/lib/libjrebel64.so (for development use) + curl -sS -f -o ${HOME_DIR}/jrebel.zip http://dl.zeroturnaround.com/jrebel-stable-nosetup.zip && \ + unzip -q "${HOME_DIR}/jrebel.zip" -d "${HOME_DIR}" && \ + # Install packages + apt-get update -q && \ + apt-get install -qqy ${PKGS} && \ + rm -rf /var/lib/apt/lists/* "${HOME_DIR}/jrebel.zip" -# Install JRebel library (for development use) +### PART 2: PAYARA ### +# After setting up system, now configure Payara USER payara -RUN wget --no-verbose -O "${HOME_DIR}/jrebel.zip" http://dl.zeroturnaround.com/jrebel-stable-nosetup.zip && \ - unzip -q "${HOME_DIR}/jrebel.zip" -d "${HOME_DIR}" +WORKDIR ${HOME_DIR} + +# Download, check and install Payara +RUN curl -sSfL -o payara.zip "https://repo1.maven.org/maven2/fish/payara/distributions/payara/${PAYARA_VERSION}/payara-${PAYARA_VERSION}.zip" && \ + curl -sSfL -o payara.zip.sha256 "https://repo1.maven.org/maven2/fish/payara/distributions/payara/${PAYARA_VERSION}/payara-${PAYARA_VERSION}.zip.sha256" && \ + echo "$(cat payara.zip.sha256) payara.zip" | sha256sum -c - && \ + unzip -q payara.zip -d ${HOME_DIR} && \ + mv ${HOME_DIR}/payara5/* ${PAYARA_DIR}/ && \ + rm -rf ${HOME_DIR}/payara5 payara.zip* + +# Copy the system (appserver level) scripts like entrypoint, etc +COPY --chown=payara:payara maven/scripts/system ${SCRIPT_DIR}/ + +# TODO: refactor and make production ready +# Configure the domain to be container and production ready +RUN true && \ + # Set admin password + echo "AS_ADMIN_PASSWORD=\nAS_ADMIN_NEWPASSWORD=${ADMIN_PASSWORD}" > /tmp/password-change-file.txt && \ + echo "AS_ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> ${PASSWORD_FILE} && \ + asadmin --user=${ADMIN_USER} --passwordfile=/tmp/password-change-file.txt change-admin-password --domain_name=${DOMAIN_NAME} && \ + # Start domain for configuration + ${ASADMIN} start-domain ${DOMAIN_NAME} && \ + # Allow access to admin with password only + ${ASADMIN} enable-secure-admin && \ + # List & delete memory settings from domain + for MEMORY_JVM_OPTION in $(asadmin --user=${ADMIN_USER} --passwordfile=${PASSWORD_FILE} list-jvm-options | grep "Xm[sx]\|Xss"); \ + do \ + ${ASADMIN} delete-jvm-options $MEMORY_JVM_OPTION;\ + done && \ + ${ASADMIN} create-jvm-options '-XX\:+UseContainerSupport:-XX\:MaxRAMPercentage=${ENV=MEM_MAX_RAM_PERCENTAGE}:-Xss${ENV=MEM_XSS}' && \ + ${ASADMIN} set-log-attributes com.sun.enterprise.server.logging.GFFileHandler.logtoFile=false && \ + ${ASADMIN} stop-domain ${DOMAIN_NAME} && \ + rm -rf \ + /tmp/password-change-file.txt \ + ${PAYARA_DIR}/glassfish/domains/${DOMAIN_NAME}/osgi-cache \ + ${PAYARA_DIR}/glassfish/domains/${DOMAIN_NAME}/logs # Make docroot of Payara reside in higher level directory for easier targeting # Due to IQSS/dataverse-kubernetes#177: create the generated pathes so they are @@ -51,6 +137,7 @@ RUN rm -rf ${DOMAIN_DIR}/docroot && \ ln -s ${DOCROOT_DIR} ${DOMAIN_DIR}/docroot && \ mkdir -p ${DOMAIN_DIR}/generated/jsp/dataverse +### PART 3: DATAVERSE INSTALLATION ### # Copy app and deps from assembly in proper layers COPY --chown=payara:payara maven/deps ${DEPLOY_DIR}/dataverse/WEB-INF/lib/ COPY --chown=payara:payara maven/app ${DEPLOY_DIR}/dataverse/ @@ -62,5 +149,9 @@ RUN ln -s ${DEPLOY_DIR}/dataverse/supplements/jhove.conf ${PAYARA_DIR}/glassfish sed -i ${PAYARA_DIR}/glassfish/domains/${DOMAIN_NAME}/config/jhove.conf -e "s:/usr/local/payara5/glassfish/domains/domain1:${PAYARA_DIR}/glassfish/domains/${DOMAIN_NAME}:g" # Copy init and application scripts -COPY --chown=payara:payara maven/scripts ${SCRIPT_DIR}/ +COPY --chown=payara:payara maven/scripts/app ${SCRIPT_DIR}/ RUN chmod +x ${SCRIPT_DIR}/* + +# Set the entrypoint +ENTRYPOINT ["/tini", "--"] +CMD "${SCRIPT_DIR}/entrypoint.sh" \ No newline at end of file diff --git a/conf/container/scripts/bootstrap-job.sh b/conf/container/scripts/app/bootstrap-job.sh similarity index 100% rename from conf/container/scripts/bootstrap-job.sh rename to conf/container/scripts/app/bootstrap-job.sh diff --git a/conf/container/scripts/config-job.sh b/conf/container/scripts/app/config-job.sh similarity index 100% rename from conf/container/scripts/config-job.sh rename to conf/container/scripts/app/config-job.sh diff --git a/conf/container/scripts/default.config b/conf/container/scripts/app/default.config similarity index 100% rename from conf/container/scripts/default.config rename to conf/container/scripts/app/default.config diff --git a/conf/container/scripts/init_2_conf_payara.sh b/conf/container/scripts/app/init_2_conf_payara.sh similarity index 94% rename from conf/container/scripts/init_2_conf_payara.sh rename to conf/container/scripts/app/init_2_conf_payara.sh index 5ca61aeb32f..c34c2230772 100644 --- a/conf/container/scripts/init_2_conf_payara.sh +++ b/conf/container/scripts/app/init_2_conf_payara.sh @@ -22,7 +22,7 @@ echo "# Dataverse postboot configuration for Payara" > ${DV_POSTBOOT} # TODO: This is ugly and dirty. It leaves leftovers on the filesystem. # It should be replaced by using proper config mechanisms sooner than later, # like MicroProfile Config API. -for alias in rserve doi db +for alias in rserve doi do if [ -f ${SECRETS_DIR}/$alias/password ]; then echo "INFO: Defining password alias for $alias" @@ -93,12 +93,15 @@ env -0 | grep -z -Ee "^(dataverse|doi)_" | while IFS='=' read -r -d '' k v; do echo "create-system-properties ${KEY}=${v}" >> ${DV_POSTBOOT} done -# 4. Add the commands to the existing postboot file, but insert BEFORE deployment +# 4. Disable phone home. Always. +echo "disable-phone-home" >> ${DV_POSTBOOT} + +# 5. Enable config dir for dealing with secrets etc. +echo "set-config-dir --directory=$SECRETS_DIR" >> ${DV_POSTBOOT} + +# 6. Add the commands to the existing postboot file, but insert BEFORE deployment echo "$(cat ${DV_POSTBOOT} | cat - ${POSTBOOT_COMMANDS} )" > ${POSTBOOT_COMMANDS} echo "DEBUG: postboot contains the following commands:" echo "--------------------------------------------------" cat ${POSTBOOT_COMMANDS} echo "--------------------------------------------------" - -# 6. Disable phone home. Always. -echo "disable-phone-home" >> ${PREBOOT_COMMANDS} diff --git a/conf/container/scripts/init_3_enabledev.sh b/conf/container/scripts/app/init_3_enabledev.sh similarity index 100% rename from conf/container/scripts/init_3_enabledev.sh rename to conf/container/scripts/app/init_3_enabledev.sh diff --git a/conf/container/scripts/metadata-update.sh b/conf/container/scripts/app/metadata-update.sh similarity index 100% rename from conf/container/scripts/metadata-update.sh rename to conf/container/scripts/app/metadata-update.sh diff --git a/conf/container/scripts/system/entrypoint.sh b/conf/container/scripts/system/entrypoint.sh new file mode 100644 index 00000000000..438f177a11b --- /dev/null +++ b/conf/container/scripts/system/entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +for f in ${SCRIPT_DIR}/init_* ${SCRIPT_DIR}/init.d/*; do + case "$f" in + *.sh) echo "[Entrypoint] running $f"; . "$f" ;; + *) echo "[Entrypoint] ignoring $f" ;; + esac + echo +done + +exec ${SCRIPT_DIR}/startInForeground.sh $PAYARA_ARGS diff --git a/conf/container/scripts/system/init_1_generate_deploy_commands.sh b/conf/container/scripts/system/init_1_generate_deploy_commands.sh new file mode 100644 index 00000000000..234196ee246 --- /dev/null +++ b/conf/container/scripts/system/init_1_generate_deploy_commands.sh @@ -0,0 +1,62 @@ +#!/bin/bash +################################################################################ +# +# A script to append deploy commands to the post boot command file at +# $PAYARA_HOME/scripts/post-boot-commands.asadmin file. All applications in the +# $DEPLOY_DIR (either files or folders) will be deployed. +# The $POSTBOOT_COMMANDS file can then be used with the start-domain using the +# --postbootcommandfile parameter to deploy applications on startup. +# +# Usage: +# ./generate_deploy_commands.sh +# +# Optionally, any number of parameters of the asadmin deploy command can be +# specified as parameters to this script. +# E.g., to deploy applications with implicit CDI scanning disabled: +# +# ./generate_deploy_commands.sh --properties=implicitCdiEnabled=false +# +# Environment variables used: +# - $PREBOOT_COMMANDS - the pre boot command file. +# - $POSTBOOT_COMMANDS - the post boot command file. +# +# Note that many parameters to the deploy command can be safely used only when +# a single application exists in the $DEPLOY_DIR directory. +################################################################################ + +# Check required variables are set +if [ -z $DEPLOY_DIR ]; then echo "Variable DEPLOY_DIR is not set."; exit 1; fi +if [ -z $PREBOOT_COMMANDS ]; then echo "Variable PREBOOT_COMMANDS is not set."; exit 1; fi +if [ -z $POSTBOOT_COMMANDS ]; then echo "Variable POSTBOOT_COMMANDS is not set."; exit 1; fi + +# Create pre and post boot command files if they don't exist +touch $POSTBOOT_COMMANDS +touch $PREBOOT_COMMANDS + +deploy() { + + if [ -z $1 ]; then + echo "No deployment specified"; + exit 1; + fi + + DEPLOY_STATEMENT="deploy $DEPLOY_PROPS $1" + if grep -q $1 $POSTBOOT_COMMANDS; then + echo "post boot commands already deploys $1"; + else + echo "Adding deployment target $1 to post boot commands"; + echo $DEPLOY_STATEMENT >> $POSTBOOT_COMMANDS; + fi +} + +# RAR files first +for deployment in $(find $DEPLOY_DIR -mindepth 1 -maxdepth 1 -name "*.rar"); +do + deploy $deployment; +done + +# Then every other WAR, EAR, JAR or directory +for deployment in $(find $DEPLOY_DIR -mindepth 1 -maxdepth 1 ! -name "*.rar" -a -name "*.war" -o -name "*.ear" -o -name "*.jar" -o -type d); +do + deploy $deployment; +done diff --git a/conf/container/scripts/system/startInForeground.sh b/conf/container/scripts/system/startInForeground.sh new file mode 100644 index 00000000000..f2b82ee2020 --- /dev/null +++ b/conf/container/scripts/system/startInForeground.sh @@ -0,0 +1,73 @@ +#!/bin/bash +########################################################################################################## +# +# This script is to execute Payara Server in foreground, mainly in a docker environment. +# It allows to avoid running 2 instances of JVM, which happens with the start-domain --verbose command. +# +# Usage: +# Running +# startInForeground.sh +# is equivalent to running +# asadmin start-domain +# +# It's possible to use any arguments of the start-domain command as arguments to startInForeground.sh +# +# Environment variables used: +# - $ADMIN_USER - the username to use for the asadmin utility. +# - $PASSWORD_FILE - the password file to use for the asadmin utility. +# - $PREBOOT_COMMANDS - the pre boot command file. +# - $POSTBOOT_COMMANDS - the post boot command file. +# - $DOMAIN_NAME - the name of the domain to start. +# - $JVM_ARGS - extra JVM options to pass to the Payara Server instance. +# - $AS_ADMIN_MASTERPASSWORD - the master password for the Payara Server instance. +# +# This script executes the asadmin tool which is expected at ~/appserver/bin/asadmin. +# +########################################################################################################## + +# Check required variables are set +if [ -z $ADMIN_USER ]; then echo "Variable ADMIN_USER is not set."; exit 1; fi +if [ -z $PASSWORD_FILE ]; then echo "Variable PASSWORD_FILE is not set."; exit 1; fi +if [ -z $PREBOOT_COMMANDS ]; then echo "Variable PREBOOT_COMMANDS is not set."; exit 1; fi +if [ -z $POSTBOOT_COMMANDS ]; then echo "Variable POSTBOOT_COMMANDS is not set."; exit 1; fi +if [ -z $DOMAIN_NAME ]; then echo "Variable DOMAIN_NAME is not set."; exit 1; fi + +# The following command gets the command line to be executed by start-domain +# - print the command line to the server with --dry-run, each argument on a separate line +# - remove -read-string argument +# - surround each line except with parenthesis to allow spaces in paths +# - remove lines before and after the command line and squash commands on a single line + +# Create pre and post boot command files if they don't exist +touch $POSTBOOT_COMMANDS +touch $PREBOOT_COMMANDS + +OUTPUT=`${PAYARA_DIR}/bin/asadmin --user=${ADMIN_USER} --passwordfile=${PASSWORD_FILE} start-domain --dry-run --prebootcommandfile=${PREBOOT_COMMANDS} --postbootcommandfile=${POSTBOOT_COMMANDS} $@ $DOMAIN_NAME` +STATUS=$? +if [ "$STATUS" -ne 0 ] + then + echo ERROR: $OUTPUT >&2 + exit 1 +fi + +COMMAND=`echo "$OUTPUT"\ + | sed -n -e '2,/^$/p'\ + | sed "s|glassfish.jar|glassfish.jar $JVM_ARGS |g"` + +echo Executing Payara Server with the following command line: +echo $COMMAND | tr ' ' '\n' +echo + +# Run the server in foreground - read master password from variable or file or use the default "changeit" password + +set +x +if test "$AS_ADMIN_MASTERPASSWORD"x = x -a -f "$PASSWORD_FILE" + then + source "$PASSWORD_FILE" +fi +if test "$AS_ADMIN_MASTERPASSWORD"x = x + then + AS_ADMIN_MASTERPASSWORD=changeit +fi +echo "AS_ADMIN_MASTERPASSWORD=$AS_ADMIN_MASTERPASSWORD" > /tmp/masterpwdfile +exec ${COMMAND} < /tmp/masterpwdfile