Labels WebUI, macvlan et docker stop récalcitrant : les pièges Docker sous Unraid
Une tâche qui avait l’air anodine — “ajoute le lien WebUI à quelques conteneurs qui n’en ont pas” — s’est transformée en visite guidée de trois pièges Docker différents. Voici ce que j’ai appris.
Le problème de départ : des conteneurs sans WebUI
Sur Unraid, le lien “WebUI” qui apparaît sous chaque conteneur vient d’un label Docker : net.unraid.docker.webui. Sauf que ce label ne peut être défini qu’à la création du conteneur — impossible de l’ajouter à un conteneur déjà lancé avec un simple docker update.
J’avais repéré une bonne demi-douzaine de conteneurs sans ce label — pas créés via le formulaire “Add Container” d’Unraid, donc pas de label, pas de lien. La seule solution : recréer chaque conteneur, à l’identique, avec le label en plus.
Reconstruire un docker run à partir d’un conteneur existant
Pas question de deviner la config à la main. J’ai utilisé runlike (assaflavie/runlike), un petit outil qui inspecte un conteneur et recrache la commande docker run équivalente :
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock assaflavie/runlike nom_du_conteneur
Précieux, mais pas parfait : sur les conteneurs en réseau macvlan (Unraid br0), runlike n’affiche pas l’IP statique. Elle est bien configurée (visible dans docker inspect sous IPAMConfig.IPv4Address), mais runlike l’oublie. Sans ce détail, recréer le conteneur lui aurait donné une IP différente — cassant tout ce qui la référence ailleurs (reverse proxy, DNS interne…).
Leçon : ne jamais faire confiance aveuglément à un outil de reconstruction de commande. Toujours croiser avec docker inspect pour les détails réseau.
Le piège macvlan + port publié : searxng cassé
Pour la plupart des conteneurs, la recréation (stop → rename → run avec le label en plus → suppression de l’ancien) s’est bien passée. Un seul a mal tourné : searxng, qui a la particularité d’être sur deux réseaux — le bridge par défaut (avec un port publié -p 8102:8080) et macvlan br0 (attaché après coup via docker network connect).
Après recréation, plus aucun accès sur le port 8102 depuis l’hôte. Le conteneur tournait, écoutait bien en interne (ss -ltn le confirmait dans le conteneur), mais rien ne passait de l’extérieur. En creusant docker inspect, le port-mapping n’était tout simplement plus actif (NetworkSettings.Ports vide) malgré une config correcte dans HostConfig.PortBindings.
J’ai testé dans l’ordre docker create → docker network connect → docker start (au lieu de docker run direct) : même résultat. Le souci n’était pas l’ordre des opérations mais une vraie incompatibilité entre le proxy de port de Docker et l’attachement d’un second réseau macvlan sur ce setup.
Solution finale : rollback pur et simple vers le conteneur d’origine (jamais supprimé, juste renommé pendant l’opération — heureusement). Testé sur le conteneur original non modifié : même symptôme. Donc pas un bug que j’ai introduit, un vrai piège de la stack réseau Docker+Unraid sur ce genre de topologie. Parfois la bonne réponse est de ne pas insister et de laisser le conteneur tel quel.
Le docker stop qui ne s’arrête jamais
Le deuxième conteneur à donner du fil à retordre : Immich, qui bundle Postgres + Redis + API + ML dans un seul conteneur via supervisord.
Au moment de le recréer, docker stop a échoué avec :
Error response from daemon: cannot stop container: Immich: tried to kill container, but did not receive an exit event
Le conteneur continuait de tourner malgré la commande. En creusant les logs, le SIGTERM était bien reçu, mais supervisord attendait patiemment que postgres, redis, l’API et le service ML s’arrêtent tous proprement — un par un — avant de rendre la main. Sur un conteneur qui bundle plusieurs services lourds, le délai de grâce par défaut de Docker (10s) est juste trop court.
Résultat en cascade : j’ai relancé le conteneur pendant que l’ancien processus finissait de mourir en arrière-plan, provoqué un état confus (deux instances qui se marchent dessus brièvement), et Postgres a dû faire une récupération après crash (WAL replay) au redémarrage suivant — sans casse heureusement, juste un redémarrage plus lent que d’habitude.
Leçon : pour un conteneur qui bundle plusieurs process via supervisord, docker stop --time 60 (ou plus) est bien plus sûr que le timeout par défaut. Et surtout : ne jamais relancer un conteneur tant qu’on n’est pas certain que l’ancien processus est complètement mort (docker ps -a doit montrer Exited, pas juste “la commande stop a retourné”).
Ce que j’ai appris
net.unraid.docker.webuine se rajoute qu’à la création — pas de retour en arrière sur un conteneur déjà lancé, il faut le recréer- runlike est utile mais incomplet — toujours vérifier l’IP statique macvlan à la main via
docker inspect - macvlan + port bridge publié, ça ne fait pas toujours bon ménage — si un conteneur fonctionne déjà comme ça, mieux vaut ne pas le toucher que de risquer de casser le port-forwarding
docker stopsur un conteneur multi-process peut mentir — le process peut continuer à tourner après l’échec apparent de la commande ; toujours vérifier l’état réel avant d’agir- Savoir reculer — sur 7 conteneurs à migrer, 5 se sont bien passés, 2 ont posé problème. Le bon réflexe a été de rollback proprement sur les 2 plutôt que de s’acharner à tout prix
Et toi, tu as déjà eu un docker stop qui refuse de coopérer ?