Guide d’administration système

Comment est-ce que tout cela fonctionne, sous le capot ?

Salut, Administrateur⋅trice ! Cette page servira de guide à l’usage des différentes commandes et scripts qui permettent de faire tourner Zcraft.

Ce guide est destiné aux personnes ayant un accès au serveur de production.
Si ce n’est pas votre cas, vous pouvez toujours lire ce qui suit par curiosité, mais vous ne pourrez rien appliquer vous-même. Cela dit, vous pouvez toujours demander à un(e) administrateur(trice) de le faire pour vous, s’il ou elle le juge pertinent.

Écosystème

À l’heure actuelle, Zcraft tourne sur une seule machine de Scaleway, sous FreeBSD, avec 8 Gio de RAM. La même machine fait tourner tous les services de Zcraft que l’on héberge nous-même :

Occasionnellement, d’autres services peuvent être hébergés sur la machine, avec parcimonie car les ressources sont limitées.

Il y a une exception : le service status.zcraft.fr n’est pas hébergé sur la même machine, afin de rester disponible même en cas de coupure totale. Il est également disponible via un autre nom de domaine, en cas de coupure de ce dernier : zcraft-status.carrade.eu.

Accès

L’accès à la machine se fait via SSH. Les administrateurs ont la capacité de donner un accès supplémentaire, éventuellement limité.

Serveurs Minecraft

Toutes les opérations concernant le serveur Minecraft doivent être fait en tant qu’utilisateur pablo. Une session de tmux tourne, afin de persister tous les terminaux des divers serveurs. Pour ouvrir les terminaux dédiés à Minecraft, le plus simple si vous avez un accès au compte, est d’exécuter la commande suivante, qui vous permettra d’y entrer instantanément.

sudo -u pablo tmux a
Attention
Les scripts de démarrage et de commande de serveurs Minecraft doivent être exécutés depuis le dossier ~/minecraft de l’utilisateur pablo. Vous pouvez taper la commande ci-dessous depuis tmux pour être sûr⋅e.

cd ~/minecraft

Dans tmux, nous utilisons généralement une fenêtre par serveur, et chaque fenêtre est divisée en deux, avec un terminal pour la console du serveur en haut, et un pour l’usage général associé en dessous. Si tout cela n’est pas clair pour vous, continuez de lire.

Utilisation de tmux

Comme tout le monde n’est pas forcément familier de tmux, voici un rappel ou un mini-tutoriel afin que vous puissiez vous en servir.

Tmux est un émulateur de terminal persistant, c’est à dire que si vous quittez le serveur, les terminaux resteront actif. Il est multi-utilisateur, dans le sens où plusieurs personnes peuvent être connectées à la même session tmux ; elles verront alors toutes la même chose (y compris ce que vous écrivez, par exemple — exactement la même chose).

On utilise tmux comme un terminal standard ; les commandes sont les mêmes. Il y a en plus de ça des raccourcis clavier spécifiques à tmux qui permettent de le contrôler : créer des fenêtres, diviser les fenêtres en plusieurs terminaux, etc.

Vocabulaire de tmux

Afin d’y voir plus clair, voici une explication des différents concepts de tmux.

Contrôler tmux

Pour exécuter une commande tmux, vous devez systématiquement taper Ctrl + B, suivi d’un caractère représentant la commande souhaitée. Voici un récapitulatif rapide des commandes les plus courantes.

Ctrl+B puis c
Créé une nouvelle fenêtre (window).
Ctrl+B puis n
Passe à la fenêtre suivante (n comme next).
Ctrl+B puis p
Passe à la fenêtre précédente (p comme prevous).
Ctrl+B puis ← ↑ → ↓
Changer le pan actif en allant vers celui dans la direction de la flèche (↑ pour aller vers celui du haut, par exemple).
Ctrl+B puis %
Diviser le pan actuel en deux, verticalement.
Ctrl+B puis "
Diviser le pan actuel en deux, horizontalement.
Ctrl+B puis Ctrl + ← ↑ → ↓
Redimentionne le pan actif dans la direction de la flèche.
Ctrl+B puis x
Ferme le pan actif (et le terminal associé). Attention à ne pas le faire depuis un pan contenant la console d’un serveur actif ! Une confirmation sera demandée.

