cedriccubat.dev System Online
|
Retour au terminal
11 juillet 2026 Cédric

Mettre à jour un serveur Soulmask Dockerisé (et arrêter de le faire à la main)

#docker#homelab#sysadmin#automatisation#bash#powershell

Mettre à jour un serveur Soulmask Dockerisé (et arrêter de le faire à la main)

Petit retour terrain sur la mise à jour de mon serveur Soulmask auto-hébergé. Rien de spectaculaire, mais l'occasion de reparler d'une leçon classique en sysadmin : avant de mettre à jour quoi que ce soit, vérifie ce qui tourne réellement.

Le piège du départ : deux serveurs, un seul nom

Je voulais mettre à jour mon serveur Soulmask. Simple sur le papier. Sauf qu'en listant les conteneurs actifs :

docker ps

Surprise : deux conteneurs Soulmask tournaient en même temps, avec deux images différentes :

  • windrose-server — image indifferentbroccoli/windrose-server-docker, healthy depuis 7 jours
  • soulmask-server-dedicated-server-1 — image kagurazakanyaa/soulmask:latest, up depuis 5 jours

"Windrose" est en fait le nom de code interne du moteur derrière Soulmask — d'où la confusion. Mais un seul des deux exposait réellement les ports utilisés par les joueurs (8777/udp et 27015/udp).

Pour identifier lequel était le vrai serveur en prod, j'ai inspecté les labels Docker Compose du conteneur :

docker inspect soulmask-server-dedicated-server-1 --format '{{ .Config.Labels }}' | tr ',' '\n' | grep -i compose

Ça m'a donné le chemin exact du docker-compose.yml responsable : /home/cedric/soulmask-server/. Morale : sur un serveur perso qui accumule les projets au fil du temps, un docker ps régulier évite de perdre du temps à mettre à jour le mauvais conteneur — ou pire, à en oublier un qui tourne pour rien.

La mise à jour, en soi

Une fois le bon docker-compose.yml localisé, la procédure est classique :

cd /home/cedric/soulmask-server

# Sauvegarde manuelle avant toute manipulation
cp -r ./data ./data-backup-$(date +%Y%m%d)

# Récupération de la dernière image (sans impact sur le serveur en cours)
docker compose pull

# Recréation du conteneur avec la nouvelle image
docker compose up -d

# Suivi des logs pour valider le démarrage
docker compose logs -f dedicated-server

Point important à noter : docker compose pull ne coupe rien. Il télécharge l'image en arrière-plan pendant que le serveur continue de tourner. C'est seulement docker compose up -d qui recrée le conteneur — et donc coupe les joueurs connectés le temps du redémarrage (respecté ici par un stop_grace_period: 60s propre, défini dans le compose).

Autre point rassurant : mon docker-compose.yml montait déjà ./data:/opt/soulmask/WS/Saved, donc les sauvegardes du monde vivent en dehors du conteneur. Une mise à jour d'image ne touche jamais à ces données.

Lire les logs sans paniquer

Au redémarrage, la console crache une quantité impressionnante d'erreurs LogStreaming: Error — des dépendances manquantes type BinkMediaPlayer ou une police chinoise (SiYuanHeiTi). Ce sont des assets côté client (lecteur vidéo, police d'interface) que le serveur dédié n'a simplement pas besoin de charger. Elles apparaissent à chaque démarrage, mise à jour ou non — pas un signal d'alarme.

La ligne à surveiller pour confirmer qu'une mise à jour a bien pris :

LogNetVersion: Set ProjectVersion to 1.0.14.

Et pour valider que le serveur écoute bien après son (parfois long) temps de chargement initial :

docker ps                  # uptime stable, pas de restart en boucle
ss -uln | grep 8777        # le port UDP doit apparaître en écoute

Automatiser la corvée

Faire ces 4-5 commandes à la main à chaque mise à jour, ça va deux minutes — jusqu'au jour où on oublie une étape ou qu'on met à jour le mauvais conteneur (cf. plus haut). J'ai donc scripté tout ça en deux couches :

1. Un script bash côté serveur (update-soulmask.sh) qui fait, dans l'ordre : sauvegarde datée, pull, up, prune des vieilles images, puis bascule sur les logs en direct.

#!/bin/bash
set -e

SOULMASK_DIR="/home/cedric/soulmask-server"
BACKUP_DIR="$SOULMASK_DIR/data-backup-$(date +%Y%m%d-%H%M%S)"

cd "$SOULMASK_DIR"
cp -r ./data "$BACKUP_DIR"
docker compose pull
docker compose up -d
docker image prune -f
docker compose logs -f dedicated-server

Le set -e en tête de script est le détail qui compte : si une étape échoue (échec du pull réseau, par exemple), le script s'arrête net au lieu d'enchaîner aveuglément sur un up -d avec une image potentiellement corrompue.

2. Un wrapper PowerShell côté poste Windows (Update-Soulmask.ps1), pour ne pas avoir à ouvrir une session SSH manuellement à chaque fois. Il envoie le script sur le serveur via scp, puis l'exécute à distance via ssh :

$ServerIP     = "192.168.1.46"
$SshUser      = "cedric"
$RemoteScript = "/home/cedric/soulmask-server/update-soulmask.sh"

scp $LocalScript "${SshUser}@${ServerIP}:${RemoteScript}"
ssh "${SshUser}@${ServerIP}" "chmod +x $RemoteScript && $RemoteScript"

Résultat : une mise à jour complète (avec sauvegarde) se lance désormais en une commande depuis mon poste :

.\Update-Soulmask.ps1

Prochaine étape

La suite logique serait de virer l'authentification par mot de passe SSH au profit d'une clé dédiée (pour ne plus taper de passphrase deux fois par exécution), et éventuellement de planifier une vérification automatique de version pour ne lancer le script que si une mise à jour est réellement disponible côté Steam. À creuser dans un prochain article.

En attendant : un docker ps de temps en temps sur un serveur perso, ça évite bien des surprises.

© 2026 cedriccubat.dev - All rights reserved. Made in terminal.