Aller au contenu
Blockchain Association of Cameroon
BAC-L1-FOUND-1174 h

Docker et environnements reproductibles

« Ça marche sur ma machine » n'est pas un résultat. Empaqueter un nœud et ses dépendances pour que l'atelier fonctionne à l'identique partout.

  • Écrire une image reproductible et versionnée
  • Composer un réseau local multi-conteneurs
  • Gérer volumes persistants et données de chaîne

« Ça marche sur ma machine » n'est pas un résultat : si votre collègue de Douala ne peut pas relancer votre nœud de test, personne ne peut vérifier votre travail. Cet atelier vous apprend à décrire un programme et ses dépendances dans une image versionnée, à relier plusieurs conteneurs dans un petit réseau local, et à garder les données de chaîne sur un volume qui survit aux conteneurs. Vous partez de ce que vous savez de Linux (permissions, services, journaux, ports). Attention : le navigateur ne peut pas lancer Docker. Les exercices en ligne entraînent donc la lecture et le diagnostic sur des extraits réalistes ; la vraie pratique se fait dans le laboratoire autonome, sur votre machine.

Leçons 1/4 · 15 min

Une image reproductible et versionnée

Pourquoi « ça marche chez moi » ne suffit pas

Amina a un nœud de test qui tourne sur son portable. Brice, son collègue, le lance à son tour : il plante, car sa machine a une autre version d'une bibliothèque. Personne n'a mal travaillé : le programme dépendait de choses que personne n'avait écrites.

Trois mots d'abord.

  • Un conteneur est un programme lancé comme un processus isolé : il voit ses propres fichiers, ses propres bibliothèques et sa propre vue du réseau. Contrairement à une machine virtuelle, il partage le noyau Linux de la machine hôte (sous Windows ou macOS, Docker Desktop fait tourner une petite machine virtuelle Linux entre les deux, mais la logique reste la même).
  • Une image est le paquet en lecture seule à partir duquel on démarre des conteneurs. Une image est à un conteneur ce qu'un fichier de programme est à un programme en cours d'exécution.
  • Un Dockerfile est la recette écrite qui fabrique une image.

Lire un Dockerfile

Exemple pour un petit service Node.js (l'indexeur de l'atelier). Les valeurs entre chevrons sont à remplacer par vous-même.

FROM node:<tag>@sha256:<empreinte-relevée>
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
USER node
CMD ["node", "index.js"]

Chaque instruction est une étape. Celles qui modifient les fichiers (COPY, RUN) produisent une couche mise en cache : si rien n'a changé depuis la dernière construction, Docker la réutilise (« CACHED » dans la sortie). Dès qu'une étape change, toutes les suivantes sont refaites. Remarque : ici COPY . . s'exécute avant USER node, donc les fichiers de /app appartiennent à root et sont seulement lisibles par node ; si l'application doit y écrire, utilisez COPY --chown=node:node . ..

Reproductible veut dire épinglé

Trois leviers, du plus important au moins visible.

  1. L'image de base. FROM ubuntu:latest ne promet rien : latest est juste le nom d'étiquette par défaut, celle que l'éditeur a déplacée en dernier. Une étiquette (tag) peut être déplacée ; une empreinte (@sha256:…) ne le peut pas, car c'est le hachage SHA-256 du manifeste de l'image : un contenu différent donne une empreinte différente, comme dans l'atelier sur les fonctions de hachage. On la relève avec docker images --digests pour une image tirée d'un registre (une image construite localement n'en a pas tant qu'elle n'est pas poussée) ; sinon, sur la page du registre. Pour une image multi-architecture, l'empreinte qu'on épingle est en général celle de l'index, qui renvoie vers les variantes par architecture.
  2. Les dépendances. Un fichier de verrouillage (package-lock.json) fige les versions exactes ; npm ci les installe telles quelles et échoue si le fichier et package.json divergent. npm install peut, lui, résoudre autrement.
  3. Votre propre version. Étiquetez ce que vous construisez avec un numéro explicite, par exemple bac-testnode:lab-1, jamais seulement latest.

Ce cours n'écrit volontairement aucun numéro de version « actuel » : les versions changent. Vous apprenez à les épingler et à les vérifier (page de publication du projet, docker images --digests, npm ls), puis à noter ce que vous avez choisi.

