Minecraft Server with MCDReforged and Systemd

最近要把自己的 Minecraft 伺服器架構從純 Docker 環境換掉,因為現有的 Docker Image 要安插 MCDReforged 有點困難(更何況我跟 Docker 還是不太熟),不過這樣一來要讓伺服器在電腦啟動時正常開關就變得有點困難,需要出動自己不太熟的 Systemd。

我在自己架設的 Memos 上有架構改變相關進度,可以去看看。如果全部打勾那就代表都做好了。

還是先建立 MCDReforged 環境再說

因為 Systemd 不怎麼熟讓我原地踏步一段時間,仔細想想還是先把自己能做的事情做好,建立 MCDReforged 環境還是我比較熟悉的工作,那就先從這裡開始。

要把 MCDReforged 的環境弄好就必須先要有 Python 環境。不過這邊不能用系統的 Python 環境,實際上,如果你在 Ubuntu 22.04 的環境下直接用 root 權限執行 pip install,會出現以下警告但它還是讓你安裝:

WARNING: Running pip as the ‘root’ user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv

如果你在 Debian 12 環境下則是一言不合直接拒絕安裝,直到你加上 –break-system-packages 這個參數:

error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.

If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.

If you wish to install a non-Debian packaged Python application,
it may be easiest to use pipx install xyz, which will manage a
virtual environment for you. Make sure you have pipx installed.

See /usr/share/doc/python3.11/README.venv for more information.

note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing –break-system-packages.
hint: See PEP 668 for the detailed specification.

所以這邊就創立虛擬環境就好。

$ python3 -m venv python3-venv

不過在執行 venv 之前,要先安裝相關的 venv 套件到系統當中(Ubuntu 22.04 為 python3.10-venv)才行。

然後就可以進入虛擬環境安裝 MCDReforged,並且建立 MCDReforged 的環境:

$ source ./python3-venv/bin/activate # 切換至虛擬環境
$ pip install mcdreforged #安裝 MCDReforged
$ python3 -m mcdreforged init #初始化 MCDR 環境

這可能對我來說是裡面最簡單的步驟了。

寫啟動腳本

為了方便維護,我會分成兩個腳本:

  • 啟動 Server 用的腳本,裡面包含各種 Java 參數以及伺服器啟動前需要做什麼,例如先啟動 Packwiz 進行模組包更新檢查等
  • MCDReforged 啟動腳本

通常會先啟動 MCDReforged ,然後再透過 MCDReforged 啟動 Server,這部分需要修改一下 MCDReforged 的設定檔案,將啟動指令指向腳本。

大概來說就是這一段:

# The console command to start the server. Examples:
start_command: ./run.sh

相關腳本也沒有很難寫,首先是啟動 MCDReforged 的 start.sh:

#!/bin/bash

../python3-venv/bin/python3 -m mcdreforged

再來是啟動伺服器本體的 run.sh:

#!/bin/bash

java -Xms1G -Xmx2G -Dfile.encoding=UTF-8 -jar run-fabric.jar nogui

這邊的 run.sh 還不是完全體,我之後會把它變得更好。

寫 Systemd  service unit 檔案

這邊我搞最久,因為 MCDReforged 本身的限制加上我沒搞懂 Systemd。

MCDReforged 需要正常的 Stdin/Stdout 環境,直接用 Systemd 啟動 MCDReforged 的話,會因為 EOF 錯誤導致啟動失敗,所以這邊要有一個可以讓 MCDReforged 掛在 Shell 底下又可以背景執行的環境。

於是我找到了 tmux,雖然網路上是教 screen 比較多,但個人比較熟 tmux,雖然也沒到多熟。

啟動思路很簡單,用 tmux 創立一個 new-session 並馬上 detach 這個 session,而這個 session 只用來啟動 MCDReforged。

至於怎麼停止伺服器,查了一下發現 tmux 有 send-keys 可以將 stop 指令送進去 session 裡面,不愧是神器。

之後就可以寫 Systemd service unit 了,不過寫了一下發現事情沒那麼簡單。

首先是 Service type 要用 oneshot 而非 simple,且還要搭配 RemainAfterExit,因為 tmux 建立 session 成功之後就馬上回傳 exit code,以 Systemd 的角度來看,程式已經結束了,然後就迅速把服務停止掉,所以 type 要使用 oneshot,至於 RemainAfterExit 一來是要讓 tmux 回傳 exit-code 之後還能夠運行,再來就是避免重複下 systemctl start 導致伺服器重複開啟的問題。

再來要注意權限問題,像是 User、Group 等要指定好,ExecStart、ExecStop也要寫好,最後就是WantedBy也要指定成 multi-user.target。

於是整個 Service unit 檔案寫好就變成這樣:

[Unit]
Description="Nesquate's Minecraft Server (Main)"

[Service]
User=nesquate
Group=nesquate
Type=oneshot
RemainAfterExit=yes
ExecStart=tmux new-session -d -s "mc-nesquate-main" /home/nesquate/minecraft-server/main/start.sh
ExecStop=tmux send-keys -t "mc-nesquate-main" stop ENTER
WorkingDirectory=/home/nesquate/minecraft-server/main

[Install]
WantedBy=multi-user.target

之後就可以把檔案複製到 /etc/systemd/system 底下,重新載入 systemd ,就可以順利啟動和停止服務了。

未完成待續

藉由這次研究,總算能夠讓 Minecraft Server 透過 Systemd 來啟動了,不過根據 Memo 我還有其他伺服器要一起處理,就把那些事情都處理完再來寫吧。

參考資料

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *