Comment arrêter gracieusement un conteneur Docker à long terme

DockerBeginner
Pratiquer maintenant

Introduction

Les conteneurs Docker sont largement utilisés pour exécuter diverses applications et services, mais la gestion du cycle de vie des conteneurs à long terme peut être un défi. Ce tutoriel vous guidera tout au long du processus d'arrêt gracieux d'un conteneur Docker à long terme, garantissant une transition fluide et évitant toute perte de données potentielle ou tout problème d'application.

Comprendre le cycle de vie des conteneurs Docker

Les conteneurs Docker ont un cycle de vie bien défini que les développeurs doivent comprendre pour gérer efficacement leurs applications. Cette section fournira une vue d'ensemble du cycle de vie des conteneurs Docker, y compris les différents états par lesquels un conteneur peut passer et les concepts clés qui sous-tendent ce cycle de vie.

États des conteneurs Docker

Les conteneurs Docker peuvent exister dans plusieurs états différents au cours de leur vie :

  1. Créé (Created): Un conteneur a été créé mais n'a pas été démarré.
  2. En cours d'exécution (Running): Le conteneur exécute actuellement son processus principal.
  3. En pause (Paused): Le processus principal du conteneur a été mis en pause, mais le conteneur est toujours en cours d'exécution.
  4. Arrêté (Stopped): Le processus principal du conteneur a été arrêté.
  5. Redémarrage en cours (Restarting): Le conteneur est actuellement en train de redémarrer.
  6. Terminé (Exited): Le conteneur a été arrêté et son processus principal a terminé son exécution.

Il est important de comprendre ces états, car ils déterminent les actions que vous pouvez effectuer sur un conteneur et le comportement que vous pouvez attendre.

graph LR
    Created --> Running
    Running --> Paused
    Paused --> Running
    Running --> Stopped
    Stopped --> Running
    Stopped --> Exited

Événements du cycle de vie des conteneurs Docker

En plus des états des conteneurs, plusieurs événements clés se produisent au cours du cycle de vie d'un conteneur Docker :

  1. Création (Create): Un nouveau conteneur est créé.
  2. Démarrage (Start): Le processus principal du conteneur est démarré.
  3. Arrêt (Stop): Le processus principal du conteneur est arrêté.
  4. Redémarrage (Restart): Le conteneur est redémarré, soit manuellement, soit automatiquement.
  5. Mise en pause/Réactivation (Pause/Unpause): Le processus principal du conteneur est mis en pause ou réactivé.
  6. Terminaison forcée (Kill): Le processus principal du conteneur est terminé de force.
  7. Suppression (Delete): Le conteneur est supprimé du système.

Comprendre ces événements du cycle de vie est crucial pour gérer et automatiser le comportement de vos conteneurs Docker.

Gestion du cycle de vie des conteneurs avec l'interface de ligne de commande Docker (Docker CLI)

L'interface de ligne de commande Docker (Docker CLI) fournit plusieurs commandes pour interagir avec le cycle de vie des conteneurs :

  • docker create: Créer un nouveau conteneur.
  • docker start: Démarrer un conteneur arrêté.
  • docker stop: Arrêter un conteneur en cours d'exécution.
  • docker restart: Redémarrer un conteneur.
  • docker pause: Mettre en pause un conteneur en cours d'exécution.
  • docker unpause: Réactiver un conteneur mis en pause.
  • docker kill: Arrêter de force un conteneur en cours d'exécution.
  • docker rm: Supprimer un conteneur.

Ces commandes vous permettent de gérer le cycle de vie de vos conteneurs Docker de manière programmée et d'automatiser diverses tâches liées à la gestion des conteneurs.

Arrêt gracieux de conteneurs à long terme

Lorsque vous gérez des conteneurs Docker à long terme, il est important de vous assurer qu'ils sont arrêtés de manière gracieuse, permettant au processus principal du conteneur d'effectuer toutes les tâches de nettoyage ou d'arrêt nécessaires avant que le conteneur ne soit terminé. Cette section explorera les stratégies pour arrêter gracieusement des conteneurs Docker à long terme.

