Diagnostic en cas d’alerte

Cette page liste, pour chaque alerte, les commandes à lancer pour identifier la cause. Pour un premier diagnostic global, commencez par Faire un état des lieux rapide.

Cette section liste, pour chaque alerte, les commandes à lancer pour identifier la cause. Elles sont à exécuter en root sur un manager du cluster concerné, sauf mention contraire.

Boîte à outils commune

# État global
docker node ls
docker service ls

# Historique des tâches d'un service, avec le message d'erreur complet
docker service ps reemo_portal --no-trunc

# Configuration et état de la dernière mise à jour
docker service inspect reemo_portal --pretty
docker service inspect reemo_portal --format '{{json .UpdateStatus}}'

# Conteneurs du nœud local et état du healthcheck Docker
docker ps -a --filter name=reemo_portal
docker inspect --format '{{json .State.Health}}' <ID_CONTENEUR>

# Événements récents (redémarrages, échecs de healthcheck, OOM…)
docker events --since 30m --until 0s --filter type=container

# Ressources du nœud
df -h /var/lib/docker /opt
free -m
dmesg -T | grep -i -E 'oom|killed process'

Journaux : les services journalisent en syslog avec le tag <INSTANCE_NAME>_<service>. Il faut les lire sur le nœud qui exécute le conteneur (colonne NODE de docker service ps) :

journalctl -t reemo_portal --since "1 hour ago"
# ou, selon la configuration rsyslog :
grep reemo_portal /var/log/syslog      # Debian / Ubuntu
grep reemo_portal /var/log/messages    # RedHat / Rocky

# Docker >= 20.10 garde aussi un cache local des journaux :
docker logs --tail 200 <ID_CONTENEUR>

Actions correctives courantes :

# Redémarrer un service (recrée ses conteneurs)
docker service update --force reemo_portal

# Revenir à la version précédente après une mise à jour ratée
docker service rollback reemo_portal

# Redéployer un composant avec le rôle Ansible (depuis le poste d'administration)
ansible-playbook -i <inventaire> <playbook> --limit <groupe> --tags portal

Messages d’erreur fréquents dans docker service ps --no-trunc :

Message

Cause probable

no suitable node

Contrainte de placement impossible : nœud indisponible, label manquant, replicas_max_per_node atteint, ou ressources insuffisantes.

secret not found

Secret Docker absent : relancer le rôle avec le tag secrets (ou secrets_turn, traefik…).

No such image / manifest unknown

Image absente du registre ou non chargée (mode offline : relancer avec --tags load_image).

port is already in use / address already in use

Un autre processus (nginx, ancien conteneur) occupe le port publié : ss -lntup | grep <port>.

task: non-zero exit (1) puis redémarrages en boucle

Le conteneur démarre puis plante : consulter ses journaux.

unhealthy container

Le healthcheck Docker échoue : le service n’écoute pas sur son port interne. Consulter ses journaux.

Alerte : nœud Swarm KO

docker node ls
docker node inspect <NOEUD> --pretty          # état, raison, adresse
# sur le nœud concerné :
systemctl status docker
journalctl -u docker --since "1 hour ago"
docker info | sed -n '/Swarm/,/Node Address/p'
timedatectl                                   # décalage d'horloge ?

Points à vérifier :

  • le démon Docker tourne sur le nœud ;

  • les flux Swarm entre nœuds sont ouverts : 2377/tcp, 7946/tcp+udp et 4789/udp (ou SWARM_DATA_PATH_PORT). Test : nc -vz <autre_noeud> 2377 ;

  • quorum des managers : avec 3 managers, la perte de 2 d’entre eux bloque le cluster. Ne retirez jamais un manager sans avoir vérifié le quorum.

Alerte : service Swarm incomplet (réplicas x/y)

docker service ps <SERVICE> --no-trunc | head -20
docker service inspect <SERVICE> --format '{{json .Spec.TaskTemplate.Placement}}'
# sur le nœud indiqué dans la colonne NODE :
journalctl -t <SERVICE> --since "30 min ago"

Cas particuliers :

  • <INSTANCE_NAME>_db / <INSTANCE_NAME>_logapidb à 0/1 : état normal pour ces tâches uniques de mise à jour des bases. Une alerte n’est justifiée que si leur dernière exécution est en échec (Failed). Consultez alors journalctl -t reemo_db (ou reemo_logapidb) sur le nœud qui l’a exécutée, puis relancez le déploiement avec --tags db (ou logapidb).

  • <INSTANCE_NAME>_mysqlbackup : ancien système de sauvegarde, à ignorer.

