ITSkillsCenter
Business Digital

Service discovery et health checks Consul — du JSON à la résolution DNS 2026

16 دقائق للقراءة

📍 Article principal du cluster : HashiCorp Consul Associate (003) — guide pratique de la certification 2026

Ce tutoriel fait partie du cluster certification Consul Associate. Pour la vue d’ensemble, lisez d’abord le pilier.

Introduction

Le service discovery est le cœur fonctionnel de Consul. C’est aussi le domaine 4 du syllabus Consul Associate (003) — le plus richement testé après les ACL. Dans ce tutoriel, vous allez enregistrer trois services applicatifs réels (un service Go qui expose une API HTTP, un service Node.js qui le consomme, un service Python qui maintient une configuration partagée), configurer des health checks de quatre types différents (HTTP, TCP, script, et TTL), interroger le catalogue par les quatre canaux officiels (CLI, API HTTP, UI Web, DNS), et exploiter les prepared queries pour agréger plusieurs services en un nom DNS unique. Toutes les commandes supposent que vous avez déjà un cluster Consul opérationnel comme dans le tutoriel d’installation.

Prérequis

  • Cluster Consul 1.20 fonctionnel (3 serveurs + 2 clients) issu du tutoriel d’installation
  • Notions de base HTTP et REST
  • Go 1.22+, Node.js 22+ et Python 3.12+ disponibles dans les conteneurs clients (installation rapide pendant le tuto)
  • 40 minutes de temps

Étape 1 — Comprendre les méthodes d’enregistrement de service

Consul propose trois méthodes pour enregistrer un service. Le candidat à l’examen doit savoir les distinguer et choisir la bonne selon le contexte. La première méthode est le fichier de configuration statique placé dans `/etc/consul.d/services/` — chaque service est décrit en HCL ou JSON et chargé au démarrage de l’agent. C’est la méthode recommandée pour les services systemd traditionnels qui tournent sur VM Linux. La deuxième méthode est l’API HTTP : un script ou un orchestrateur appelle `PUT /v1/agent/service/register` pour enregistrer un service à la volée. C’est la méthode utilisée par les containers ECS ou par des hooks de déploiement custom. La troisième méthode est l’injection automatique sidecar en mode service mesh : Consul Connect injecte un Envoy à côté de l’application et l’enregistre automatiquement avec son sidecar. C’est exclusif au service mesh et tombe dans le domaine 5 du syllabus.

Pour ce tutoriel, on utilise les deux premières méthodes pour bien voir la différence. La méthode sidecar attendra le tutoriel service mesh.

Étape 2 — Préparer les services applicatifs Go, Node et Python

On installe d’abord les runtimes nécessaires sur les deux conteneurs clients. Cette étape est purement opérationnelle mais essentielle pour avoir un environnement de pratique réaliste — les questions du domaine 4b portent souvent sur le comportement de Consul face à des services qui plantent, qui sont lents ou qui répondent en erreur.

incus exec consul-cli-1 -- bash -c "
  apt update && apt install -y golang-go nodejs npm
  go version && node --version
"
incus exec consul-cli-2 -- bash -c "
  apt update && apt install -y python3 python3-venv curl
  python3 --version
"

Si l’installation de Node échoue avec une version trop ancienne, utilisez le repository NodeSource pour Node 22+ : `curl -fsSL https://deb.nodesource.com/setup_22.x | bash – && apt install -y nodejs`. Vérifiez ensuite que `go`, `node` et `python3` répondent correctement avant de continuer.

Étape 3 — Créer le service Go « api-orders » avec health check HTTP

Le premier service est un service Go minimaliste qui expose `/health` (200 OK quand sain) et `/orders` (renvoie une liste statique pour la démo). On le déploie sur consul-cli-1 et on l’enregistre via fichier de config — la méthode standard production.

incus exec consul-cli-1 -- bash -c "cat > /opt/api-orders.go <<'EOF'
package main

import (
  \"encoding/json\"
  \"net/http\"
)

