systemd를 사용하여 Minecraft 서버 시작/중지

systemd를 사용하여 Minecraft 서버 시작/중지

저는 sysV init 스크립트를 사용하여 Minecraft 서버를 실행해 왔습니다. 이것은 매우 좋은 스크립트입니다. Minecraft를 "화면"에서 실행하면 Minecraft가 두 번 시작되지 않고 Minecraft가 닫힐 때까지 기다립니다. Minecraft에 명령을 전달할 수도 있어 /etc/init.d/minecraft command <command>백업을 계획하는 데 유용합니다.

이제 저는 시스템화되어 있는 Debian Jessie로 업그레이드했습니다. 하지만 지금은 이전 대본이 훌륭하기 때문에 그대로 유지합니다. 하지만 저는 실제로 systemd를 매우 지지합니다. 많은 개선, 단순화 및 중앙 집중화가 이루어진 것 같습니다. systemd 개발자들이 "기존 sysV 스크립트는 이전처럼 작동할 것"이라고 약속했던 것을 기억합니다. 그러나 그것이 그렇게 쉽지는 않았습니다!

이전에 일부 시작 스크립트에 문제가 있었던 것을 기억합니다. 스크립트를 /etc/init.d에 넣고 실행 가능으로 표시하는 것만으로는 더 이상 충분하지 않습니다. 작동하려면 스크립트를 "활성화"해야 했습니다. "음, 이제 systemd에서 인식되고 이제 systemctl을 통해 제어할 수 있습니다. 명령을 처리하려면 이전 스크립트를 사용해야 할 것 같습니다!"라고 생각했습니다.

제대로 시작되지 않고, 제대로 중지되지 않고, 상태가 올바르게 표시되지 않으며, "명령" 명령이 누락되었습니다. 나는 systemd가 sysV보다 어떻게 더 나은지, 그리고 모든 것을 단순화하고 향상시키기 위해 무엇을 할 수 있는지에 대한 정보를 찾기 시작했습니다. 분명히 systemctl 자체는 가장 간단한 단위 파일을 가능하게 하며, 그것으로 충분하기를 바랍니다! 이제 systemd가 실제로 그렇게 복잡한 상황을 전혀 처리할 수 없는지 궁금합니다!

일반 시스템 서비스는 기본적으로 몇 가지 요구 사항과 ExecStart로 구성되어 있다는 것을 알았습니다. systemd가 데몬 프로세스를 모니터링해야 하는 것처럼. 조건과 실행 파일 이름을 입력하면 systemd가 시작, 중지 및 기타 사항을 처리합니다. 하지만 쉽지 않아요! Minecraft의 PID를 직접 삭제할 수는 없습니다(화면의 PID와 동일하지 않다는 것은 말할 것도 없습니다)! 각 작업에 대해 더 복잡한 스크립트를 작성하고 싶습니다. 어쩌면 "명령"과 같은 새로운 작업을 추가할 수도 있습니다(좋아요, 이것이 전혀 불가능할 수도 있다는 점을 인정했습니다). "상태"의 경우 Java 프로세스를 모니터링해야 하고 중지하려면 Minecraft 콘솔에 명령을 보낸 다음 Java와 화면이 모두 죽을 때까지 기다려야 합니다! 또한 systemd가 SIGHUP, SIGINT 또는 SIGTERM만 시도하지 않도록 하고 싶습니다!

그렇다면 systemd가 제공하는 모든 "개선 사항"과 "단순화"를 실제로 활용할 수 있게 해주는 깔끔하고 현대적이며 "기대되는 systemd 방식"은 무엇입니까? 확실히 한 줄에서 시작하고 SIGINT로 종료되는 단순한 단일 프로세스 데몬보다 더 복잡한 것을 처리할 수 있어야 할까요? systemd 장치를 생성하고 다음과 같이 모든 명령에서 이전 스크립트를 호출하도록 수동으로 지정해야 합니까?

ExecStart=/etc/init.d/minecraft start
ExecReload=/etc/init.d/minecraft reload
(and how do I make the "stop" command and explain how to find the processes to watch for the "status" command?..)