Reportez-vous au tableau des messages d’erreur fréquents de Boîte à outils commune. Si le service redémarre en boucle, la cause se trouve presque toujours dans ses journaux : base de données injoignable, secret ou certificat invalide, erreur de configuration.

Alerte : mise à jour en échec (paused / rollback)

docker service inspect <SERVICE> --format '{{json .UpdateStatus}}'
docker service ps <SERVICE> --no-trunc | head -10
  • rollback_completed : la nouvelle version n’a pas démarré correctement et Swarm est revenu à la précédente. Le service fonctionne, mais la mise à jour n’est pas appliquée. Analysez les journaux de la tâche en échec avant de relancer le déploiement.

  • paused : la mise à jour ou le rollback est bloqué, une intervention est requise : docker service rollback <SERVICE> ou relance du rôle.

Alerte : certificat HTTPS proche de l’expiration ou invalide

# Certificat réellement présenté et chaîne
openssl s_client -connect portail.example.com:443 -servername portail.example.com -showcerts </dev/null

# Configuration traefik (sur les managers)
ls -l /opt/traefik/config/
cat /opt/traefik/config/certificates.toml

# Journaux traefik (erreurs de chargement, ACME)
journalctl -t reemo_traefik --since "1 day ago" | grep -i -E 'error|acme|certificate'
  • Certificat fourni par le client (TRAEFIK_SSL_CERTS) : remplacer les fichiers sur le poste d’administration, puis relancer --tags traefik_ssl. Traefik recharge la configuration à chaud, sans redémarrage.

  • Let’s Encrypt : le challenge TLS-ALPN passe par le port 443. Vérifiez que le port est joignable depuis Internet et que le DNS pointe bien vers la plateforme.

  • Traefik présente un certificat ``localhost`` : c’est le certificat par défaut. Aucun certificat ne correspond au nom demandé (SNI) : vérifiez l’URL et le contenu de certificates.toml.

  • Ports en passthrough (Workstation, Appliance, Credential portal) : le certificat est celui du service lui-même. Renouvelez-le côté service (PKI / CA Workstation), puis redéployez le service.

Alerte : healthcheck portail / portail d’administration KO

curl -v https://portail.example.com/api/healthcheck
curl -s https://portail.example.com/api/healthcheck | jq '.. | objects | select(.status? and .status != "OK")'
docker service ps reemo_portal --no-trunc | head
journalctl -t reemo_portal --since "30 min ago"
journalctl -t reemo_traefik --since "30 min ago" | grep -i portal

Interprétation du code HTTP :

Code

Cause probable

200 avec un status différent de OK

Un sous-service est en défaut : repérez-le dans le JSON (api, db, provision-api, provision-relay-api, container-providers, ws-relays, signal) et suivez l’alerte correspondante.

403

IP de supervision absente de HEALTHCHECK_RESTRICT_IP (ou de HEALTHCHECK_PORTALADMIN_RESTRICT_IP).

404

Route de healthcheck non déployée (HEALTHCHECK_ENABLE à false) ou mauvais nom d’hôte (PORTAL_URL).

502 / 503

Traefik n’atteint pas le service reemo_portal : service arrêté, en cours de redémarrage ou unhealthy.

504

Le portail ne répond pas à temps : surcharge, ou dépendance (API) lente ou injoignable.

Erreur TLS

Voir Alerte : certificat HTTPS proche de l’expiration ou invalide.

En architecture séparée, un healthcheck du portail en erreur peut venir de l’API : suivez aussi Alerte : API (architecture séparée).

Alerte : signal KO

curl -v https://signal.example.com:8443/            # attendu : HTTP 426 "Upgrade Required"
docker service ps reemo_signal --no-trunc | head
journalctl -t reemo_signal --since "30 min ago"
ss -lntp | grep 8443                           # sur les managers portail

Interprétation de la réponse :

  • HTTP 426 « Upgrade Required » : signal fonctionne. Si les sessions échouent malgré tout, un équipement intermédiaire (proxy, WAF, répartiteur de charge) bloque probablement le passage en WebSocket (en-têtes Upgrade / Connection).

  • HTTP 200, ou 426 sans ce texte : la réponse ne vient pas de signal (page de maintenance, autre routeur traefik). Vérifiez SIGNAL_URL et le port.

  • 404 : aucun routeur traefik ne correspond au nom d’hôte demandé.

  • 502 / 504 : traefik n’atteint pas reemo_signal (service arrêté, ou mTLS traefik → signal en échec).

