Handle SIGTERM to stop Minecraft gracefully
- Set up SIGTERM signal trap to invoke stop_server - Ensure proper process exit and cleanup after the server stops - Create makefile to build, clean, and install builds
This commit is contained in:
parent
381bd9eeff
commit
297902a686
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
data
|
data
|
||||||
.env
|
.env
|
||||||
|
screenlog.0
|
||||||
|
@ -10,7 +10,7 @@ RUN groupadd -g 1000 minecraft && \
|
|||||||
|
|
||||||
# Install scripting dependencies
|
# Install scripting dependencies
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y curl gpg jq screen && \
|
apt-get install -y curl gpg jq procps screen strace && \
|
||||||
apt-get clean && \
|
apt-get clean && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
17
Makefile
Normal file
17
Makefile
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
CONTAINER = minecraft-minecraft-1
|
||||||
|
|
||||||
|
.PHONY: default build clean install
|
||||||
|
default: build
|
||||||
|
|
||||||
|
build:
|
||||||
|
docker compose build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f screenlog.0
|
||||||
|
docker compose down --rmi all
|
||||||
|
docker builder prune -f
|
||||||
|
|
||||||
|
install: build
|
||||||
|
touch screenlog.0
|
||||||
|
docker compose up -d && \
|
||||||
|
docker logs -f $(CONTAINER)
|
13
README.md
13
README.md
@ -1,13 +1,24 @@
|
|||||||
# Minecraft Docker Image
|
# Minecraft Docker Image
|
||||||
This Dockerfile sets up a Minecraft server based on the `debian-slim` image.
|
This Dockerfile sets up a Minecraft server based on the `debian-slim` image.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
By running the following and building this image, you are agreeing to
|
By running the following and building this image, you are agreeing to
|
||||||
[Minecraft's EULA](https://www.minecraft.net/en-us/eula):
|
[Minecraft's EULA](https://www.minecraft.net/en-us/eula):
|
||||||
```
|
```
|
||||||
echo "EULA=true" > .env
|
echo "EULA=true" > .env
|
||||||
```
|
```
|
||||||
|
|
||||||
To build and test the image:
|
Build the image using the Makefile:
|
||||||
|
```
|
||||||
|
make build
|
||||||
|
```
|
||||||
|
|
||||||
|
Optionally, build _and_ run to test it:
|
||||||
|
```
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
Feel free to use `docker compose` directly to build and test:
|
||||||
```
|
```
|
||||||
docker compose build
|
docker compose build
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
volumes:
|
|
||||||
minecraft:
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
minecraft:
|
minecraft:
|
||||||
build:
|
build:
|
||||||
@ -12,12 +9,10 @@ services:
|
|||||||
image: ${IMAGE:-minecraft}:${TAG:-latest}
|
image: ${IMAGE:-minecraft}:${TAG:-latest}
|
||||||
ports:
|
ports:
|
||||||
- "0.0.0.0:25565:25565"
|
- "0.0.0.0:25565:25565"
|
||||||
#volumes:
|
|
||||||
# - minecraft:/app/world
|
|
||||||
environment:
|
environment:
|
||||||
EULA: "${EULA:-false}"
|
EULA: "${EULA:-false}"
|
||||||
DEBUG: "${DEBUG:-false}"
|
DEBUG: "${DEBUG:-false}"
|
||||||
JVM_OPTS: "-Xms1G -Xmx2G"
|
JVM_OPTS: "${JAVA_OPTS:--Xms1G -Xmx2G}"
|
||||||
SETTINGS_gamemode: "${GAMEMODE:-survival}"
|
SETTINGS_gamemode: "${GAMEMODE:-survival}"
|
||||||
SETTINGS_hardcore: "${HARDCORE:-false}"
|
SETTINGS_hardcore: "${HARDCORE:-false}"
|
||||||
SETTINGS_motd: "${MOTD:-A Minecraft Server}"
|
SETTINGS_motd: "${MOTD:-A Minecraft Server}"
|
||||||
|
@ -1,5 +1,44 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Check if the minecraft screen is still running
|
||||||
|
check_screen() {
|
||||||
|
if [ "$(screen -ls | grep -cE '[0-9]+\.minecraft')" -eq 1 ]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to stop the server gracefully
|
||||||
|
stop_server() {
|
||||||
|
if check_screen; then
|
||||||
|
# Run 'stop' inside screen and wait for the screen to exit
|
||||||
|
/usr/bin/screen -p 0 -S minecraft -X eval 'stuff "stop"\015'
|
||||||
|
wait "$STRACE_PID"
|
||||||
|
|
||||||
|
# Stop tail -f to stdout
|
||||||
|
if kill -0 "$TAIL_PID" 2>/dev/null; then
|
||||||
|
kill "$TAIL_PID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check only this script is running (PID 1) and pgrep (2 PIDs total)
|
||||||
|
PGREP_OUTPUT="$(pgrep .)"
|
||||||
|
if ! [ "$(echo "$PGREP_OUTPUT" | wc -l)" -eq 2 ]; then
|
||||||
|
echo "[WARN] Some processes might not have exited:"
|
||||||
|
echo "$PGREP_OUTPUT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Exit cleanly
|
||||||
|
echo "[INFO] Server stopped gracefully"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "[ERROR]: Can't find which screen to use"
|
||||||
|
screen -ls
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Enable debug mode
|
# Enable debug mode
|
||||||
DEBUG="${DEBUG:-false}"
|
DEBUG="${DEBUG:-false}"
|
||||||
if [ "$DEBUG" = "true" ]; then
|
if [ "$DEBUG" = "true" ]; then
|
||||||
@ -32,9 +71,10 @@ while IFS='=' read -r ENVVAR VALUE ; do
|
|||||||
rm "${FILE}.bak"
|
rm "${FILE}.bak"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
[ "$DEBUG" = "true" ] && \
|
if [ "$DEBUG" = "true" ]; then
|
||||||
echo "[DEBUG] \"$ENVVAR\" doesn't have the prefix \"$PREFIX\""
|
echo "[DEBUG] \"$ENVVAR\" doesn't have the prefix \"$PREFIX\""
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
done < <(env)
|
done < <(env)
|
||||||
|
|
||||||
# Show server.properties in DEBUG mode
|
# Show server.properties in DEBUG mode
|
||||||
@ -43,17 +83,33 @@ if [ "$DEBUG" = "true" ]; then
|
|||||||
cat "$FILE"
|
cat "$FILE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Pre-create the screen log
|
# Set up a SIGTERM signal trap to stop the server
|
||||||
touch screenlog.0
|
trap 'stop_server' SIGTERM
|
||||||
|
|
||||||
# Run server in screen (without attaching)
|
# Run server in screen (without attaching)
|
||||||
|
echo "[INFO] Starting Minecraft server"
|
||||||
/usr/bin/screen -dmS minecraft -L \
|
/usr/bin/screen -dmS minecraft -L \
|
||||||
bash -c "
|
bash -c "/usr/bin/java $JVM_OPTS -jar server.jar --nogui"
|
||||||
sleep 0.5
|
|
||||||
[ $DEBUG = true ] && echo '[DEBUG] Starting server'
|
|
||||||
/usr/bin/java $JVM_OPTS -jar server.jar --nogui
|
|
||||||
"
|
|
||||||
|
|
||||||
# Tail screen log to container stdout
|
# Get screen PID
|
||||||
[ "$DEBUG" = "true" ] && echo "[DEBUG] Tailing screenlog.0"
|
[ "$DEBUG" = "true" ] && screen -ls
|
||||||
tail -f screenlog.0
|
SCREEN_PID="$(
|
||||||
|
screen -ls | grep -oE '[0-9]+\.minecraft' | cut -d. -f1
|
||||||
|
)"
|
||||||
|
|
||||||
|
# Check screen PID
|
||||||
|
if ! kill -0 "$SCREEN_PID" 2>/dev/null; then
|
||||||
|
echo "[ERROR] Cannot find Minecraft screen (PID: \"$SCREEN_PID\")"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Output logs to stdout (touch in case slow to create)
|
||||||
|
touch screenlog.0
|
||||||
|
tail -f screenlog.0 &
|
||||||
|
TAIL_PID="$!"
|
||||||
|
|
||||||
|
# Wait for screen to exit
|
||||||
|
strace -e exit -e signal=none -p "$SCREEN_PID" 2>/dev/null &
|
||||||
|
STRACE_PID="$!"
|
||||||
|
[ "$DEBUG" = "true" ] && ps aux
|
||||||
|
wait "$STRACE_PID"
|
||||||
|
Loading…
Reference in New Issue
Block a user