Alert Troubleshooting¶
This page lists, for each alert, the commands to run to identify the cause. For an initial global diagnosis, start with Quick status check.
This section lists, for each alert, the commands to run to identify the cause. They should be executed as root on a manager of the cluster in question, unless otherwise specified.
Common Toolbox¶
# Global state
docker node ls
docker service ls
# Task history for a service, with the complete error message
docker service ps reemo_portal --no-trunc
# Configuration and status of the latest update
docker service inspect reemo_portal --pretty
docker service inspect reemo_portal --format '{{json .UpdateStatus}}'
# Containers on the local node and Docker healthcheck status
docker ps -a --filter name=reemo_portal
docker inspect --format '{{json .State.Health}}' <CONTAINER_ID>
# Recent events (restarts, healthcheck failures, OOM…)
docker events --since 30m --until 0s --filter type=container
# Node resources
df -h /var/lib/docker /opt
free -m
dmesg -T | grep -i -E 'oom|killed process'
Logs: services log to syslog with the tag <INSTANCE_NAME>_<service>. You must read
them on the node running the container (column NODE from docker service ps):
journalctl -t reemo_portal --since "1 hour ago"
# or, depending on rsyslog configuration:
grep reemo_portal /var/log/syslog # Debian / Ubuntu
grep reemo_portal /var/log/messages # RedHat / Rocky
# Docker >= 20.10 also keeps a local log cache:
docker logs --tail 200 <CONTAINER_ID>
Common corrective actions:
# Restart a service (recreates its containers)
docker service update --force reemo_portal
# Revert to the previous version after a failed update
docker service rollback reemo_portal
# Redeploy a component using the Ansible role (from the administration station)
ansible-playbook -i <inventory> <playbook> --limit <group> --tags portal
Common error messages in docker service ps --no-trunc:
Message |
Probable cause |
|---|---|
|
Impossible placement constraint: unavailable node, missing label, |
|
Missing Docker secret: rerun the role with the |
|
Image missing from registry or not loaded (offline mode: rerun with |
|
Another process (nginx, old container) occupies the published port: |
|
Container starts then crashes: check its logs. |
|
Docker healthcheck fails: the service is not listening on its internal port. Check its logs. |
Alert: Swarm node down¶
docker node ls
docker node inspect <NODE> --pretty # status, reason, address
# on the node in question:
systemctl status docker
journalctl -u docker --since "1 hour ago"
docker info | sed -n '/Swarm/,/Node Address/p'
timedatectl # clock skew?
Points to verify:
Docker daemon is running on the node;
Swarm flows between nodes are open: 2377/tcp, 7946/tcp+udp, and 4789/udp (or
SWARM_DATA_PATH_PORT). Test:nc -vz <other_node> 2377;manager quorum: with 3 managers, losing 2 of them blocks the cluster. Never remove a manager without verifying quorum.
Alert: Incomplete Swarm service (replicas x/y)¶
docker service ps <SERVICE> --no-trunc | head -20
docker service inspect <SERVICE> --format '{{json .Spec.TaskTemplate.Placement}}'
# on the node indicated in the NODE column:
journalctl -t <SERVICE> --since "30 min ago"
Special cases:
<INSTANCE_NAME>_db/<INSTANCE_NAME>_logapidbat0/1: normal state for these unique database update tasks. An alert is only justified if their last execution failed (Failed). Then checkjournalctl -t reemo_db(orreemo_logapidb) on the node that ran it, then rerun the deployment with--tags db(orlogapidb).<INSTANCE_NAME>_mysqlbackup: legacy backup system, ignore it.
Refer to the frequent error message table in Common Toolbox. If the service restarts in a loop, the cause is almost always in its logs: unreachable database, invalid secret or certificate, configuration error.
Alert: Failed update (paused / rollback)¶
docker service inspect <SERVICE> --format '{{json .UpdateStatus}}'
docker service ps <SERVICE> --no-trunc | head -10
rollback_completed: the new version did not start correctly and Swarm reverted to the previous one. The service is working, but the update is not applied. Analyze the failed task’s logs before rerunning the deployment.paused: the update or rollback is blocked; intervention is required:docker service rollback <SERVICE>or rerun the role.
Alert: HTTPS certificate near expiration or invalid¶
# Certificate actually presented and chain
openssl s_client -connect portail.example.com:443 -servername portail.example.com -showcerts </dev/null
# Traefik configuration (on managers)
ls -l /opt/traefik/config/
cat /opt/traefik/config/certificates.toml
# Traefik logs (loading errors, ACME)
journalctl -t reemo_traefik --since "1 day ago" | grep -i -E 'error|acme|certificate'
Certificate provided by the client (
TRAEFIK_SSL_CERTS): replace the files on the administration station, then rerun--tags traefik_ssl. Traefik reloads the configuration hot, without restart.Let’s Encrypt: the TLS-ALPN challenge goes through port 443. Verify that the port is reachable from the Internet and that DNS points to the platform.
Traefik presents a ``localhost`` certificate: this is the default certificate. No certificate matches the requested name (SNI): check the URL and the contents of
certificates.toml.Ports in passthrough (Workstation, Appliance, Credential portal): the certificate is from the service itself. Renew it on the service side (PKI / Workstation CA), then redeploy the service.
Alert: Portal / admin portal healthcheck down¶
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
HTTP code interpretation:
Code |
Probable cause |
|---|---|
200 with a |
A sub-service is failing: identify it in the JSON ( |
403 |
Monitoring IP missing from |
404 |
Healthcheck route not deployed ( |
502 / 503 |
Traefik cannot reach the |
504 |
Portal not responding in time: overload, or slow/unreachable dependency (API). |
TLS error |
In a separate architecture, a portal healthcheck error can come from the API: also follow Alert: API (separate architecture).
Alert: Signal down¶
curl -v https://signal.example.com:8443/ # expected: HTTP 426 "Upgrade Required"
docker service ps reemo_signal --no-trunc | head
journalctl -t reemo_signal --since "30 min ago"
ss -lntp | grep 8443 # on portal managers
Response interpretation:
HTTP 426 “Upgrade Required”: signal is working. If sessions still fail, an intermediary (proxy, WAF, load balancer) is probably blocking the WebSocket upgrade (
Upgrade/Connectionheaders).HTTP 200, or 426 without this text: the response is not from signal (maintenance page, another traefik router). Check
SIGNAL_URLand the port.404: no traefik router matches the requested hostname.
502 / 504: traefik cannot reach
reemo_signal(service stopped, or mTLS traefik > signal failed).
The signal port (TRAEFIK_SSL_SIGNALPORT) must be open inbound. Traefik reaches
signal via mTLS: a 502 with TLS errors in traefik logs indicates an expired signal
certificate or internal CA.
Alert: API (separate architecture)¶
Follow if there is an alert on the API port, or on the portal healthcheck in separate architecture.
From a portal machine (flow actually used by the portal):
nc -vz <API_IP> 443 # portal -> API network flow
curl -sk -o /dev/null https://<API_IP>/ # should fail with "certificate required"
docker service ps reemo_api --no-trunc | head # haproxy proxy on portal side
journalctl -t reemo_api --since "30 min ago" # haproxy logs (portal node)
journalctl -t reemo_portal --since "30 min ago" | grep -i -E 'api|error|timeout'
On an ``api_manager`` 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'
Symptom |
Lead |
|---|---|
|
Network filtering between portal and API, or traefik stopped on API. |
Port probe reports “mTLS not required” |
API traefik configuration changed ( |
Port OK, portal healthcheck down, TLS errors in haproxy/portal logs |
Portal client certificate or API server certificate expired, or different CA between the two clusters. Check the PKI (see Alert: Internal PKI certificate near expiration). |
Port OK, portal healthcheck down, 502 / 504 in API traefik logs |
Traefik cannot reach |
Alert: Workstation down¶
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) closed: check firewall and traefik service.Workstation starts but fails on API calls: in separate architecture, follow Alert: API (separate architecture). Otherwise, check
WORKSTATION_API_URLand thereemo_apiservice.Expired certificate: Workstation CA (
WORKSTATION_INITCA_ENABLED), then redeploy with--tags workstation.
Alert: Appliance portal down¶
# From the monitoring server, or from an appliance site
nc -vz portail.example.com 8444
openssl s_client -connect portail.example.com:8444 </dev/null | openssl x509 -noout -subject -enddate
# On a portal manager
docker service ps reemo_applianceportal --no-trunc | head
journalctl -t reemo_applianceportal --since "30 min ago"
ss -lntp | grep 8444 # is traefik publishing the port?
# On an API manager
docker service ps reemo_applianceapi --no-trunc | head
journalctl -t reemo_applianceapi --since "30 min ago"
Symptom |
Lead |
|---|---|
Port 8444 closed |
Firewall, or traefik deployed without the |
Port open but connection dropped immediately |
|
Expired certificate |
Renew it via PKI (see Alert: Internal PKI certificate near expiration), then redeploy with |
Appliances not connecting while probe is OK |
Flow blocked from appliance site, or |
API call errors in applianceportal / applianceapi logs |
See |
Alert: Credential portal down¶
# From the monitoring server (IP authorized in 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
# On a portal manager
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"}}'
# On an API manager
docker service ps reemo_credentialapi --no-trunc | head
journalctl -t reemo_credentialapi --since "30 min ago"
Symptom |
Lead |
|---|---|
|
Source IP missing from |
Port 8446 closed |
Firewall, or traefik deployed without the |
Portal reachable but vault opening errors |
|
Expired certificate |
Renew it via PKI, then redeploy with |
Alert: TURN down¶
# On the node hosting TURN (TURN1_NODE / TURN2_NODE)
docker service ps reemo_turn1 --no-trunc | head
ss -lntup | grep 58200 # listening on TCP and UDP
journalctl -t reemo_turn1 --since "30 min ago"
timedatectl # time must be synchronized
# From outside
nc -vz <TURN1_IP> 58200
nc -vzu <TURN1_IP> 58200
Symptom |
Lead |
|---|---|
Port unreachable from outside |
Firewall or NAT: |
Service at 0/1, |
|
Authentication refused (401) |
Secret differs between TURN and API, or clocks out of sync (ephemeral credentials). |
Sessions not passing while probe is OK |
|
Verify secret consistency: a Docker secret is not readable. Instead, compare
the creation date on each side, and ensure TURN_SECRET has the same value in
the inventory for turn_manager and for api_manager / infra_manager:
docker secret inspect reemo_TURN_SECRET --format '{{.CreatedAt}}'
The role creates the secret only if it does not exist. Changing TURN_SECRET
in the inventory does not update an existing secret. To change it, you must
delete and recreate the secret on each cluster. The secret is used by
running services (TURN, API): perform this operation during a maintenance window,
in coordination with Reemo support.
Alert: Vault sealed¶
docker ps --format '{{.ID}} {{.Names}}' | grep reemo_vault
docker exec <CONTAINER_ID> bao status
journalctl -t reemo_vault1 --since "1 hour ago"
In VAULT_UNSEAL_MODE=manual mode, Vault locks on each container restart
(node restart, update…). To unlock it:
using the role (recommended): from the administration station with
init.json(VAULT_INIT_FILE), rerun the role with--tags vault;manually: on each replica, apply
VAULT_KEY_THRESHOLDkeys (3 by default):docker exec -it <CONTAINER_ID> bao operator unseal # repeat with 3 different keys
In raft mode, then check the cluster: docker exec <ID> bao operator raft list-peers
(requires a token). The reemo_credentialapi / reemo_credentialportal
services resume operation once Vault is unlocked.
Alert: MariaDB database¶
docker service ps reemo_mysql --no-trunc | head
journalctl -t reemo_mysql --since "1 hour ago"
df -h /opt/reemo/db # disk full?
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'
Disk full: free up space. The database restarts on its own once space is available; otherwise, restart the service.
Too many connections: check the process list (
processlist) and identify the service responsible for the connections.InnoDB errors at startup: do not delete any files. Contact support with the logs.
Alert: 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"
ndbdnode not connected: check thereemo_mysql-ndbd-Nservice (docker service ps) and its logs (journalctl -t reemo_mysql-ndbd-N).Data memory saturated: writes fail (
table is full). Increase NDB memory (sizing), then perform a rolling restart with the role (--tags mysqlclusterrollingrestart).
Alert: Backup missing or outdated¶
docker service ps reemo_backup --no-trunc | head
journalctl -t reemo_backup --since "2 days ago"
# From the administration station
ansible-playbook ... --tags backup --extra-vars "LISTBACKUP=true" # available backups
ansible-playbook ... --tags backup --extra-vars "BACKUP_NOW=true" # immediate backup
ansible-playbook ... --tags backup --extra-vars "VERIFYBACKUP=true" # integrity check
Common causes: backup server unreachable (SSH, key), full space on destination, encryption key or password changed, database unavailable at backup time.
Alert: Internal PKI certificate near expiration¶
The role automatically regenerates a service certificate when it expires
within 30 days, when the PKI role is run (INITCA_ENABLE=true). To renew:
rerun the role with
--tags initcaandINITCA_ENABLE=true(git push ifINITCA_GIT_ENABLE=true);redeploy affected services so they pick up the new certificates (full deployment, or targeted tags:
api,portal,signal,traefik…).
The CA itself expiration (INITCA_OWNCA_NOT_AFTER, 824 days by default)
requires a planned operation: all certificates must be reissued. Plan ahead with
Reemo support.
Alert: relayws / provisioning (nginx mTLS) down¶
# On the relayws or provision machine
systemctl status nginx
nginx -t
journalctl -u nginx --since "30 min ago"
tail -50 /var/log/nginx/error.log
ss -lntp | grep 8443
# From an API machine
nc -vz <RELAYWS_OR_PROVISION_IP> 8443
ncfails: check firewall. WithRELAYWS_NGINX_FW_ENABLE/PROVISION_NGINX_FW_ENABLE, the API machine IPs must be in*_NGINX_FW_ALLOWED_IPS.Error
400 No required SSL certificate/certificate verify failedin nginx logs: client certificate (prorelayapi) expired or different CA. See Alert: Internal PKI certificate near expiration.
Alert: Traefik down¶
docker service ps traefik --no-trunc | head
journalctl -t reemo_traefik --since "30 min ago"
ss -lntp | grep -E ':(80|443|8443) ' # port conflict?
ls -ld /opt/traefik /opt/traefik/config # permissions root:docker 0750
If traefik is stopped, all HTTPS access to the cluster is cut. A port conflict (nginx or apache installed on the host, for example) prevents port publication in host mode.
Alert: Disk full¶
df -h
docker system df
du -sh /opt/* /var/lib/docker/* 2>/dev/null | sort -h | tail
Warning
docker image prune -a removes unused images, including previous
versions, making rollback impossible. In offline installations, these
images must be reloaded. Prefer docker image prune (orphaned images only)
and docker container prune.