Le port signal (TRAEFIK_SSL_SIGNALPORT) doit être ouvert en entrée. Traefik joint signal en mTLS : un 502 accompagné d’erreurs TLS dans les journaux traefik indique un certificat signal ou une CA interne expirés.

Alerte : API (architecture séparée)

À suivre en cas d’alerte sur le port de l’API, ou sur le healthcheck du portail en architecture séparée.

Depuis une machine portail (flux réellement utilisé par le portail) :

nc -vz <API_IP> 443                             # flux réseau portail -> API
curl -sk -o /dev/null https://<API_IP>/         # doit echouer avec "certificate required"
docker service ps reemo_api --no-trunc | head   # proxy haproxy côté portail
journalctl -t reemo_api --since "30 min ago"    # journaux haproxy (nœud portail)
journalctl -t reemo_portal --since "30 min ago" | grep -i -E 'api|error|timeout'

Sur un manager ``api_manager`` :

docker service ls | grep -E 'reemo_(api|mysql|proapi|prorelayapi)|traefik'
docker service ps reemo_api --no-trunc | head
journalctl -t reemo_api --since "30 min ago"
journalctl -t reemo_traefik --since "30 min ago" | grep -i -E 'error|tls|api'

Symptôme

Piste

nc échoue depuis le portail

Filtrage réseau entre portail et API, ou traefik arrêté sur l’API.

La sonde de port signale « mTLS non exigé »

Configuration traefik de l’API modifiée (/opt/traefik/config/certificates.toml) : redéployez avec --tags traefik.

Port OK, healthcheck du portail KO, erreurs TLS dans les journaux haproxy/portail

Certificat client du portail ou certificat serveur de l’API expiré, ou CA différente entre les deux clusters. Vérifiez la PKI (voir Alerte : certificat de la PKI interne proche de l’expiration).

Port OK, healthcheck du portail KO, 502 / 504 dans les journaux traefik de l’API

Traefik n’atteint pas reemo_api : service arrêté ou unhealthy. Consultez les journaux de l’API (connexion à la base ?).

Alerte : Workstation KO

nc -vz portail.example.com 8445
openssl s_client -connect portail.example.com:8445 </dev/null | openssl x509 -noout -subject -enddate
docker service ps reemo_workstation --no-trunc | head
journalctl -t reemo_workstation --since "30 min ago"
  • Port 8445 (WORKSTATION_INIT_PORTALPORT) fermé : vérifiez le pare-feu et le service traefik.

  • Workstation démarre mais échoue sur les appels API : en architecture séparée, suivez Alerte : API (architecture séparée). Sinon, vérifiez WORKSTATION_API_URL et le service reemo_api.

  • Certificat expiré : CA Workstation (WORKSTATION_INITCA_ENABLED), puis redéploiement --tags workstation.

Alerte : appliance portal KO

# Depuis le serveur de supervision, ou depuis un site appliance
nc -vz portail.example.com 8444
openssl s_client -connect portail.example.com:8444 </dev/null | openssl x509 -noout -subject -enddate

# Sur un manager portail
docker service ps reemo_applianceportal --no-trunc | head
journalctl -t reemo_applianceportal --since "30 min ago"
ss -lntp | grep 8444                            # traefik publie-t-il le port ?

# Sur un manager API
docker service ps reemo_applianceapi --no-trunc | head
journalctl -t reemo_applianceapi --since "30 min ago"

Symptôme

Piste

Port 8444 fermé

Pare-feu, ou traefik déployé sans l’entrypoint applianceportal (APPLIANCE_ENABLED à false lors du déploiement de traefik) : relancer avec --tags traefik.

Port ouvert mais connexion coupée immédiatement

Service reemo_applianceportal arrêté ou unhealthy : consultez ses journaux.

Certificat expiré

Renouvelez-le via la PKI (voir Alerte : certificat de la PKI interne proche de l’expiration), puis redéployez --tags applianceportal.

Les appliances ne se connectent pas alors que la sonde est OK

Flux bloqué depuis le site de l’appliance, ou APPLIANCE_INIT_PORTALURL incorrect dans la configuration de l’appliance.

Erreurs d’appel à l’API dans les journaux applianceportal / applianceapi

Voir reemo_applianceapi et, en architecture séparée, Alerte : API (architecture séparée).

Alerte : credential portal KO