L'ordre des instructions compte

Dans l'exemple, on copie d'abord les deux fichiers de dépendances, puis npm ci, puis le reste du code. Si vous modifiez index.js, seule la dernière copie est refaite : l'installation, longue, reste en cache. Si vous aviez écrit COPY . . avant RUN npm ci, chaque modification d'une ligne de code relancerait l'installation complète. Ajoutez aussi un fichier .dockerignore pour exclure .git, node_modules et surtout .env du contexte envoyé à la construction.

Ce que cela ne garantit PAS

  • Pas des octets identiques : une construction peut embarquer des dates, ou un apt-get update qui récupère ce que le miroir contient aujourd'hui. « Reproductible » veut ici : même comportement avec les mêmes entrées épinglées.
  • Épinglé ne veut pas dire sûr. Une empreinte fige aussi une faille connue : il faut mettre à jour volontairement, en changeant l'empreinte et en retestant.
  • Une étiquette qui marche aujourd'hui peut pointer ailleurs demain.

À retenir : image de base par empreinte, dépendances verrouillées, version explicite, cache bien ordonné.

Leçons 2/4 · 15 min

Un réseau local de conteneurs avec Compose

Trois nœuds, une seule commande

Pour tester un protocole, un seul nœud ne suffit pas : il faut au moins trois pairs qui se parlent. Lancer trois fois docker run avec des options longues est source d'erreurs. Docker Compose décrit l'ensemble dans un fichier YAML et le démarre d'un coup : docker compose up -d. L'option -d rend la main au terminal. Voici un extrait. L'image bac-testnode et sa commande health sont fictives, inventées pour l'exercice.

services:
  node1:
    image: bac-testnode:lab-1
    command: ["--name", "node1", "--listen", "0.0.0.0:30333"]
    ports:
      - "127.0.0.1:9944:9944"
    healthcheck:
      test: ["CMD", "bac-testnode", "health"]
      interval: 5s
      retries: 5
    volumes:
      - node1-data:/data
  node2:
    image: bac-testnode:lab-1
    command: ["--name", "node2", "--bootnode", "node1:30333"]
    depends_on:
      node1:
        condition: service_healthy
    volumes:
      - node2-data:/data
volumes:
  node1-data:
  node2-data:

Les noms de services sont des adresses

Compose crée un réseau privé pour le projet. Sur ce réseau, chaque service est joignable par son nom : node1:30333 désigne le port 30333 du conteneur node1. Piège classique : écrire 127.0.0.1:30333 dans la configuration de node2. Dans un conteneur, 127.0.0.1 (« localhost ») désigne le conteneur lui-même, pas la machine ni les autres conteneurs. Le message est alors « connection refused », car personne n'écoute sur ce port dans node2.

Publier un port : hôte:conteneur

La ligne "127.0.0.1:9944:9944" se lit : adresse de l'hôte, port de l'hôte, port du conteneur. Sans le préfixe 127.0.0.1, le port est ouvert sur toutes les interfaces de la machine. Entre conteneurs du même réseau, aucune publication n'est nécessaire : elle ne sert qu'à atteindre un service depuis l'hôte. Avec trois nœuds sur la même machine, deux ne peuvent pas publier le même port hôte : on écrit 9944:9944, 9945:9944, 9946:9944. Même port dans les conteneurs, trois ports différents sur l'hôte.

Démarrer n'est pas être prêt

depends_on simple ne règle que l'ordre de démarrage : Compose lance node1 avant node2, sans attendre que node1 accepte des connexions. Pour attendre, on définit un healthcheck (une commande que Docker exécute à intervalle régulier) et on écrit condition: service_healthy. Même ainsi, un client robuste réessaie sa connexion : un pair peut tomber après le démarrage.

Les commandes à connaître

CommandeEffet
docker compose configvalide le fichier et affiche la configuration résolue
docker compose up -dcrée et démarre les services en arrière-plan
docker compose psétat de chaque service (et santé, si définie)
docker compose logs -f node2suit les journaux d'un service
docker compose downarrête et supprime conteneurs et réseau (pas les volumes)