나는 이 점에 있어서 매우 혁신적이고, 포에터링을 지지하고, 시스템에 찬성하며, 이전보다 일을 더 잘할 수 있는 방법이 있어야 한다고 믿습니다. 어쩌면 포터링이 흔히 하는 방식처럼 완전히 다른 방법이 있을 수도 있습니다. 그!). 그러나 이것은 큰 개선처럼 보이지는 않습니다. 이전처럼 계속하려면 많은 조립이 필요한 거대한 퇴보처럼 보입니다. "sysV 스크립트는 계속 작동합니다" 내 포니테일! Minecraft를 제대로 중지하기 위해 시스템이 종료될 때 내 스크립트를 호출하는지, 아니면 단지 "systemctl status"를 보고 "비활성(죽음)"인지 확인하는 것인지조차 알 수 없습니다.

더 좋은 아이디어가 있나요?

답변1

매뉴얼 페이지를 몇 번 살펴본 후(예, 처음에는 답이 없습니다...) 해결책을 찾았지만... 작동하지 않습니다. 좀 더 찾아본 후 마침내 가장 우아한 솔루션을 찾았습니다.

[Unit]
Description=Minecraft server
After=local-fs.target network.target

[Service]
WorkingDirectory=/home/minecraft/minecraft_server
User=minecraft
Group=minecraft
Type=forking
# Run it as a non-root user in a specific directory

ExecStart=/usr/bin/screen -h 1024 -dmS minecraft ./minecraft_server.sh
# I like to keep my commandline to launch it in a separate file
# because sometimes I want to change it or launch it manually
# If it's in the WorkingDirectory, then we can use a relative path

# Send "stop" to the Minecraft server console
ExecStop=/usr/bin/screen -p 0 -S minecraft -X eval 'stuff \"stop\"\015'
# Wait for the PID to die - otherwise it's killed after this command finishes!
ExecStop=/bin/bash -c "while ps -p $MAINPID > /dev/null; do /bin/sleep 1; done"
# Note that absolute paths for all executables are required!

[Install]
WantedBy=multi-user.target

이것은 실제로 원래 스크립트보다 더 좋아 보입니다! 그러나 몇 가지 회귀가 있습니다.

  • 명령을 서버 콘솔에 전달하려면 별도의 스크립트를 작성해야 합니다.
  • 실행한 systemctl start minecraftsystemctl stop minecraft확인하십시오. 그렇지 않으면 systemctl status minecraft이러한 명령이 실제로 실패하더라도 전혀 출력을 제공하지 않습니다. 이것은 스크립트와 비교할 때 유일한 주요 회귀입니다. "항상 출력을 확인하십시오"는 IT의 규칙 #1이지만 systemd는 그것에 신경 쓰지 않는 것 같습니다.
  • 또한 systemd가 "PID 종료 대기" 해결 방법 없이 서비스 종료를 관리할 수 있기를 바랍니다. 이전 init 스크립트에서는 이 작업을 수동으로 수행해야 했습니다. 왜냐하면 이는 스크립트였고 systemd는 동일한 일의 복잡한 스크립트에 대한 필요성을 제거하려고 시도하기 때문입니다. 이는 모든 시간 초과를 수동으로 스크립팅하고 필요하지 않은 시간 초과를 종료하는 것을 제거합니다. 하지만 "pid가 죽을 때까지 기다리는 것"은 우리가 스크립트를 작성해야 하는 다음으로 가장 일반적인 것입니다.

답변2

요약: 화면을 전혀 사용하지 마세요. RCON을 사용하여 서버를 제어하십시오.

저는 화면이 Minecraft 서버 관리를 위한 사실상의 표준이었다는 것을 깨달았지만, 두 가지 방법을 모두 시도한 후에 RCON이 제어 문제를 더 깔끔한 방식으로 해결한다는 결론에 도달했습니다.

스크린 세션에서 서버를 실행하는 이유는 스크린 세션을 사용하여 서버의 표준 입력에 명령을 입력하여 서버에 명령을 보낼 수 있기 때문입니다. 서버의 대화형 콘솔을 사용하기 위해 screen 세션에 직접 연결할 수도 있습니다. 이는 중요한 기능이지만 화면이 이를 달성하는 유일한 방법은 아닙니다.