# Depuis le serveur de supervision (IP autorisée dans CREDENTIAL_PORTAL_RESTRICT_IP)
nc -vz portail.example.com 8446
openssl s_client -connect portail.example.com:8446 </dev/null | openssl x509 -noout -subject -enddate

# Sur un manager portail
docker service ps reemo_credentialportal --no-trunc | head
journalctl -t reemo_credentialportal --since "30 min ago"
docker service inspect reemo_credentialportal \
  --format '{{index .Spec.Labels "traefik.tcp.middlewares.reemo_credentialportal_ipallowlist.ipallowlist.sourcerange"}}'

# Sur un manager API
docker service ps reemo_credentialapi --no-trunc | head
journalctl -t reemo_credentialapi --since "30 min ago"

Symptôme

Piste

nc OK mais openssl s_client coupé sans certificat

IP source absente de CREDENTIAL_PORTAL_RESTRICT_IP (liste affichée par la commande docker service inspect ci-dessus).

Port 8446 fermé

Pare-feu, ou traefik déployé sans l’entrypoint credentialportal : relancer avec --tags traefik.

Portail joignable mais erreurs à l’ouverture du coffre

reemo_credentialapi KO, ou Vault sealed (voir Alerte : Vault sealed).

Certificat expiré

Renouvelez-le via la PKI, puis redéployez --tags credentialportal.

Alerte : TURN KO

# Sur le nœud qui héberge TURN (TURN1_NODE / TURN2_NODE)
docker service ps reemo_turn1 --no-trunc | head
ss -lntup | grep 58200                          # écoute TCP et UDP
journalctl -t reemo_turn1 --since "30 min ago"
timedatectl                                     # l'heure doit être synchronisée

# Depuis l'extérieur
nc -vz  <TURN1_IP> 58200
nc -vzu <TURN1_IP> 58200

Symptôme

Piste

Port injoignable depuis l’extérieur

Pare-feu ou NAT : TURN_PORT doit être ouvert en TCP et UDP vers TURN1_IP / TURN2_IP.

Service à 0/1, no suitable node

TURN1_NODE ne correspond pas au hostname Swarm du nœud (docker node ls).

Authentification refusée (401)

Secret différent entre TURN et API, ou horloge désynchronisée (identifiants éphémères).

Sessions qui ne passent pas alors que la sonde est OK

TURN1_IP / TURN2_IP ne sont pas les IP publiques réellement joignables par les clients (externalip).

Vérifier la cohérence du secret : un secret Docker n’est pas relisible. On compare donc les dates de création de chaque côté, et on s’assure que TURN_SECRET a la même valeur dans l’inventaire pour turn_manager et pour api_manager / infra_manager :

docker secret inspect reemo_TURN_SECRET --format '{{.CreatedAt}}'

Le rôle crée le secret uniquement s’il n’existe pas. Modifier TURN_SECRET dans l’inventaire ne met donc pas à jour un secret existant. Pour le changer, il faut supprimer puis recréer le secret sur chaque cluster concerné. Le secret est utilisé par des services en cours d’exécution (TURN, API) : réalisez cette opération pendant une fenêtre de maintenance, en lien avec le support Reemo.

Alerte : Vault sealed

docker ps --format '{{.ID}} {{.Names}}' | grep reemo_vault
docker exec <ID_CONTENEUR> bao status
journalctl -t reemo_vault1 --since "1 hour ago"

En mode VAULT_UNSEAL_MODE=manual, Vault se verrouille à chaque redémarrage de ses conteneurs (redémarrage du nœud, mise à jour…). Pour le déverrouiller :

  • avec le rôle (recommandé) : depuis le poste d’administration qui détient init.json (VAULT_INIT_FILE), relancez le rôle avec --tags vault ;

  • manuellement : sur chaque réplica, appliquez VAULT_KEY_THRESHOLD clés (3 par défaut) :

    docker exec -it <ID_CONTENEUR> bao operator unseal     # répéter avec 3 clés différentes
    

En mode raft, contrôlez ensuite le cluster : docker exec <ID> bao operator raft list-peers (nécessite un jeton). Les services reemo_credentialapi / reemo_credentialportal reprennent leur fonctionnement une fois Vault déverrouillé.

Alerte : base de données MariaDB