Vous remarquerez que vous ne pouvez pas défiler dans tmux (sauf parfois le pan du haut). Pour pouvoir remonter dans un terminal, il vous faut entrer en copy mode. Ce mode permet aussi de faire une recherche (si vous connaissez Vim, vous ne serez pas dépaysé).

Ctrl+B puis crochet ouvrant
Entrer en mode copie.
↑ ↓
Se déplacer dans l’historique.
/
Faire une recherche.
%
Faire une recherche dans l’autre sens.
n
Dans le cadre d’une recherche, aller au prochain résultat.
N
Dans le cadre d’une recherche, aller au précédent résultat.
q
Quitter le mode copie.

Vous pouvez retrouver ces raccourcis et d’autres depuis tmux, en exécutant Ctrl+B puis ?.

Utilisation de screen

screen est un autre utilitaire que nous utilisons pour maintenir un terminal ouvert. Nous l’utilisons uniquement pour les terminaux qui contiennent les consoles des serveurs Minecraft actifs, car cela permet de pouvoir envoyer des commandes automatiquement à tous les serveurs (on en parle plus bas).

La seule chose qu’il faut savoir, c’est que screen a le même problème de défilement dans l’historique que tmux. Mais heureusement, ce problème se résout quasiment de la même façon : screen utilise le même concept de raccourci clavier pour entrer des commandes, la seule différence étant que ce raccourci est Ctrl + A, au lieu de Ctrl + B.