Ce que cela ne garantit PAS

  • Un réseau Compose simule la topologie, pas la réalité : latence nulle, pas de coupures, une seule machine. Les trois nœuds partagent le même processeur et le même disque.
  • Le réseau interne est isolé de l'extérieur par défaut, mais chaque port que vous publiez ouvre une porte vers l'hôte.
  • Un healthcheck vert dit que la commande de test réussit, pas que le nœud est synchronisé avec les autres.

À retenir : noms de services comme adresses, hôte:conteneur pour publier, santé avant ordre.

Leçons 3/4 · 15 min

Volumes persistants et données de chaîne

Le conteneur oublie tout

Votre nœud a synchronisé jusqu'au bloc 500 ; vous tapez docker compose down puis docker compose up -d. Reprend-il au bloc 500 ou à zéro ? Tout dépend d'où il écrit. Le système de fichiers d'un conteneur est une couche d'écriture jetable : quand on supprime le conteneur, elle disparaît. Pour garder des données, on les place sur un volume, géré hors du conteneur.

Deux sortes de montage

Volume nomméMontage lié (bind mount)
Syntaxenode1-data:/data./data:/data
Géré parDockervous (un dossier de l'hôte)
Avantageportable, pas de souci de cheminvous voyez et sauvegardez les fichiers
Piègecaché dans l'espace de Dockerdroits et propriétaire de l'hôte

Trois séquences, trois résultats

  1. docker compose down puis docker compose up -d : les conteneurs sont supprimés et recréés, mais le volume nommé reste. Le nœud reprend où il était (par exemple bloc 500).
  2. docker compose down -v : l'option -v supprime aussi les volumes nommés déclarés dans le fichier. Le nœud repart de zéro et doit tout resynchroniser.
  3. docker compose stop puis start : le conteneur n'est même pas supprimé.

Retenez la différence entre down et down -v : elle ressemble à celle entre fermer un tiroir et le jeter.

Les droits : retour à Linux

Un montage lié garde le propriétaire de l'hôte. Si votre image tourne avec un utilisateur non privilégié (par exemple l'identifiant 10001) et que ./data appartient à root, le nœud échoue avec un message du genre :

node1  | Error: cannot create directory /data/chain: Permission denied (os error 13)

(Message illustratif.) C'est le même mécanisme de permissions que dans l'atelier sur Linux : on corrige avec chown sur le dossier de l'hôte, jamais avec un chmod 777 qui ouvre tout à tout le monde.