docker service ps reemo_mysql --no-trunc | head
journalctl -t reemo_mysql --since "1 hour ago"
df -h /opt/reemo/db                              # disque plein ?
id=$(docker ps -q --filter name=^reemo_mysql\.)
docker exec -it $id sh -c 'MYSQL_PWD=$(cat $MYSQL_ROOT_PASSWORD_FILE) mysqladmin -u root status processlist'
  • Disque plein : libérez de l’espace. La base se remet en marche seule dès que l’espace est disponible, sinon redémarrez le service.

  • Trop de connexions : consultez la liste des processus (processlist) et identifiez le service à l’origine des connexions.

  • Erreurs InnoDB au démarrage : ne supprimez aucun fichier. Contactez le support avec les journaux.

Alerte : NDB Cluster

id=$(docker ps -q --filter name=reemo_mysql-mgmd | head -1)
docker exec $id ndb_mgm -e show
docker exec $id ndb_mgm -e "all status"
docker exec $id ndb_mgm -e "all report memory"
journalctl -t reemo_mysql-mgmd-1 --since "1 hour ago"
  • Nœud ndbd non connecté : vérifiez le service reemo_mysql-ndbd-N (docker service ps) et ses journaux (journalctl -t reemo_mysql-ndbd-N).

  • Mémoire de données saturée : les écritures échouent (table is full). Augmentez la mémoire NDB (dimensionnement), puis faites un redémarrage progressif avec le rôle (--tags mysqlclusterrollingrestart).

Alerte : sauvegarde absente ou trop ancienne

docker service ps reemo_backup --no-trunc | head
journalctl -t reemo_backup --since "2 days ago"

# Depuis le poste d'administration
ansible-playbook ... --tags backup --extra-vars "LISTBACKUP=true"    # sauvegardes disponibles
ansible-playbook ... --tags backup --extra-vars "BACKUP_NOW=true"    # sauvegarde immédiate
ansible-playbook ... --tags backup --extra-vars "VERIFYBACKUP=true"  # contrôle d'intégrité

Causes fréquentes : serveur de sauvegarde injoignable (SSH, clé), espace plein sur la destination, clé de chiffrement ou mot de passe modifiés, base de données indisponible au moment de la sauvegarde.

Alerte : certificat de la PKI interne proche de l’expiration

Le rôle régénère automatiquement un certificat de service lorsqu’il expire dans moins de 30 jours, à l’exécution de la PKI (INITCA_ENABLE=true). Pour renouveler :

  1. relancer le rôle avec --tags initca et INITCA_ENABLE=true (poussée git si INITCA_GIT_ENABLE=true) ;

  2. redéployer les services concernés pour qu’ils prennent en compte les nouveaux certificats (déploiement complet, ou tags ciblés : api, portal, signal, traefik…).

L’expiration de la CA elle-même (INITCA_OWNCA_NOT_AFTER, 824 jours par défaut) demande une opération planifiée : tous les certificats doivent être réémis. Anticipez-la avec le support Reemo.

Alerte : relayws / provisionnement (nginx mTLS) KO

# Sur la machine relayws ou provision
systemctl status nginx
nginx -t
journalctl -u nginx --since "30 min ago"
tail -50 /var/log/nginx/error.log
ss -lntp | grep 8443

# Depuis une machine API
nc -vz <IP_RELAYWS_OU_PROVISION> 8443
  • nc échoue : vérifiez le pare-feu. Avec RELAYWS_NGINX_FW_ENABLE / PROVISION_NGINX_FW_ENABLE, l’IP des machines API doit figurer dans *_NGINX_FW_ALLOWED_IPS.

  • Erreur 400 No required SSL certificate / certificate verify failed dans les journaux nginx : certificat client (prorelayapi) expiré ou CA différente. Voir Alerte : certificat de la PKI interne proche de l’expiration.

Alerte : traefik KO

docker service ps traefik --no-trunc | head
journalctl -t reemo_traefik --since "30 min ago"
ss -lntp | grep -E ':(80|443|8443) '             # conflit de port ?
ls -ld /opt/traefik /opt/traefik/config          # droits root:docker 0750

Si traefik est arrêté, tous les accès HTTPS du cluster sont coupés. Un conflit de port (nginx ou apache installé sur l’hôte, par exemple) empêche la publication des ports en mode host.

Alerte : disque plein

df -h
docker system df
du -sh /opt/* /var/lib/docker/* 2>/dev/null | sort -h | tail

Avertissement

docker image prune -a supprime les images qui ne sont pas utilisées, y compris les versions précédentes, ce qui rend un rollback impossible. En installation hors ligne, ces images devront être rechargées. Préférez docker image prune (images orphelines uniquement) et docker container prune.