Sinon c’est pareil, donc faites Ctrl + A puis [ pour entrer en mode copie (qui permet de défiler) et utilisez les flèches pour défiler. Seule différence ; il faut utiliser Échap pour quitter le mode, et il n’y a pas de fonctionnalités de recherche.

Cycle de vie d’un serveur

Pour gérer les serveurs Minecraft, un script a été écrit qui permet de les installer, démarrer et redémarrer automatiquement (en cas de crash par exemple), ainsi que de les contrôler de façon centralisée.

Démarrage ou installation

Chacun des serveurs réside dans un sous-dossier du dossier ~/minecraft. Pour démarrer un serveur, depuis tmux, exécutez la commande suivante.

./boot_server.sh nom-du-serveur 1.16.3 1024

Les arguments sont, dans l’ordre :

  1. le nom du dossier dans lequel réside le serveur (si le dossier n’existe pas, il sera créé et un nouveau serveur sera initialisé avec les réglages par défaut) ;
  2. la version de Minecraft souhaitée (sous la forme d’une version numérique sans préfixe — pour connaître les versions acceptées, exécutez la commande ./boot_server.sh sans argument) ;
  3. la quantité de RAM à allouer au serveur (en Mio).

Cette commande va :

En plus de tout cela, si le serveur s’arrête (par exemple en cas de plantage), il sera redémarré automatiquement.

Comme le serveur est créé s’il n’existe pas déjà, il est facile d’initialiser un nouveau serveur — n’oubliez pas de changer son port dans son fichier server.properties, sinon il n’arrivera pas à démarrer. Vous aurez peut-être à autoriser le port au niveau du pare-feu ; les ports 25565 et 25566 fonctionneront toujours.

Le serveur principal s’appelle main.

Faites attention à la RAM

La machine ne dispose que de 8 Gio de RAM en tout, et Minecraft ne peut se permettre de tout utiliser. En lançant un serveur, prenez en considération la quantité de mémoire vive déjà allouée par d’autres serveurs, et laissez au moins 2,5 Gio de mémoire vive au reste du système.

Si vous demandez l’allocation de trop de mémoire vive, un des serveurs risque d’être tué par le système d’exploitation au bout d’un moment.

N’hésitez pas à temporairement diminuer la quantité de mémoire allouée au serveur principal si besoin (par exemple, pendant un événement).

Redémarrage

Pour redémarrer le serveur, exécutez la commande stop (ou /stop depuis le jeu). Le serveur redémarrera automatiquement après quelques secondes.

Arrêt

Pour arrêter le serveur, exécutez la commande stop puis dans tmux, lorsque l’opportunité vous est présentée, appuyez sur Ctrl + C puis sur Ctrl + D, tel que précisé. Vous avez quelques secondes pour ce faire avant que le serveur ne redémarre automatiquement.

Quand vous voyez ce message, vous avez l’opportunité d’annuler le redémarrage du serveur.

Il n’est pas possible d’arrêter définitivement un serveur depuis le jeu.

Changement de version de Minecraft

Pour mettre à jour un serveur, arrêtez-le complètement, puis relancez-le en précisant la nouvelle version à utiliser en paramètre de la commande du script plus haut. La nouvelle version du serveur sera automatiquement téléchargée et remplacera l’ancienne.

Notez que si la mise à jour du serveur lui-même est automatiquement gérée, ce n’est pas le cas de celle des éventuels plugins.

Diffusion centralisée sur tous les serveurs

Diffuser une commande

Pour envoyer la même commande Minecraft sur tous les serveurs actifs, exécutez le script suivant. Le script s’exécute silencieusement mais transmet bien la commande, qui est exécutée par chacun des serveurs.

./broadcast_command.sh <commande>

Par exemple, avec la console du serveur en haut et un terminal en bas :

Et pouf !

Cette commande est utilisée en interne pour toutes les autres qui vont suivre, et aussi pour redémarrer automatiquement tous les serveurs à cinq heures du matin (en envoyant la commande stop, précédée d’une commande permettant d’expulser tout le monde avec un message d’expulsion adapté), et pour diffuser l’heure.

Diffuser un message

Le cas de la diffusion d’un message étant plutôt courant, il existe une commande qui va s’en charger, en affichant avec un préfixe et en isolant le message entre deux lignes vides.

./broadcast.sh <message>

Vous pouvez utiliser les codes de formatage de Minecraft (avec §).

La commande (en bas) et son effet dans la console (au milieu, les trois tellraw) et en jeu (en haut).

Si vous voulez diffuser un message brut, mais tout de même profiter du préfixe, de la séparation, etc., utilisez à la place cette commande.

./broadcast_rawtext.sh <message en JSON>

Vous devez lui donner un message au format enrichi de Minecraft (en JSON, aussi appelé « format tellraw »). Certains sites peuvent le générer, mais il ne faut envoyer que le JSON, pas la commande avant.

Veuillez noter que les shell n’aiment pas forcément toutes ces accolades et guillemets. Pour être sûr que la commande passe bien, mettez le JSON entre guillemets simples, comme dans l’exemple ci-dessous (et n’oubliez pas d’échapper d’éventuels accents dans votre texte en les préfixant d’un anti-slash).

La commande (en bas) et son effet dans la console (au milieu) et en jeu (en haut, la souris étant sur le texte).

Si vous ne voulez que diffuser un message brut, sans le préfixe ni rien, utilisez broadcast_command.sh vu plus haut, avec la commande say ou tellraw @a, selon les besoins.

Si personne n’est connecté au serveur, les commandes de diffusion de message causeront des erreurs dans la console (trois fois « No player was found »). C’est totalement bénin, vous pouvez l’ignorer.

Autres scripts de gestion du serveur

Il existe d’autres scripts mais leur exécution est totalement automatisée — vous n’avez donc pas à vous en soucier, sauf en cas de problème éventuel. Voici malgré tout une petite description.

Si vous voulez connaître leur fonctionnement, affichez simplement leur contenu. Vous n’avez pas d’accès au serveur mais vous êtes tout de même curieux⋅se ? Contactez un administrateur 😉 .

Diffusion de l’heure

Exécuter le script suivant diffuse l’heure sur tous les serveurs. Il est appelé automatiquement toutes les heures par un cron.

./broadcast_time.sh
Il est une heure.

L’heure affichée est celle du serveur, à savoir celle de la France métropolitaine, au format 24 heures.

Ce script récupère également la liste des personnes connectées en vocal sur Discord, via l’API du widget. S’il y en a, une phrase en gris est ajoutée au message indiquant combien de membres sont là ; survoler cette phrase précise lesquels.

Redémarrage quotidien

Tous les jours à cinq heures, le serveur est redémarré. Plutôt qu’une simple commande stop diffusée à tous les serveurs, le script suivant est exécuté par un cron, un quart d’heure avant l’heure.

./reboot_server.sh

Il va prévenir un quart d’heure, cinq minutes, et quarante secondes avant, que le serveur va redémarrer ; puis va expulser les joueurs avec un message explicatif avant de couper le serveur.

Ce script va donc mettre un quart d’heure à s’exécuter (car il attend entre chaque avertissement).

Pour expulser les joueurs, le script va d’abord envoyer la commande kick-all-for-reboot, et ensuite exécuter une commande kick @a avec un message standard. La raison est simple : il n’est pas possible d’envoyer des commandes d’expulsion avec des retours à la ligne depuis la console (\n est ignoré) ; mais ça l’est depuis un alias. Le second kick sert de solution de repli au cas où l’un des serveurs ne possède pas l’alias.

Il est donc recommandé de définir cet alias dans le fichier commands.yml.

aliases:
  kick-all-for-reboot:
  - |-
    kick @a §aVous avez été expulsé⋅e car le serveur a redémarré.

    §7Le serveur redémarre automatiquement chaque nuit afin de se mettre à jour et d'éviter des problèmes de performances. Vous pourrez vous reconnecter dans une minute ou deux.
Le message d’avertissement diffusé un quart d’heure avant le redémarrage. Pour des raisons de sommeil (je n’ai pas veillé jusqu’à quatre heures quarante-cinq du matin juste pour faire cette capture d’écran), ceci est une simulation.
Le message d’explication affiché aux joueurs qui étaient toujours connectés aussi tard (on salut les farmers et les canadiens).
Export et sauvegarde des cartes

Les cartes sont exportées chaque nuit pour servir de sauvegarde, et aussi pour que quiconque puisse les télécharger. Ce script est exécuté par un cron à cinq heures trente.

./export_V5.sh

Il va :

Utilitaires de manipulation des cartes

Parfois, il est nécessaire de manipuler des cartes Minecraft, par exemple pour supprimer des chunks afin de les régénérer, ou pour en importer. Il y a plusieurs solutions connues pour ça, mais elles ont des usages spécifiques.

Générer une carte avec WorldBorder

Pour générer complètement une carte avec WorldBorder, suivez les instructions suivantes.

  1. Configurez la bordure du monde afin qu’elle ait la taille finale désirée.

    /wb set radiusX radiusZ centerX centerZ
    – ou –
    /wb set radiusX radiusZ spawn

    Depuis la console, vous devez spécifier le monde à modifier : /wb world set ….

  2. Demandez la génération du monde. Les arguments sont les suivants.
    Le nombre de chunks générés par seconde — cette valeur sera maximisée par la capacité du serveur, donc mettre un très grand nombre revient à dire « le plus possible ». Pour une génération sur un serveur avec des joueurs actifs, il vaut mieux être plus raisonnable afin que les joueurs ne ressentent pas de pertes de performances.
    Le nombre de chunks à générer derrière la bordure — si vous l’omettez, ce sera 208 (afin de couvrir la distance de rendu typique).

    /wb fill 10000 0

    De même, spécifiez le monde à générer depuis la console : /wb world fill ….

  3. Confirmez et attendez (potentiellement longtemps). WorldBorder vous donnera une estimation de l’avancement.

    /wb fill confirm
  4. Une fois la génération terminée, il est recommandé de re-générer la dynmap — sa totalité ou la zone générée — à l’aide de /dynmap radiusrender ou de /dynmap fullrender.

Pour plus de détails, consultez l’aide des commandes utilisées :

Manipuler la carte avec MCA Selector

MCA Selector est un logiciel écrit en Java et qui peut s’appeler en ligne de commande (headless mode), ce qui est pratique dans notre cas car ça évite d’avoir à télécharger la carte localement pour travailler dessus.

Sur Zcraft, il est installé dans le dossier ~/minecraft de l’utilisateur pablo — tout comme les scripts mentionnés plus haut. Assurez-vous d’y être, sinon les commandes plus bas ne fonctionneront pas telles quelles. Dans le doute, exécutez ceci depuis tmux.

cd ~/minecraft

Ensuite, il suffira d’appeler MCA Selector comme suit.

java -jar mcaselector.jar [arguments…]

La documentation de MCA Selector est disponible ici (pour le mode headless) — dans le doute, référez-vous y. Ci-dessous, vous trouverez des notes complétant la documentation, ainsi que quelques exemples de manipulations courantes.

La lecture de la première partie de la documentation (dédiée au mode graphique) peut être utile pour mieux saisir les concepts utilisés.

Préciser quelle carte on modifie

Pour toutes les commandes ci-dessous, vous devez préciser quelle carte doit être altérée. Il faut pour ce faire passer un argument indiquant le dossier des régions (pas le dossier du monde ! sinon ça ne fonctionnera pas). Par exemple, pour V5, il faudra faire comme suit.

java -jar mcaselector.jar --world main/V5/region/

Notez le /region/ à la fin.

Filtrer les chunks que l’on modifie

MCA Selector permet de spécifier quels chunks seront traités par la commande (pour les supprimer, les exporter…). Vous devez utiliser l’option --query pour cela.

La syntaxe des filtres est documentée ici. Ce qu’il est important de savoir, c’est que les coordonnées indiquées (xPos, zPos) sont les coordonnées des chunks et non des blocs.

Vous pouvez trouver les coordonnées des chunks en jeu dans l’écran de débogage (F3), ou bien prendre les coordonnées d’un bloc dans le chunk, les diviser par 16, puis arrondir à l’entier inférieur.

Les coordonnées des blocs (préfixées par XYZ: et par Block:) et du chunk (préffixées par Chunk:) dans l'écran de débogage.
Les coordonnées du chunk sont affichées après Chunk: … in x y z. Ici, les coordonnées sont x = 257 et z = -873.

Le filtrage se fait en écrivant des tests sur des variables représentant les chunks. Voici d’abord les variables et les opérateurs ; puis quelques exemples.

Variables
xPos
La coordonnée X du chunk (pas du bloc !) (axe est-ouest)
zPos
La coordonnée Z du chunk (axe sud-nord)
InhabitedTime
La durée cumulée de présence de joueurs dans ce chunk (en ticks). S’il y a plusieurs joueurs dans un chunk, la valeur augmente plus vite. Si 0, le chunk n’a jamais été visité.
LastUpdate
Le tick du dernier enregistrement du chunk.
LightPopulated
1 si la lumière est générée dans le chunk ; 0 si elle ne l’est pas.
Palette
Les blocs dans ce chunk. Pour filtrer, contient une liste de blocs qui doivent, ou ne doivent pas, être dans ce chunk.
Biome
Les biomes dans ce chunk. Pour filtrer, contient une liste de biomes qui doivent, ou ne doivent pas, être dans ce chunk.
Entities
Les entités dans ce chunk. Pour filtrer, contient une liste d’entités qui doivent, ou ne doivent pas, être dans ce chunk.
#Entities
Le nombre d’entités dans ce chunk.
#TileEntities
Le nombre de tile entities dans de chunk.

Liste non-exhaustive. Vous pourrez trouver des détails sur ces variables sur la documentation du format Anvil (cherchez les mots-clefs).

Opérateurs
>
Strictement supérieur à
>=
Supérieur ou égal à
<
Strictement inférieur à
<=
Inférieur ou égal à
=
Égal à
!=
Différent de
contains
Contient, suivi d’une liste d’éléments séparés par des virgules (pour Palette, Biome ou Entities).
!contains
Ne contient pas (même usage que contains).

Vous pouvez également combiner des propositions logiques avec and ou or, et utiliser des parenthèses pour faire des groupes logiques. Vous trouverez des exemples plus bas.

Exemples
--query "xPos = 42 and zPos = 69"

Sélectionne le chunk aux coordonnées 42 ; 69.

--query "zPos <= -842"

Sélectionne tous les chunks au nord de ceux à la coordonnée -842 (donc les blocs au nord de Z = -13 472).

--query "InhabitedTime = 0 and xPos >= 230 and Palette contains diamond or Palette contains dirt"

Sélectionne les chunks qui n’ont jamais été visités, à l’est de la coordonnée 230 (donc les blocs à l’est de X = 3 680), et qui contiennent du diamant ou de l’émeraude.

--query "xPos > 12 and xPos < 21 and zPos > -4 and zPos < 2"

Sélectionne un rectangle de chunks entre les coordonnées notées, ce qui correspond, en coordonnées de blocs, à X entre 192 et 252, et Z entre -64 et 32.

Stocker une sélection dans un fichier

Pour persister une sélection, utilisez le --mode select. Vous pouvez alors sélectionner comme ci-dessus avec --query, mais aussi ajouter –radius pour sélectionner des chunks en plus autour de chaque zone. Attention, le rayon est carré.

Utilisez --output pour spécifier dans quel fichier stocker la sélection.

java -jar mcaselector.jar --world main/V5/region/ --mode select --query "zPos <= -842" --output "new-area.csv"

Stocke une sélection de la région du monde ajoutée en 2020 à Vessinque dans un fichier new-area.csv.

Supprimer des chunks

Pour supprimer des chunks, utilisez le --mode delete, et filtrez les chunks à supprimer comme précisé ci-dessus, avec --query. Vous pouvez utiliser --input pour utiliser une sélection depuis un fichier.

Attention – ces actions sont destructives et ne peuvent être annulées. Vérifiez bien la sélection avant d’exécuter la commande. Si vous avez un doute, exportez d’abord la sélection dans un fichier et inspectez-le (c’est un simple fichier texte), et/ou faites une sauvegarde du dossier region de la carte.

java -jar mcaselector.jar --world main/V5/region/ --mode delete --query "(zPos < -1400 or zPos > 300) and (xPos < -400 or xPos > 400)"

Supprime les chunks hors d’une régrion de la carte (Z trop grand ou trop petit pour être dedans ; et X trop grand ou trop petit). Ici, toute la carte rentre dans le périmètre conservé, par sûreté (mais dans le doute, n’exécutez pas cette commande !).

java -jar mcaselector.jar --world main/V5/region/ --mode delete --query "xPos > 1400 and xPos < 1410 and zPos > -1400 and zPos < -1410"

Supprime un carré de 10×10 chunks du monde.

Exporter des chunks

Vous pouvez exporter des chunks dans un dossier avec --mode export. Indiquez le dossier dans lequel exporter avec --output (il doit être vide). Choisissez quels chunks exporter avec --query ou --input.

Il est également possible d’exporter depuis chez vous avec le client graphique de MCA Selector, ce qui permet de modifier des bouts de la carte sans tout transférer et sans avoir à fermer le serveur.

Importer des chunks

Vous pouvez importer des chunks depuis un export avec --mode import. Il y a un peu plus de paramètres ; en voici le détail.

--input <dossier>
Le dossier duquel importer les chunks, où ils ont été précédemment exportés.
--offset-x <nombre>
Le décalage à appliquer selon l’axe des x par rapport aux coordonnées d’origine des chunks exportés. Ne pas le renseigner importera les chunks au même endroit.
--offset-z <nombre>
Le décalage à appliquer selon l’axe des z par rapport aux coordonnées d’origine des chunks exportés. Ne pas le renseigner importera les chunks au même endroit.
--selection <fichier_de_sélection>
Si spécifié, l’import sera fait uniquement dans la zone spécifiée par la sélection donnée.
--overwrite <true/false>
Si true, les chunks existant seront écrasés par ceux importés. Par défaut, false, donc pour mettre à jour des chunks depuis un import, il est nécessaire de préciser cet argument.

L’usage le plus typique (à savoir, importer des chunks exportés de la même carte, au même endroit, en écrasant les chunks existant pour les mettre à jour) serait le suivant.

java -jar mcaselector.jar --world main/V5/region/ --mode import --input folder --overwrite true
Autres modes

Les autres modes ne sont pas documentés ici. Référez-vous à la documentation officielle.

Pare-feu

Le serveur est protégé par un pare-feu, à savoir pf. Par défaut, tous les ports sont fermés sauf exceptions.

Si vous avez besoin d’ouvrir un port, suivez les instructions suivantes (vous devez être root — devenez-le avec sudo su si vous avez les droits nécessaires).

  1. Ouvrez le fichier /etc/pf.conf.

    nano /etc/pf.conf
  2. Repérez les premières lignes, qui contiennent la liste des ports ouverts pour TCP et UDP respectivement. Ajoutez-y votre port, en vous assurant de le séparer des autres par une virgule.

    tcp_services = "{ … }"
    udp_services = "{ … }"
  3. Rechargez pf.

    pfctl -f /etc/pf.conf