Données de chaîne et clés : deux choses différentes

  • Sur un nœud complet qui ne valide pas, les données de chaîne (blocs, état) se retrouvent en resynchronisant avec le réseau. Les perdre coûte du temps et de la bande passante, pas des fonds.
  • Les clés d'un nœud ou d'un validateur ne se retrouvent pas. Elles ne se mettent pas dans l'image. Sauvegardez-les séparément, hors ligne et chiffrées.
  • Exception importante, pour un validateur. Son état de protection contre la double signature vit souvent dans le dossier de données (par exemple le fichier priv_validator_state.json pour CometBFT ; d'autres clients gardent des données comparables). Supprimer ce volume puis redémarrer le validateur peut effacer cet état et provoquer une double signature, donc une sanction. Ne supprimez jamais ce volume sur un validateur sans l'avoir sauvegardé, et ne le restaurez jamais à une version plus ancienne. Emplacements et détails dépendent du client : lisez sa documentation.

Attention aussi au contraire : sur de nombreuses chaînes à preuve d'enjeu, lancer deux instances avec la même clé de validateur peut être sanctionné. Restaurer une sauvegarde à côté d'un nœud encore vivant n'est donc pas anodin.

Surveiller l'espace disque

Un nœud écrit en continu. Exemple illustratif : 50 Mo par heure font 50 × 24 = 1 200 Mo, soit environ 1,2 Go par jour, donc environ 36 Go au bout de 30 jours. Une saturation de disque arrête le nœud, parfois en corrompant une base. Utilisez df -h sur l'hôte et docker system df pour voir ce que Docker occupe.

Ce que cela ne garantit PAS

  • Un volume n'est pas une sauvegarde : il vit sur le même disque. Si le disque meurt, tout part.
  • Un volume monté depuis une image n'est pas reproductible comme l'image : son contenu dépend de l'historique du nœud.
  • Copier un dossier de base pendant que le nœud écrit peut donner une copie incohérente ; arrêtez le service d'abord, ou utilisez l'outil d'export du nœud s'il existe.

À retenir : données sur un volume, down garde, down -v efface, clés ailleurs que dans l'image.

Leçons 4/4 · 15 min

Un conteneur durci : utilisateur, base minimale, secrets

Un conteneur n'est pas une forteresse

Beaucoup croient qu'« isolé » veut dire « sûr ». Un conteneur partage le noyau de l'hôte : une faille dans l'application, plus des droits excessifs, et l'attaquant a une prise sur la machine. Quatre règles réduisent les dégâts possibles.

1. Ne pas tourner en root

Par défaut, le processus d'un conteneur s'exécute en root dans le conteneur. Dans l'exemple de la première leçon, USER node le remplace par un utilisateur sans privilèges. Si l'application est compromise, l'attaquant ne peut pas, par exemple, modifier les fichiers système de l'image. Pour votre propre binaire, créez un utilisateur dédié avec un identifiant numérique fixe, et donnez-lui seulement le dossier de données.

2. Une image de base minimale

Chaque paquet présent dans l'image est du code à tenir à jour et une surface d'attaque en plus. Une base « slim » ou minimale contient moins de paquets qu'une distribution complète : moins de failles à surveiller, une image plus petite à télécharger (précieux sur une connexion limitée). Compromis : moins d'outils de débogage à l'intérieur. On ne peut pas y installer ce dont on aurait besoin en urgence ; mieux vaut déboguer depuis l'extérieur.

Pour alléger encore, une construction en plusieurs étapes (multi-stage build) compile dans une première image volumineuse, puis ne copie que le résultat dans une image finale minimale. Les outils de compilation ne se retrouvent pas dans l'image livrée :

FROM node:<tag>@sha256:<empreinte> AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:<tag-slim>@sha256:<empreinte>
WORKDIR /app
COPY --from=builder /app/dist ./dist
USER node
CMD ["node", "dist/index.js"]

(Schéma : les noms de scripts et de dossiers varient selon le projet.)

3. Aucun secret dans le Dockerfile

Une clé écrite dans le Dockerfile fait partie de l'image, donc de chaque copie de l'image.

Où le secret se trouveProblème
ENV CLE=… dans le Dockerfilelisible par quiconque a l'image ou peut lancer docker inspect
ARG CLE=… utilisé dans un RUNsouvent retrouvable avec docker history
COPY .env . puis RUN rm .envle fichier reste dans la couche précédente
.env dans le dépôt Gitpublié avec le code

Les secrets arrivent au moment de l'exécution : fichier monté en lecture seule, env_file non versionné, ou mécanisme de secrets de la plateforme. Pour une construction qui a besoin d'un secret, Docker propose les secrets de construction (--mount=type=secret). Si un secret réel a été écrit dans une image ou un dépôt, on le considère comme compromis : on le révoque et on le remplace. Le retirer de l'historique ne suffit pas.

4. Ne pas ouvrir plus de ports que nécessaire

Un port d'administration RPC publié en 9944:9944 est joignable depuis tout le réseau de la machine. Écrivez 127.0.0.1:9944:9944 pour le limiter à l'hôte. Point souvent ignoré : par défaut, Docker gère lui-même les règles réseau de l'hôte, et un port publié peut contourner un pare-feu configuré avec ufw dans l'atelier Linux. Vérifiez avec un test depuis une autre machine.

Autres gestes : ne montez jamais le socket Docker (/var/run/docker.sock) dans un conteneur sans raison, car qui le contrôle contrôle de fait toute la machine ; et faire partie du groupe docker revient en pratique à être administrateur.

Un exemple lu en entier

FROM ubuntu:latest
ENV NODE_KEY=FAKE-KEY-DO-NOT-USE-0000
COPY . /app
CMD ["/app/bac-testnode", "--rpc-external"]

Défauts : base non épinglée et non minimale, clé (fictive ici) dans l'image, pas de USER, et le contexte COPY . /app peut embarquer un .env. Le correctif combine un utilisateur dédié, l'injection de la clé à l'exécution et le port limité à 127.0.0.1.

Ce que cela ne garantit PAS

  • Durcir n'élimine pas les failles de l'application ; cela limite ce qu'une faille permet.
  • Une image petite n'est pas une image sans faille.
  • Un scanner d'images trouve des failles connues, pas toutes.

À retenir : utilisateur sans privilèges, base minimale, secrets à l'exécution, ports restreints.

Laboratoire guidé

Honnêteté d'abord : le navigateur ne peut ni lancer Docker ni construire d'image. Ces étapes entraînent donc la lecture et le diagnostic, qui sont la moitié du métier : devant un Dockerfile, un fichier Compose ou une sortie de console, il faut voir ce qui cloche. Chaque étape présente un extrait réaliste (l'image bac-testnode est fictive) et une question. La vraie pratique, avec un vrai réseau à trois nœuds, est le laboratoire autonome à la fin de l'atelier.

Le navigateur ne remplace pas un vrai terminal : ce laboratoire entraîne la lecture et le raisonnement ; la pratique réelle est dans le laboratoire autonome.

Un compte certifié est nécessaire

Les activités notées enregistrent des résultats à votre nom et servent de base à un titre. Elles exigent donc un dossier certifiant complet et un consentement en vigueur. Remplir le dossier ne vérifie pas votre identité ; le Secrétariat peut ensuite la vérifier (badge « Vérifié »).

  1. 1.Lire un Dockerfile

    Voici le Dockerfile d'un collègue. Son image donne un résultat différent d'une semaine à l'autre, sans que personne ait touché au code.

    FROM ubuntu:latest
    RUN apt-get update && apt-get install -y curl
    COPY . /app
    RUN /app/build.sh
    USER 10001
    CMD ["/app/bac-testnode"]

    Répondez à la question de la grille : quelle ligne est la cause principale du manque de reproductibilité ?

  2. 2.Diagnostiquer un réseau qui ne se forme pas

    Trois nœuds sont lancés avec docker compose up -d. Le service node2 boucle sans trouver de pair. Sa commande dans le fichier Compose et son journal :

    node2:
      command: ["--name", "node2", "--bootnode", "127.0.0.1:30333"]
    
    $ docker compose logs node2
    node2  | dial 127.0.0.1:30333: connect: connection refused
    node2  | no peers, retrying in 5s

    Le nœud node1 est sain (docker compose ps le dit). Répondez à la question de la grille : quelle est la cause et quelle est la correction ?

  3. 3.Prédire ce qui survit

    Un journal de séance, avec le volume nommé node1-data monté sur /data :

    1. docker compose up -d          # node1 synchronise jusqu'au bloc 500
    2. docker compose down
    3. docker compose up -d          # node1 redémarre
    4. docker compose down -v
    5. docker compose up -d          # node1 redémarre

    Répondez à la question de la grille : à quel bloc node1 reprend-il aux étapes 3 puis 5 ?

  4. 4.Lire la sortie d'une construction

    Un Dockerfile et la sortie de la construction faite juste après avoir modifié une seule ligne de index.js :

    FROM node:<tag>@sha256:<empreinte>
    WORKDIR /app
    COPY . .
    RUN npm ci
    USER node
    CMD ["node", "index.js"]
    
     => CACHED [1/4] FROM node:<tag>@sha256:<empreinte>
     => CACHED [2/4] WORKDIR /app
     => [3/4] COPY . .
     => [4/4] RUN npm ci

    La construction est lente à chaque modification de code. Répondez à la question de la grille : quel changement d'ordre corrige cela ?

Exercice de sécurité — Relire un Dockerfile et un Compose avant de les publier

Vous allez publier le dépôt de votre réseau de test pour qu'un pair le reproduise. Avant, vous relisez les fichiers comme un relecteur de sécurité. Les valeurs sont fictives.

# Dockerfile
FROM ubuntu:latest
ENV NODE_KEY=FAKE-KEY-DO-NOT-USE-0000
COPY . /app
CMD ["/app/bac-testnode", "--rpc-external"]

# docker-compose.yml (extrait)
services:
  node1:
    build: .
    ports:
      - "9944:9944"

Le port 9944 est l'interface d'administration RPC du nœud. Le serveur qui héberge le réseau a un pare-feu ufw, mais la machine est joignable depuis Internet. Rappelez-vous : l'image fait partie de ce que vous publiez, et toute copie de l'image contient la clé.

Question de la grille : cochez TOUS les problèmes de sécurité réels de ces extraits.

Questionnaire de l'atelier

Huit questions tirées d'une réserve plus large, seuil de réussite 70 %. Il s'ouvre quand tous les points de contrôle du laboratoire sont réussis. Vous pouvez le repasser : le tirage change.

Un compte certifié est nécessaire

Les activités notées enregistrent des résultats à votre nom et servent de base à un titre. Elles exigent donc un dossier certifiant complet et un consentement en vigueur. Remplir le dossier ne vérifie pas votre identité ; le Secrétariat peut ensuite la vérifier (badge « Vérifié »).

Laboratoire autonome (hors du site)

Non noté en ligne : à réaliser sur votre machine et à publier sur votre dépôt Git.

À faire sur votre machine, hors du site. Ce laboratoire n'est pas noté en ligne : il est évalué par un pair qui reproduit votre réseau à partir du seul dépôt.

  1. Installez Docker et Compose en suivant la documentation Docker. Notez la version obtenue avec docker --version dans votre README : c'est une information à consigner, pas une valeur à copier d'ici.
  2. Conteneurisez un nœud de test de votre choix (ou le service fourni par la BAC) : image de base épinglée par empreinte, dépendances verrouillées, utilisateur sans privilèges, aucun secret dans le Dockerfile.
  3. Écrivez un docker-compose.yml à trois nœuds qui se découvrent par nom de service, avec un healthcheck et des volumes nommés. Publiez les ports RPC sur 127.0.0.1 seulement.
  4. Prouvez la persistance : laissez le réseau produire des blocs, relevez la hauteur, faites down puis up, et notez la hauteur de reprise. Puis faites down -v et notez ce qui change (sur un réseau de test jetable : jamais down -v sur un vrai validateur sans sauvegarde de son état de signature).
  5. Réduisez la taille de l'image de moitié sans perdre de fonctionnalité (base plus petite, construction en plusieurs étapes comme dans la leçon 4, .dockerignore). Mesurez avant et après avec docker images et documentez la méthode.
  6. Demandez à un pair de cloner le dépôt sur une machine vierge et de tout relancer en suivant seulement le README. Corrigez le README selon ses blocages.

À retenir

  • Reproductible veut dire épinglé : image de base par empreinte, dépendances verrouillées, version explicite plutôt que latest.
  • Dans un réseau Compose, les conteneurs se joignent par nom de service ; 127.0.0.1 y désigne le conteneur lui-même.
  • depends_on règle l'ordre de démarrage, pas la disponibilité ; la disponibilité se vérifie avec un healthcheck.
  • Les données utiles vivent sur un volume : down les garde, down -v les efface, et un volume n'est pas une sauvegarde.
  • Aucune clé dans l'image ; utilisateur sans privilèges, base minimale et ports limités à 127.0.0.1 quand l'hôte seul en a besoin.

Idées fausses courantes

  • Idée reçue : Écrire FROM nom:latest suffit à avoir toujours la même image.

    En réalité : latest est une étiquette ordinaire que l'éditeur déplace. Seule l'empreinte sha256 désigne un contenu précis, et même elle fige une éventuelle faille connue.

  • Idée reçue : Un conteneur isolé est automatiquement sûr, même avec une clé dans l'image.

    En réalité : Le conteneur partage le noyau de l'hôte, et une clé dans l'image se retrouve dans chaque copie. Isolation et secrets sont deux sujets distincts.

  • Idée reçue : docker compose down -v est la même commande que down, en plus bavarde.

    En réalité : L'option -v supprime les volumes nommés déclarés dans le fichier : les données de chaîne disparaissent et le nœud repart de zéro.

Glossaire

Image
Paquet en lecture seule (fichiers, bibliothèques, commande de départ) à partir duquel on démarre des conteneurs.
Conteneur
Programme lancé comme processus isolé à partir d'une image, avec ses propres fichiers et sa vue du réseau, sur le noyau de l'hôte.
Empreinte (digest)
Hachage SHA-256 du manifeste d'une image : il désigne un contenu précis et ne peut pas être déplacé comme une étiquette.
Volume
Espace de stockage géré hors du conteneur, qui survit à sa suppression ; nommé (géré par Docker) ou lié à un dossier de l'hôte.
Healthcheck
Commande que Docker exécute régulièrement pour savoir si un service répond ; elle permet d'attendre qu'un service soit prêt.