Comprendre le signal SIGTERM

Le mécanisme principal pour arrêter gracieusement un conteneur Docker consiste à envoyer le signal SIGTERM au processus principal du conteneur. Ce signal informe le processus qu'il devrait commencer le processus d'arrêt et effectuer toutes les tâches de nettoyage nécessaires.

Par défaut, lorsque vous exécutez la commande docker stop, Docker enverra le signal SIGTERM au processus principal du conteneur et attendra une période de délai d'attente par défaut (généralement 10 secondes) pour que le processus se termine. Si le processus ne se termine pas dans la période de délai d'attente, Docker enverra ensuite un signal SIGKILL, qui termine le processus de force.

Personnaliser le comportement d'arrêt

Pour personnaliser le comportement d'arrêt d'un conteneur Docker à long terme, vous pouvez utiliser les options suivantes :

  1. --stop-signal : Spécifiez un signal alternatif à envoyer au processus principal du conteneur lors de l'exécution de la commande docker stop. Par exemple, --stop-signal=SIGINT enverrait le signal SIGINT au lieu du signal SIGTERM par défaut.

  2. --stop-timeout : Spécifiez le nombre de secondes à attendre pour que le processus principal du conteneur se termine avant d'envoyer le signal SIGKILL. Par exemple, --stop-timeout=30 donnerait au processus 30 secondes pour se terminer avant d'être terminé de force.

Voici un exemple d'utilisation de ces options lors du démarrage d'un conteneur à long terme :

docker run -d --name my-app --stop-signal=SIGINT --stop-timeout=60 my-app:latest

Cette commande démarrerait un conteneur à long terme nommé my-app, et lorsque la commande docker stop serait exécutée, elle enverrait le signal SIGINT au processus principal du conteneur et attendrait jusqu'à 60 secondes pour qu'il se termine avant d'envoyer le signal SIGKILL.

Implémenter un arrêt gracieux dans votre application

Pour vous assurer que vos conteneurs Docker à long terme sont arrêtés de manière gracieuse, il est important de concevoir votre application pour gérer le signal SIGTERM (ou un signal alternatif) et effectuer toutes les tâches de nettoyage nécessaires avant de se terminer. Cela peut impliquer des tâches telles que :

  • Sauvegarder les données en mémoire dans un stockage persistant
  • Fermer les connexions réseau ou les connexions à la base de données
  • Vider les journaux ou autres sorties
  • Effectuer toutes les autres tâches de nettoyage spécifiques à l'application

En implémentant cette gestion de signal dans votre application, vous pouvez vous assurer que vos conteneurs sont arrêtés de manière contrôlée et prévisible, minimisant le risque de perte de données ou d'autres problèmes.

Stratégies pour un arrêt gracieux

Lorsqu'il s'agit d'arrêter gracieusement des conteneurs Docker à long terme, il existe plusieurs stratégies que vous pouvez employer pour garantir un processus d'arrêt fluide et contrôlé. Cette section explorera certaines des principales stratégies et meilleures pratiques pour un arrêt gracieux.

Gestion des signaux dans votre application

L'une des stratégies les plus importantes pour un arrêt gracieux consiste à implémenter la gestion des signaux dans votre application. Cela implique d'écrire un code qui écoute le signal SIGTERM (ou un signal alternatif) et effectue les tâches de nettoyage nécessaires avant que l'application ne se termine.

Voici un exemple de mise en œuvre de la gestion des signaux dans une application Node.js :

process.on("SIGTERM", () => {
  console.log("Received SIGTERM signal, starting graceful shutdown...");
  // Perform cleanup tasks, such as:
  // - Saving in-memory data to persistent storage
  // - Closing network connections or database connections
  // - Flushing logs or other output
  // - Performing any other application-specific cleanup tasks
  console.log("Graceful shutdown complete, exiting process.");
  process.exit(0);
});