func main() {
  http.HandleFunc(\"/health\", func(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(200)
    w.Write([]byte(\"OK\"))
  })
  http.HandleFunc(\"/orders\", func(w http.ResponseWriter, r *http.Request) {
    json.NewEncoder(w).Encode([]string{\"order-1\", \"order-2\", \"order-3\"})
  })
  http.ListenAndServe(\":8081\", nil)
}
EOF"

incus exec consul-cli-1 -- bash -c "
  cd /opt && go build -o api-orders api-orders.go
  nohup /opt/api-orders > /var/log/api-orders.log 2>&1 &
"

# Vérifier que le service répond
incus exec consul-cli-1 -- curl -s http://localhost:8081/health

La sortie doit afficher `OK`. Le service tourne en arrière-plan sur le port 8081. En production réelle, on le packagerait en service systemd avec restart automatique — pour le labo, le `nohup` suffit. À chaque redémarrage du conteneur, il faudra relancer le binaire.

Maintenant on enregistre le service auprès de l’agent Consul local via fichier de configuration :

incus exec consul-cli-1 -- mkdir -p /etc/consul.d/services
incus exec consul-cli-1 -- bash -c "cat > /etc/consul.d/services/api-orders.hcl <<EOF
service {
  name = \"api-orders\"
  id   = \"api-orders-1\"
  port = 8081
  tags = [\"v1\", \"production\"]
  check {
    id       = \"health-check-http\"
    name     = \"HTTP /health\"
    http     = \"http://localhost:8081/health\"
    interval = \"10s\"
    timeout  = \"2s\"
  }
}
EOF"

incus exec consul-cli-1 -- consul reload
sleep 3
incus exec consul-cli-1 -- consul catalog services

La commande `consul catalog services` doit lister `api-orders` parmi les services enregistrés. Le `consul reload` relit les fichiers de configuration sans redémarrer l’agent — c’est la méthode propre pour ajouter ou retirer un service. Le health check HTTP appelle `/health` toutes les 10 secondes : si trois échecs consécutifs surviennent, Consul marque le service en `critical` et il devient invisible aux requêtes DNS par défaut.

Étape 4 — Créer le service Node « web-frontend » avec health check TCP

Le deuxième service expose un serveur HTTP en Node.js sur le port 3000. On utilise un health check TCP plutôt que HTTP — c’est utile quand le service ne dispose pas d’endpoint santé mais qu’on veut au moins vérifier qu’il écoute. Pratique pour les services tiers ou les bases de données legacy qu’on ne contrôle pas.

incus exec consul-cli-1 -- bash -c "cat > /opt/web-frontend.js <<'EOF'
const http = require('http');
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello from web-frontend\\n');
});
server.listen(3000, () => console.log('web-frontend on 3000'));
EOF"

incus exec consul-cli-1 -- bash -c "
  nohup node /opt/web-frontend.js > /var/log/web-frontend.log 2>&1 &
"

incus exec consul-cli-1 -- bash -c "cat > /etc/consul.d/services/web-frontend.hcl <<EOF
service {
  name = \"web-frontend\"
  id   = \"web-frontend-1\"
  port = 3000
  tags = [\"v1\", \"public\"]
  check {
    id       = \"tcp-check\"
    name     = \"TCP port 3000\"
    tcp      = \"localhost:3000\"
    interval = \"10s\"
    timeout  = \"1s\"
  }
}
EOF"

incus exec consul-cli-1 -- consul reload

Vérifiez avec `incus exec consul-cli-1 — consul catalog services` que les deux services sont enregistrés. Le health check TCP est moins informatif qu’un check HTTP — il valide juste l’écoute du port. C’est volontaire : Consul Associate teste votre capacité à choisir le bon type de check selon le contexte.

Étape 5 — Créer le service Python « config-broker » avec health check script

Le troisième service tourne sur consul-cli-2 et expose une fausse logique de configuration. On l’équipe d’un health check « script » qui exécute un binaire externe et considère le service sain si le code de sortie est 0. C’est extrêmement utile quand le service ne peut pas exposer un endpoint santé — par exemple un job batch ou un démon qui doit toucher un fichier de lock.

incus exec consul-cli-2 -- bash -c "cat > /opt/config-broker.py <<'EOF'
import http.server, socketserver
PORT = 5000
class H(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200); self.end_headers()
        self.wfile.write(b'config OK\\n')
with socketserver.TCPServer(('', PORT), H) as httpd:
    httpd.serve_forever()
EOF"

incus exec consul-cli-2 -- bash -c "
  nohup python3 /opt/config-broker.py > /var/log/config-broker.log 2>&1 &
"

# Script de check qui vérifie l'existence d'un fichier de lock
incus exec consul-cli-2 -- bash -c "cat > /usr/local/bin/check-config.sh <<'EOF'
#!/bin/bash
test -f /tmp/config-broker-ok && exit 0 || exit 2
EOF
chmod +x /usr/local/bin/check-config.sh
touch /tmp/config-broker-ok"

incus exec consul-cli-2 -- mkdir -p /etc/consul.d/services
incus exec consul-cli-2 -- bash -c "cat > /etc/consul.d/services/config-broker.hcl <<EOF
service {
  name = \"config-broker\"
  id   = \"config-broker-1\"
  port = 5000
  check {
    id       = \"script-check\"
    name     = \"Lock file existence\"
    args     = [\"/usr/local/bin/check-config.sh\"]
    interval = \"15s\"
    timeout  = \"5s\"
  }
}
EOF"

incus exec consul-cli-2 -- consul reload

Pour que les checks `args` fonctionnent, l’option `enable_local_script_checks = true` doit être activée dans la configuration de l’agent client (à ajouter dans `/etc/consul.d/consul.hcl`). Sans elle, Consul refuse d’exécuter des scripts arbitraires pour des raisons de sécurité — ce comportement est documenté et tombe dans le domaine 6a (modèle de menace). Activez-le, redémarrez l’agent, puis relancez `consul reload`.

Étape 6 — Interroger le catalogue par CLI

La CLI Consul est l’outil le plus rapide pour interroger l’état. Quatre commandes à connaître absolument pour l’examen.

# Lister tous les services du catalogue
incus exec consul-srv-1 -- consul catalog services

# Détails d'un service spécifique avec health checks et tags
incus exec consul-srv-1 -- consul catalog nodes -service=api-orders

# Voir l'état détaillé des health checks d'un nœud
incus exec consul-srv-1 -- consul members
incus exec consul-srv-1 -- curl -s http://localhost:8500/v1/health/service/api-orders | jq .

# Filtrer les services par tag
incus exec consul-srv-1 -- curl -s "http://localhost:8500/v1/catalog/service/api-orders?tag=v1" | jq .

La commande `consul catalog services` liste les noms de service, et `consul catalog nodes -service=NAME` retourne les nœuds qui hébergent ce service. Pour l’API HTTP, retenez les chemins `/v1/catalog/services`, `/v1/catalog/service/NAME`, et `/v1/health/service/NAME` — ce dernier renvoie l’état des checks en plus des métadonnées du service. Ces chemins tombent régulièrement en domaine 4d.

Étape 7 — Résolution DNS et intégration dnsmasq

Consul expose un serveur DNS interne sur le port 8600 (UDP et TCP) qui répond aux requêtes `*.service.consul`. C’est l’interface la plus naturelle pour les services applicatifs qui ne veulent pas s’intégrer à l’API HTTP — ils résolvent simplement `api-orders.service.consul` comme n’importe quel hostname et obtiennent l’IP d’un nœud sain.

# Test direct contre le DNS Consul
incus exec consul-srv-1 -- dig @127.0.0.1 -p 8600 api-orders.service.consul

# Test avec filtrage par tag
incus exec consul-srv-1 -- dig @127.0.0.1 -p 8600 v1.api-orders.service.consul

# Test SRV pour obtenir IP + port simultanément
incus exec consul-srv-1 -- dig @127.0.0.1 -p 8600 api-orders.service.consul SRV

La requête A renvoie l’IP du nœud qui héberge un service sain ; la requête SRV renvoie le couple IP + port. En production, on intègre cela à dnsmasq ou systemd-resolved pour que `*.service.consul` soit résolvable depuis n’importe où sans préciser le serveur DNS. Le pattern dnsmasq classique est de forwarder uniquement le suffixe `.consul` vers `127.0.0.1:8600` et tout le reste vers les DNS upstream. Cette intégration est documentée précisément dans le syllabus 4d.

Étape 8 — Prepared queries pour la résilience cross-service

Une prepared query est une requête DNS persistante qui peut faire bien plus qu’une simple résolution de nom. Elle peut filtrer par tag, basculer sur un service de fallback si aucun nœud n’est sain, et même router automatiquement vers un autre datacenter en cas de défaillance régionale. C’est un outil puissant et c’est précisément le sujet du domaine 4e du syllabus.

incus exec consul-srv-1 -- bash -c "cat > /tmp/pq.json <<EOF
{
  \"Name\": \"orders-pq\",
  \"Service\": {
    \"Service\": \"api-orders\",
    \"Failover\": {
      \"NearestN\": 0,
      \"Datacenters\": []
    },
    \"OnlyPassing\": true,
    \"Tags\": [\"production\"]
  },
  \"DNS\": {
    \"TTL\": \"10s\"
  }
}
EOF"

# Créer la prepared query
incus exec consul-srv-1 -- curl -s -X POST \
  http://localhost:8500/v1/query \
  -d @/tmp/pq.json

# Lister les PQ existantes
incus exec consul-srv-1 -- curl -s http://localhost:8500/v1/query | jq .

# Résoudre via DNS (utilise le pattern .query.consul)
incus exec consul-srv-1 -- dig @127.0.0.1 -p 8600 orders-pq.query.consul

Notez bien la différence : `service.consul` pour la résolution directe, `query.consul` pour les prepared queries. Le paramètre `OnlyPassing: true` exclut les nœuds en warning ou critical du résultat. `NearestN` et `Datacenters` permettent un failover automatique vers d’autres datacenters — fonctionnalité critique pour le domaine 8 (multi-datacenter).

Étape 9 — Tester le comportement en cas de panne

Pour valider que tout fonctionne, on simule une panne du service api-orders et on observe la propagation dans le catalogue, dans le DNS, et dans les prepared queries. C’est le test que vous devez avoir intériorisé avant l’examen.

# Tuer le binaire api-orders
incus exec consul-cli-1 -- pkill -f api-orders

# Attendre 30 secondes (3 cycles de check à 10s)
sleep 35

# Le service doit être en état critical
incus exec consul-srv-1 -- curl -s http://localhost:8500/v1/health/service/api-orders | jq '.[0].Checks'

# La résolution DNS ne renvoie plus d'IP (NXDOMAIN)
incus exec consul-srv-1 -- dig @127.0.0.1 -p 8600 api-orders.service.consul +short

# Relancer le service et observer le retour à passing
incus exec consul-cli-1 -- bash -c "nohup /opt/api-orders > /var/log/api-orders.log 2>&1 &"
sleep 15
incus exec consul-srv-1 -- curl -s http://localhost:8500/v1/health/service/api-orders | jq '.[0].Checks[].Status'

Le statut doit passer de `passing` à `critical` après 30 secondes de panne, puis revenir à `passing` 10-15 secondes après le redémarrage. Ce comportement est exactement ce qu’évalue la question type « Combien de temps faut-il pour qu’un service en panne disparaisse du DNS ? » qui revient régulièrement.

Comprendre les états de health check — passing, warning, critical, maintenance

Consul reconnaît quatre états officiels pour un health check. Le candidat à l’examen Consul Associate doit connaître chacun et leur impact sur la résolution DNS et l’API. passing est l’état nominal : le service est sain et inclus par défaut dans les réponses DNS. warning indique un état dégradé non critique : le service reste disponible, est inclus dans les réponses DNS par défaut, mais signale qu’il faut surveiller — par exemple un check qui mesure la latence et passe en warning au-delà de 500ms. critical exclut automatiquement le service du DNS et de la plupart des prepared queries — le service est considéré inutilisable. maintenance est un état spécial activé manuellement avec `consul maint -enable -service=NAME -reason= »… »`. Il exclut le service comme `critical` mais sans déclencher d’alarmes — utile pour des opérations planifiées de maintenance.

L’algorithme exact de transition entre ces états est documenté en domaine 4c. Un check passe en `critical` après le nombre de cycles d’échec définis par le paramètre `success_before_passing` et `failures_before_critical` — par défaut, un seul échec suffit. Pour les health checks réseau bruyants, on monte à 3 ou 5 échecs successifs requis pour limiter les faux positifs.

Pourquoi les noms de service ne doivent pas refléter l’environnement

Une erreur très fréquente chez les débutants : nommer un service `api-orders-prod` ou `api-orders-staging`. C’est un anti-pattern Consul. Le nom de service doit être logique et indépendant de l’environnement (`api-orders` tout court), et l’environnement doit être encodé soit comme tag (`tags = [« v1 », « production »]`), soit comme datacenter Consul distinct (`dc1` pour prod, `dc2` pour staging). Ce design permet de migrer facilement les services entre environnements sans changer les noms — ce qui est exactement ce qu’évalue la question type sur la stratégie de nommage du domaine 4a.

Erreurs fréquentes

Erreur Cause Solution
Service jamais visible dans le catalogue après reload Erreur de syntaxe HCL silencieuse `consul validate /etc/consul.d/services/` doit retourner OK avant `reload`
Health check script refuse de s’exécuter `enable_local_script_checks` non activé Ajouter `enable_local_script_checks = true` dans la config agent et redémarrer
DNS ne résout pas `*.service.consul` Requête envoyée au mauvais serveur DNS Forcer `@127.0.0.1 -p 8600` ou intégrer dnsmasq
Prepared query renvoie un service en critical `OnlyPassing` non défini ou à false Ajouter `\ »OnlyPassing\ »: true` dans la spec JSON
Health check HTTP timeout Endpoint santé bloque sur dépendance externe L’endpoint `/health` doit répondre en moins de 100ms — ne jamais checker une DB dedans

Adaptation au contexte ouest-africain

Pour les développeurs en équipe distribuée Dakar-Abidjan, l’API HTTP de Consul devient critique pour intégrer des outils internes. Une commande très utilisée en pratique : un script shell quotidien qui interroge `/v1/health/state/critical` et envoie un message WhatsApp Business via webhook si un service tombe. Cette boucle de surveillance maison coûte zéro et évite l’abonnement à un APM payant — particulièrement adapté aux PME qui montent leur SI sur Hostinger Cloud Startup à 9,99 USD/mois sans budget Datadog.

Côté DNS, l’intégration de dnsmasq est essentielle car les solveurs DNS publics utilisés par défaut au Sénégal (8.8.8.8, 1.1.1.1) ne connaissent évidemment pas votre `.consul`. La configuration recommandée : dnsmasq local sur chaque conteneur, forwarding `.consul` vers `127.0.0.1:8600` et tout le reste vers la résolveur upstream, avec un cache local pour réduire la latence sur les noms publics.

Tutoriels frères

Pour aller plus loin

FAQ

Quelle est la différence entre `OnlyPassing` et le filtrage par défaut du DNS ?
Par défaut, le DNS Consul exclut les services en état `critical` mais inclut ceux en `warning`. `OnlyPassing: true` dans une prepared query restreint encore plus le résultat aux services strictement `passing`. C’est utile quand un warning est synonyme de comportement dégradé inacceptable.

Combien de health checks peut-on attacher à un service ?
Pas de limite stricte côté Consul, mais en pratique on garde 1 à 3 checks par service maximum. Plus de checks dilue la sémantique : si 5 checks tombent en warning et qu’un seul est en critical, l’état global du service est `critical`, ce qui peut masquer la cause racine.

Le DNS Consul peut-il remplacer Bind ou PowerDNS ?
Non, Consul DNS répond uniquement aux noms `.service.consul`, `.query.consul`, et `.node.consul`. Il ne fait pas autorité sur d’autres zones et ne peut pas servir de DNS public. C’est un complément, pas un remplacement.

Mots-clés secondaires : consul service discovery tutoriel, health check http tcp script, prepared queries consul, dnsmasq consul integration, catalogue consul api, registration service consul

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité