Minecraft server je vše, jen ne připraven na provoz na serveru. Samotný server lze spustit v příkazovém prostředí, ale není snadné ho provozovat na pozadí, protože administrativní příkazy očekává vkládané na stdin, nejlépe přímo z klávesnice.

Toto se často řeší tak, že se mc server uzavírá do samostatné tmux / screen session. A pomocí funkcí těchto prostředí se potom na stdin posílají jednotlivé příkazy. Výstup je obvykle ztracen.

Mě tento postup příliš nevyhovoval, potřeboval jsem mc server spouštět na pozadí s možností logovat jeho výstup a zachovat možnost posílat příkazy na stdin.

Systemd tento problém řeší, bohužel ne zcela uspokojivým způsobem. Systemd umožňuje tzv. socket activation kde systemd poslouchá na daném socketu (může se jednat o TCP nebo o UNIX socket) a jakmile něco přijde na vstup, tak teprve spustit service a daný socket předat danému procesu.

Ta druhá schopnost se nám bude velmi hodit, ale ta první je trochu nepřijemná, k tomu se dostanu na konci.

Požadavky

Shrňmě si tedy čeho chceme dosáhnout:

  • Korektně startovat a ukončit proces mc serveru
  • Možnost vidět a logovat výstup z procesu mc serveru
  • Možnost posílat na stdin příkazy

První bod je v případě unity .service splněn tak nějak automaticky.

Druhý bod vlastně také, systemd ukládá každý výstup na stdout a strerr do journálu. Tam lze prohlížet záznamy pomocí journalctl, v tomto případě se hodí journalctl -f -u mc a nechat vypisovat log průběžně.

Takže zbývá k řešení třetí bod. Potřebujeme ideálně FIFO, kam budeme posílat příkazy, třeba ve formě echo 'op user' > mc.socket a toto napojit na stdin procesu mc serveru.

Service

Nejprve potřebujeme definovat service. Takže např. /etc/systemd/system/tekkit.service:

[Unit]
Description=Minecraft Tekkit Server

[Service]
User=minecraft
Group=minecraft
WorkingDirectory=/home/minecraft/Tekkit/
Environment="JAVA_HOME=/usr/java"

ExecStart=/usr/java/bin/java -Xmx4G -Xms4G \
                             -XX:+UseConcMarkSweepGC \
                             -XX:+UseParNewGC \
                             -XX:+CMSIncrementalPacing \
                             -XX:ParallelGCThreads=4 \
                             -XX:+AggressiveOpts \
                             -jar Tekkit.jar nogui

StandardInput=socket
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

User, Group, Workdir a ExecStart jsou asi jasné, ale v této unitě jsou navíc definice Standard Input, Output a Error. stdin jsme napojili na socket (který budeme ještě definovat), stdout a stderr potom do journalu (což je default a zde to uvádím pro úplnost).

Socket

Soubor /etc/systemd/system/tekkit.socket (soubor se musí jmenovat stejně jako .service):

[Socket]
ListenFIFO=/home/minecraft/Tekkit/tekkit.socket

Aktivace

systemctl enable tekkit.socket
systemctl start tekkit.socket
systemctl start tekkit.service

A potom je možné posílat do socketu příkazy a mc je dostane na stdin.

echo "say hello" > /home/minecraft/Tekkit/tekkit.socket

A výpisy můžeme sledovat pomocí:

journalctl -u tekkit -f

Nevýhoda

Výše popsané řešení funguje, ovšem s jedním problémem.

Předávání socketu funguje pouze ve spojení se socket activation. V aktuální verzi systemd to nelze oddělit. Což má za následek to, že pokud je service vypnutá a někdo něco pošle do socketu, tak se service nahodí. No jenže to něco může vypadat i takto:

echo "stop" > /home/minecraft/Tekkit/tekkit.socket

Po tomto “vtipném” příkazu se spustí service, nastartuje se celá mašinerie tekkitu (což prostě trvá) a až bude tekkit při vědomí, přijme příkaz stop a opět se ukončí.

Chápu, že pro mnohé lidi to nemusí být problém a že mohou socket activation využít i rovnou ke spouštění této služby posláním neutrálního příkazu (třeba say). Ale já bych velmi ocenil, kdyby byla možnost předání socketu, ale bez aktivace.

I s touto drobností tento způsob spouštění mc serveru považuji za vhodnější, než ty běžné postupy s tmux apod.