Minecraft는 원격 관리를 위해 RCON 프로토콜을 지원합니다. 로컬로 사용하여 서버와 상호 작용할 수 있습니다. 나는 사용한다맥콘단일 명령을 보내거나 대화형 터미널 역할을 할 수 있는 명령줄 도구입니다. 이것은 화면보다 더 강력하고 덜 복잡합니다(화면을 통해 명령을 보내면 eval항상 stuff오그라들게 됩니다).

minecraft.service파일은 다음과 같습니다.

[Unit]
Description=Minecraft Server
After=network.target

[Service]
Type=simple
User=minecraft
Group=minecraft
WorkingDirectory=/srv/minecraft
ExecStart=/usr/local/bin/minecraft/start
ExecStop=/usr/local/bin/minecraft/stop
Restart=always

[Install]
WantedBy=default.target

start스크립트는 단순히 서버 실행 파일을 실행합니다.

#!/bin/sh

cd /srv/minecraft
java -Xmx12G -Xms12G \
  -XX:+UnlockExperimentalVMOptions \
  -XX:+UseG1GC \
  -XX:G1NewSizePercent=50 \
  -XX:MaxGCPauseMillis=50 \
  -XX:+AlwaysPreTouch \
  -jar server.jar nogui

스크립트 stop는 서버에 명령을 보내고 프로세스가 중지될 때까지 기다립니다.

#!/bin/sh

/usr/local/bin/minecraft/rcon stop

while kill -0 $MAINPID 2>/dev/null
do
  sleep 0.5
done

rcon스크립트는 간단히 말해서 다음과 같습니다.

#!/bin/sh

mcrcon -H localhost -P 25575 -p "password omitted" $@

내 스크립트에는 RCON 포트와 비밀번호가 하드코딩되어 있지만 server.properties파일에서 쉽게 가져올 수 있습니다. 또한 mcrcon원하는 경우 명령줄 인수가 아닌 환경 변수를 통해 허용됩니다.

기타 참고사항:

  • 파일에서 RCON을 활성화 해야 server.properties하지만 원격 사용을 방지하기 위해 방화벽에서 포트를 닫을 수 있습니다.
  • 대화형 터미널 세션을 시작하려면 rcon인수 없이 실행하세요(또는 mcrcon을 직접 호출하세요).
  • 서버 로그를 보려면 Journalctl을 사용하십시오. 저는 이것을 사용하여 모든 로그를 Discord 웹훅으로 보냅니다.

편집: 다른 답변의 주석은 SIGINT가 명령을 보내는 것처럼 Minecraft 서버를 정상적으로 중지하게 한다고 주장합니다 stop. 그렇다면 서버를 중지하기 위해 RCON을 사용하는 대신 SIGINT를 보내는 것이 더 간단하고 더 좋을 것입니다. RCON은 다른 관리 작업에 여전히 유용합니다.

답변3

나는 이 서비스 파일을 사용합니다:

[Unit]
Description=Minecraft server
Wants=network.target
After=network.target

[Service]
User=minecraft
Group=minecraft
Nice=5

WorkingDirectory=/home/minecraft/.minecraft/
KillMode=process
KillSignal=SIGINT
SuccessExitStatus=130

ExecStart=/usr/bin/java -Xms1G -Xmx1G -jar /home/minecraft/.minecraft/minecraft_server.jar nogui

[Install]
WantedBy=multi-user.target

중지하려면 SIGINT(ctrl+c)를 사용합니다.

KillSignal=SIGINT

SuccessExitStatus는 성공적인 종료를 나타냅니다.

SuccessExitStatus=130

답변4

@darkpenguin의 답변을 기반으로 한 tmux에 대한 내용은 다음과 같습니다.

[Unit]
After=network.target

[Service]
WorkingDirectory=/home/minecraft/server/
Type=forking
User=minecraft
ExecStart=/usr/bin/tmux new-session -s mine1 -n m -d "/home/minecraft/start_minecraft.sh"

# Send "stop" to the Minecraft server console
ExecStop=/usr/bin/tmux send-keys -t mine1 'Stop' Enter
# Wait for the PID to die - otherwise it's killed after this command finishes!
ExecStop=/bin/bash -c "while ps -p $MAINPID > /dev/null; do /bin/sleep 1; done"
# Note that absolute paths for all executables are required!

[Install]
WantedBy=default.target

관련 정보