En implémentant cette gestion des signaux, votre application peut s'assurer d'effectuer un arrêt contrôlé, minimisant le risque de perte de données ou d'autres problèmes.

Utilisation des vérifications de santé (healthcheck) et des sondes de vitalité (liveness probes)

Une autre stratégie pour un arrêt gracieux consiste à utiliser les fonctionnalités intégrées de vérification de santé et de sonde de vitalité de Docker. Ces fonctionnalités vous permettent de définir des vérifications que Docker peut utiliser pour déterminer l'état de santé et la disponibilité de votre conteneur.

Au cours du processus d'arrêt, vous pouvez utiliser ces sondes pour signaler à Docker que votre conteneur est en cours d'arrêt, permettant à Docker d'attendre la fin de l'arrêt avant de supprimer le conteneur.

Voici un exemple de configuration d'une vérification de santé et d'une sonde de vitalité dans votre conteneur Docker :

## Dockerfile
FROM node:14-alpine
COPY. /app
WORKDIR /app
CMD ["node", "server.js"]
HEALTHCHECK --interval=5s --timeout=3s \
  CMD curl -f http://localhost:3000/healthz || exit 1
LABEL com.labex.shutdown.signal=SIGINT
LABEL com.labex.shutdown.timeout=60

Dans cet exemple, l'instruction HEALTHCHECK définit une vérification de santé qui vérifie le point de terminaison /healthz du serveur web du conteneur. Les instructions LABEL définissent le signal à utiliser pour l'arrêt gracieux (SIGINT) et la période de délai d'attente (60 secondes).

Au cours du processus d'arrêt, votre application peut mettre à jour le point de terminaison de vérification de santé pour signaler que l'arrêt est en cours, permettant à Docker d'attendre la fin de l'arrêt avant de supprimer le conteneur.

Exploitation des frameworks d'orchestration

Si vous exécutez vos conteneurs Docker dans un framework d'orchestration comme Kubernetes ou Docker Swarm, vous pouvez exploiter les fonctionnalités intégrées de ces frameworks pour faciliter l'arrêt gracieux.

Par exemple, dans Kubernetes, vous pouvez utiliser le crochet preStop pour exécuter une commande ou un script qui effectue des tâches de nettoyage avant que le conteneur ne soit terminé. Vous pouvez également utiliser le champ terminationGracePeriodSeconds pour spécifier la durée pendant laquelle le conteneur devrait avoir le temps de s'arrêter gracieusement.

Voici un exemple de configuration d'un déploiement Kubernetes avec un crochet preStop et une période de terminaison gracieuse :

## kubernetes-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          image: my-app:latest
          ports:
            - containerPort: 3000
          lifecycle:
            preStop:
              exec:
                command: ["/app/shutdown.sh"]
          terminationGracePeriodSeconds: 60

Dans cet exemple, le crochet preStop exécute un script (/app/shutdown.sh) qui effectue toutes les tâches de nettoyage nécessaires avant que le conteneur ne soit terminé. Le champ terminationGracePeriodSeconds donne au conteneur 60 secondes pour s'arrêter gracieusement avant d'être terminé de force.

En exploitant ces fonctionnalités des frameworks d'orchestration, vous pouvez améliorer encore la fiabilité et la prévisibilité de votre processus d'arrêt de conteneur.

Résumé

Dans ce tutoriel, vous avez appris l'importance de comprendre le cycle de vie des conteneurs Docker et les stratégies pour arrêter gracieusement des conteneurs à long terme. En suivant les meilleures pratiques décrites, vous pouvez garantir un processus d'arrêt fluide et fiable, minimisant le risque de perte de données ou de perturbations d'application. Maîtriser l'art de l'arrêt gracieux de conteneurs est une compétence essentielle pour tout développeur ou administrateur Docker.