From 1fcbd8410f2ba22a850b4c96eeb1f878b5b6d9b7 Mon Sep 17 00:00:00 2001 From: Geoff Bourne Date: Tue, 29 Dec 2020 10:56:05 -0600 Subject: [PATCH 1/6] Allow CUSTOM_SERVER to reference not-yet-existing file from GENERIC_PACK For #703 --- start-deployCustom | 6 +++++- start-finalSetupModpack | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/start-deployCustom b/start-deployCustom index 571a5a0c..e2939ab8 100644 --- a/start-deployCustom +++ b/start-deployCustom @@ -17,12 +17,16 @@ if isURL ${CUSTOM_SERVER}; then fi elif [[ -f ${CUSTOM_SERVER} ]]; then - log "Using custom server jar at ${CUSTOM_SERVER} ..." + export SERVER=${CUSTOM_SERVER} + +elif [[ ${GENERIC_PACK} ]]; then + log "Using custom server jar from generic pack at ${CUSTOM_SERVER} ..." export SERVER=${CUSTOM_SERVER} else log "CUSTOM_SERVER is not properly set to a URL or existing jar file" exit 2 + fi export SKIP_LOG4J_CONFIG=true diff --git a/start-finalSetupModpack b/start-finalSetupModpack index 4b955e27..7e477582 100644 --- a/start-finalSetupModpack +++ b/start-finalSetupModpack @@ -153,7 +153,8 @@ if [[ "${GENERIC_PACK}" ]]; then if ! sha256sum -c ${sum_file} -s 2> /dev/null; then base_dir=/tmp/generic_pack_base mkdir -p ${base_dir} - unzip -q -d ${base_dir} ${GENERIC_PACK} + isDebugging && ls -l "${GENERIC_PACK}" + unzip -q -d ${base_dir} "${GENERIC_PACK}" if [ -f /data/manifest.txt ]; then log "Manifest exists from older generic pack, cleaning up ..." while read f; do @@ -171,7 +172,7 @@ if [[ "${GENERIC_PACK}" ]]; then for d in $(find ${base_dir} -type d); do mkdir -p "$(sed "s#${base_dir}#/data#" <<< $d)"; done for f in $(find ${base_dir} -type f); do cp -f "$f" "$(sed "s#${base_dir}#/data#" <<< $f)"; done rm -rf ${base_dir} - sha256sum ${GENERIC_PACK} > ${sum_file} + sha256sum "${GENERIC_PACK}" > ${sum_file} fi fi From 3de2bf88df93a0ef8ef41830dafb22ca6b45962e Mon Sep 17 00:00:00 2001 From: Geoff Bourne Date: Wed, 30 Dec 2020 09:42:29 -0600 Subject: [PATCH 2/6] Escaped backslashes when setting server property value (#706) * Escaped backslashes when setting server property value For #446 * Fixed pattern substitution to "replace all" --- start-finalSetupServerProperties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start-finalSetupServerProperties b/start-finalSetupServerProperties index 32608c47..d058cf95 100644 --- a/start-finalSetupServerProperties +++ b/start-finalSetupServerProperties @@ -13,7 +13,7 @@ function setServerProp { var=${var,,} ;; esac log "Setting ${prop} to '${var}' in ${SERVER_PROPERTIES}" - sed -i "/^${prop}\s*=/ c ${prop}=${var}" "$SERVER_PROPERTIES" + sed -i "/^${prop}\s*=/ c ${prop}=${var//\\/\\\\}" "$SERVER_PROPERTIES" else log "Skip setting ${prop}" fi From 8ee650f38d5f2d1ddfc33b62c676cd41811c0a8a Mon Sep 17 00:00:00 2001 From: Geoff Bourne Date: Thu, 31 Dec 2020 13:11:26 -0600 Subject: [PATCH 3/6] Allowed CF_BASE_DIR/FTB_BASE_DIR to be configured For #518 --- README.md | 8 +++++++- start-deployCF | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5340d3ae..ddcb1201 100644 --- a/README.md +++ b/README.md @@ -535,6 +535,12 @@ The following example uses `/modpacks` as the container path as the pre-download -e CF_SERVER_MOD=/modpacks/SkyFactory_4_Server_4.1.0.zip \ -p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server +#### Modpack data directory + +By default, CurseForge modpacks are expanded into the sub-directory `/data/FeedTheBeast` and executed from there. (The default location was chosen for legacy reasons, when Curse and FTB were maintained together.) + +The directory can be changed by setting `CF_BASE_DIR`, such as `-e CF_BASE_DIR=/data`. + #### Buggy start scripts Some modpacks have buggy or overly complex start scripts. You can avoid using the bundled start script and use this image's standard server-starting logic by adding `-e USE_MODPACK_START_SCRIPT=false`. @@ -1125,4 +1131,4 @@ To run this image on a RaspberryPi 3 B+, 4, or newer, use the image tag itzg/minecraft-server:multiarch -> NOTE: you may need to lower the memory allocation, such as `-e MEMORY=750m` \ No newline at end of file +> NOTE: you may need to lower the memory allocation, such as `-e MEMORY=750m` diff --git a/start-deployCF b/start-deployCF index 97e4e54f..86bd44ca 100644 --- a/start-deployCF +++ b/start-deployCF @@ -5,7 +5,9 @@ set -e . ${SCRIPTS:-/}start-utils isDebugging && set -x -export FTB_BASE_DIR=/data/FeedTheBeast +: ${FTB_BASE_DIR:=${CF_BASE_DIR:-/data/FeedTheBeast}} +export FTB_BASE_DIR + legacyJavaFixerUrl=https://ftb.forgecdn.net/FTB2/maven/net/minecraftforge/lex/legacyjavafixer/1.0/legacyjavafixer-1.0.jar export TYPE=FEED-THE-BEAST From 468671a3fa01b90cc9c7468ca30f407872d69630 Mon Sep 17 00:00:00 2001 From: "Nathanial L. McConnell" Date: Fri, 1 Jan 2021 16:23:04 -0500 Subject: [PATCH 4/6] Update README.md (#712) Change "Please" to "Place" --- examples/modpacks/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/modpacks/README.md b/examples/modpacks/README.md index 17b8e85b..8adbed9b 100644 --- a/examples/modpacks/README.md +++ b/examples/modpacks/README.md @@ -1,3 +1,3 @@ -Please server [modpacks downloaded from CurseForge](https://www.curseforge.com/minecraft/modpacks) in this directory. +Place server [modpacks downloaded from CurseForge](https://www.curseforge.com/minecraft/modpacks) in this directory. The example [`docker-compose-curseforge.yml`](../docker-compose-curseforge.yml) references a modpack downloaded from . From 02bce8c3a86686d0c687d285f11a49e341362030 Mon Sep 17 00:00:00 2001 From: Geoff Bourne Date: Sat, 2 Jan 2021 11:12:07 -0600 Subject: [PATCH 5/6] docs: Documented adopt15 and multiarch-latest tags --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ddcb1201..ad9a4f58 100644 --- a/README.md +++ b/README.md @@ -146,13 +146,15 @@ To use a different version of Java, please use a docker tag to run your Minecraf | Tag name | Description | Linux | | -------------- | ------------------------------------------- | ------------ | -| latest | **Default**. Uses Java version 8 update 212 | Alpine Linux | -| adopt14 | Uses Java version 14 latest update | Alpine Linux | -| adopt13 | Uses Java version 13 latest update | Alpine Linux | -| adopt11 | Uses Java version 11 latest update | Alpine Linux | +| latest | **Default**. Uses Java version 8 | Alpine Linux | +| adopt15 | Uses Java version 15 from AdoptOpenJDK | Alpine Linux | +| adopt14 | Uses Java version 14 from AdoptOpenJDK | Alpine Linux | +| adopt13 | Uses Java version 13 from AdoptOpenJDK | Alpine Linux | +| adopt11 | Uses Java version 11 from AdoptOpenJDK | Alpine Linux | | openj9 | Uses Eclipse OpenJ9 JVM | Alpine Linux | | openj9-nightly | Uses Eclipse OpenJ9 JVM testing builds | Alpine Linux | | multiarch | Uses Java version 8 latest update | Debian Linux | +| multiarch-latest | Uses Java version 15 latest update | Debian Linux | For example, to use a Java version 13: From 2fb01b4adfcd279e914ed6a5b1c5bac70994ec11 Mon Sep 17 00:00:00 2001 From: Michael Kirsch Date: Sat, 2 Jan 2021 18:27:03 +0100 Subject: [PATCH 6/6] Autopause update: allow network interface selection (#711) * Cherry-pick: Fixing AUTOPAUSE on Raspberry Pi 4s (#708) * implement autopause interface selection * concentrate ps calls in function file * wording and add note about PAPER's etc watchdogs --- Dockerfile | 3 +- README.md | 12 ++++--- files/autopause/autopause-daemon.sh | 49 ++++++++++++++++++++++------- files/autopause/autopause-fcns.sh | 4 +++ files/autopause/pause.sh | 2 +- files/autopause/resume.sh | 2 +- files/sudoers-mc | 2 +- start-autopause | 9 ++++-- 8 files changed, 60 insertions(+), 23 deletions(-) diff --git a/Dockerfile b/Dockerfile index ef7b5e41..c21bbd0a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -74,7 +74,8 @@ ENV UID=1000 GID=1000 \ TYPE=VANILLA VERSION=LATEST FORGEVERSION=RECOMMENDED SPONGEBRANCH=STABLE SPONGEVERSION= FABRICVERSION=LATEST LEVEL=world \ PVP=true DIFFICULTY=easy ENABLE_RCON=true RCON_PORT=25575 RCON_PASSWORD=minecraft \ LEVEL_TYPE=DEFAULT SERVER_PORT=25565 ONLINE_MODE=TRUE SERVER_NAME="Dedicated Server" \ - ENABLE_AUTOPAUSE=false AUTOPAUSE_TIMEOUT_EST=3600 AUTOPAUSE_TIMEOUT_KN=120 AUTOPAUSE_TIMEOUT_INIT=600 AUTOPAUSE_PERIOD=10 + ENABLE_AUTOPAUSE=false AUTOPAUSE_TIMEOUT_EST=3600 AUTOPAUSE_TIMEOUT_KN=120 AUTOPAUSE_TIMEOUT_INIT=600 \ + AUTOPAUSE_PERIOD=10 AUTOPAUSE_KNOCK_INTERFACE=eth0 COPY start* / COPY health.sh / diff --git a/README.md b/README.md index ad9a4f58..ca19395b 100644 --- a/README.md +++ b/README.md @@ -182,22 +182,22 @@ healthy Some orchestration systems, such as Portainer, don't allow for disabling the default `HEALTHCHECK` declared by this image. In those cases you can approximate the disabling of healthchecks by setting the environment variable `DISABLE_HEALTHCHECK` to `true`. -## Autopause (experimental) +## Autopause ### Description -> EXPERIMENTAL: this feature only works with default bridge networking using official Docker distributions. Host networking and container management software, such as Portainer, and NAS solutions do not seem to provide compatible networking. - There are various bug reports on [Mojang](https://bugs.mojang.com) about high CPU usage of servers with newer versions, even with few or no clients connected (e.g. [this one](https://bugs.mojang.com/browse/MC-149018), in fact the functionality is based on [this comment in the thread](https://bugs.mojang.com/browse/MC-149018?focusedCommentId=593606&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-593606)). An autopause functionality has been added to this image to monitor whether clients are connected to the server. If for a specified time no client is connected, the Java process is stopped. When knocking on the server port (e.g. by the ingame Multiplayer server overview), the process is resumed. The experience for the client does not change. Of course, even loaded chunks are not ticked when the process is stopped. -From the server's point of view, the pausing causes a single tick to take as long as the process is stopped, so the server watchdog might intervene after the process is continued, possibly forcing a container restart. To prevent this, ensure that the `max-tick-time` in the `server.properties` file is set correctly. +From the server's point of view, the pausing causes a single tick to take as long as the process is stopped, so the server watchdog might intervene after the process is continued, possibly forcing a container restart. To prevent this, ensure that the `max-tick-time` in the `server.properties` file is set correctly. Non-vanilla versions might have their own configuration file, you might have to disable their watchdogs separately (e.g. PAPER Servers). On startup the `server.properties` file is checked and, if applicable, a warning is printed to the terminal. When the server is created (no data available in the persistent directory), the properties file is created with the Watchdog disabled. +The utility used to wake the server (`knock(d)`) works at network interface level. So the correct interface has to be set using the `AUTOPAUSE_KNOCK_INTERFACE` variable when using non-default networking environments (e.g. host-networking, Portainer oder NAS solutions). See the description of the variable below. + A starting, example compose file has been provided in [examples/docker-compose-autopause.yml](examples/docker-compose-autopause.yml). ### Enabling Autopause @@ -208,7 +208,7 @@ Enable the Autopause functionality by setting: -e ENABLE_AUTOPAUSE=TRUE ``` -There are 4 more environment variables that define the behaviour: +The following environment variables define the behaviour of auto-pausing: * `AUTOPAUSE_TIMEOUT_EST`, default `3600` (seconds) describes the time between the last client disconnect and the pausing of the process (read as timeout established) * `AUTOPAUSE_TIMEOUT_INIT`, default `600` (seconds) @@ -217,6 +217,8 @@ describes the time between server start and the pausing of the process, when no describes the time between knocking of the port (e.g. by the main menu ping) and the pausing of the process, when no client connects inbetween (read as timeout knocked) * `AUTOPAUSE_PERIOD`, default `10` (seconds) describes period of the daemonized state machine, that handles the pausing of the process (resuming is done independently) +* `AUTOPAUSE_KNOCK_INTERFACE`, default `eth0` +
Describes the interface passed to the `knockd` daemon. If the default interface does not work, run the `ifconfig` command inside the container and derive the interface receiving the incoming connection from its output. The passed interface must exist inside the container. Using the loopback interface (`lo`) does likely not yield the desired results. ## Deployment Templates and Examples diff --git a/files/autopause/autopause-daemon.sh b/files/autopause/autopause-daemon.sh index e46fdffa..e2f48608 100644 --- a/files/autopause/autopause-daemon.sh +++ b/files/autopause/autopause-daemon.sh @@ -2,23 +2,48 @@ . /autopause/autopause-fcns.sh -. /start-utils +. ${SCRIPTS:-/}start-utils -sudo /usr/sbin/knockd -c /tmp/knockd-config.cfg -d -if [ $? -ne 0 ] ; then + +autopause_error_loop() { + logAutopause "Available interfaces within the docker container:" + INTERFACES=$(echo /sys/class/net/*) + INTERFACES=${INTERFACES//\/sys\/class\/net\//} + logAutopause " $INTERFACES" + logAutopause "Please set the environment variable AUTOPAUSE_KNOCK_INTERFACE to the interface that handles incoming connections." + logAutopause "If unsure which interface to choose, run the ifconfig command in the container." + logAutopause "Autopause failed to initialize. This log entry will be printed every 30 minutes." while : do - if [[ -n $(ps -o comm | grep java) ]] ; then - break - fi - sleep 0.1 + sleep 1800 + logAutopause "Autopause failed to initialize." done +} + +# wait for java process to be started +while : +do + if java_process_exists ; then + break + fi + sleep 0.1 +done + +# check for interface existence +if [[ -z "$AUTOPAUSE_KNOCK_INTERFACE" ]] ; then + logAutopause "AUTOPAUSE_KNOCK_INTERFACE variable must not be empty!" + autopause_error_loop +fi +if ! [[ -d "/sys/class/net/$AUTOPAUSE_KNOCK_INTERFACE" ]] ; then + logAutopause "Selected interface \"$AUTOPAUSE_KNOCK_INTERFACE\" does not exist!" + autopause_error_loop +fi + +sudo /usr/sbin/knockd -c /tmp/knockd-config.cfg -d -i "$AUTOPAUSE_KNOCK_INTERFACE" +if [ $? -ne 0 ] ; then logAutopause "Failed to start knockd daemon." - logAutopause "Possible cause: docker's host network mode." - logAutopause "Recreate without host mode or disable autopause functionality." - logAutopause "Stopping server." - killall -SIGTERM java - exit 1 + logAutopause "Probable cause: Unable to attach to interface \"$AUTOPAUSE_KNOCK_INTERFACE\"." + autopause_error_loop fi STATE=INIT diff --git a/files/autopause/autopause-fcns.sh b/files/autopause/autopause-fcns.sh index 5ebae93c..bf6cc7c4 100644 --- a/files/autopause/autopause-fcns.sh +++ b/files/autopause/autopause-fcns.sh @@ -8,6 +8,10 @@ java_running() { [[ $( ps -a -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^S.*$ ]] } +java_process_exists() { + [[ -n "$(ps -a -o comm | grep 'java')" ]] +} + rcon_client_exists() { [[ -n "$(ps -a -o comm | grep 'rcon-cli')" ]] } diff --git a/files/autopause/pause.sh b/files/autopause/pause.sh index c84bdda5..9bcb4a06 100755 --- a/files/autopause/pause.sh +++ b/files/autopause/pause.sh @@ -17,5 +17,5 @@ if [[ $( ps -a -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^S.*$ ]] ; th # finally pause the process logAutopauseAction "Pausing Java process" - killall -q -STOP java + pkill -STOP java fi diff --git a/files/autopause/resume.sh b/files/autopause/resume.sh index 73ab648e..5d1686f0 100755 --- a/files/autopause/resume.sh +++ b/files/autopause/resume.sh @@ -4,5 +4,5 @@ if [[ $( ps -a -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^T.*$ ]] ; then logAutopauseAction "Knocked, resuming Java process" - killall -q -CONT java + pkill -CONT java fi diff --git a/files/sudoers-mc b/files/sudoers-mc index 419c352e..39926d72 100644 --- a/files/sudoers-mc +++ b/files/sudoers-mc @@ -1,2 +1,2 @@ -%minecraft ALL=(ALL) NOPASSWD:/usr/bin/killall +%minecraft ALL=(ALL) NOPASSWD:/usr/bin/pkill %minecraft ALL=(ALL) NOPASSWD:/usr/sbin/knockd diff --git a/start-autopause b/start-autopause index 51acfc5e..5297272c 100755 --- a/start-autopause +++ b/start-autopause @@ -46,10 +46,15 @@ if ! [[ $AUTOPAUSE_TIMEOUT_INIT =~ ^[0-9]+$ ]] ; then export AUTOPAUSE_TIMEOUT_INIT log "Warning: AUTOPAUSE_TIMEOUT_INIT is not numeric, set to 600 (seconds)" fi +if [[ "$AUTOPAUSE_KNOCK_INTERFACE" == "lo" ]] ; then + log "Warning: AUTOPAUSE_KNOCK_INTERFACE is set to the local loopback interface." + log " This is not advisable, as incoming connections are likely not picked up there." + log " Continuing with this setting." +fi -if [[ -n $MAX_TICK_TIME ]] ; then +if [[ -n "$MAX_TICK_TIME" && "$MAX_TICK_TIME" != "-1" ]] ; then log "Warning: MAX_TICK_TIME is non-default, for autopause to work properly, this check should be disabled (-1 for versions >= 1.8.1)" -else +elif [[ -z "$MAX_TICK_TIME" ]] ; then if versionLessThan 1.8.1; then # 10 years MAX_TICK_TIME=315360000000