## Introduction

Déboguer des conteneurs Docker en production présente des défis uniques : les conteneurs sont éphémères, souvent immuables, et étroitement intégrés aux couches d'orchestration et de réseau. Une approche méthodique permet d'éviter des interruptions coûteuses et d'accélérer l'analyse des causes profondes. Cet article fournit une liste de contrôle pratique pour le débogage des conteneurs Docker en production, couvrant l'inventaire de l'environnement, la configuration sûre, les diagnostics, la récupération après échec et une liste de contrôle opérationnelle reproductible. En suivant ces étapes, les développeurs et les équipes DevOps peuvent réduire le temps moyen de récupération (MTTR) et maintenir la stabilité du système. Une liste de contrôle opérationnelle claire sépare l'investigation des suppositions, réduisant le retravail et garantissant des résultats de débogage cohérents. Commencez par un problème pilote étroit et mesurable, facile à inspecter localement avant d'étendre vos efforts de débogage.

## Inventaire des versions et de l'environnement

Avant de plonger dans le débogage, établissez un instantané précis de l'environnement. Cet inventaire aide à reproduire les problèmes et fournit une base de référence pour les changements.

### Version de Docker et système d'exploitation hôte

Exécutez `docker version` et `docker info` sur l'hôte concerné. Notez les versions du client et du serveur, le pilote de stockage et la version du noyau. Par exemple :

```bash
$ docker version --format '{{.Server.Version}}'
20.10.12
```
Sortie attendue : la version du moteur Docker. Si la version est obsolète, une mise à niveau peut résoudre des bogues connus. Enregistrez le système d'exploitation hôte avec `cat /etc/os-release` ou `uname -a`.

### Topologie des conteneurs et orchestration

Identifiez si les conteneurs sont gérés par Docker Compose, Swarm ou Kubernetes. Pour les conteneurs autonomes, utilisez `docker ps -a` pour lister tous les conteneurs et leur statut. Pour les environnements orchestrés, récupérez l'état du cluster avec les outils appropriés (par exemple, `kubectl get pods` pour Kubernetes). Capturez l'ID de l'image et les étiquettes du conteneur :

```bash
$ docker inspect -f '{{.Config.Image}} {{.Image}}' <container_id>
nginx:1.21 sha256:2bcabc23b45489fb0885d69a06ba1d648aeda973fae7bb981bafbb884165e514
```
Cela montre le nom de l'image et son empreinte, ce qui est crucial pour revenir à une image connue et stable.

### Prérequis réseau et ressources

Documentez les modes réseau, les mappages de ports et les limites de ressources. Utilisez `docker inspect` pour extraire la configuration détaillée :

```bash
$ docker inspect -f '{{json .NetworkSettings.Networks}}' <container_id> | python -m json.tool
```
Vérifiez les limites de CPU et de mémoire avec `docker stats --no-stream <container_id>` pour voir si le conteneur atteint sa limite. Vérifiez également que les journaux sont capturés par le pilote de journalisation (par exemple, `json-file`, `journald`).

## Chemin de configuration sûr

Le débogage nécessite souvent des modifications de configuration. Pour éviter de causer d'autres problèmes, implémentez les changements de manière limitée et réversible.

### Utiliser des surcharges spécifiques à l'environnement

Ne modifiez jamais directement la configuration d'un conteneur en cours d'exécution. Utilisez plutôt des variables d'environnement ou des fichiers de configuration qui peuvent être versionnés et restaurés. Par exemple, pour changer le niveau de journalisation d'un conteneur, redémarrez-le avec une variable d'environnement mise à jour :

```bash
$ docker run -d --name myapp -e LOG_LEVEL=debug myapp:latest
```
Cette commande démarre un nouveau conteneur avec le niveau de journalisation debug. L'ancien conteneur peut être arrêté et conservé pour comparaison.

### Activer la journalisation de débogage en toute sécurité

Si l'application prend en charge la journalisation de débogage, activez-la temporairement via une variable d'environnement ou un fichier de configuration. Pour le démon Docker lui-même, activez le mode débogage en éditant `/etc/docker/daemon.json` et en redémarrant le démon :

```json
{
  "debug": true
}
```
Après le redémarrage, vérifiez que les journaux de débogage apparaissent dans le journal du démon (par exemple, `journalctl -u docker.service -f`). Sachez que la journalisation de débogage augmente la verbosité et peut affecter les performances ; désactivez-la après le dépannage.

### Éviter le mode privilégié et les modifications de l'hôte

Lorsque vous devez inspecter le trafic réseau ou les appels système, utilisez des outils spécialisés qui ne nécessitent pas d'exécuter le conteneur avec `--privileged`. Par exemple, `nsenter` permet d'exécuter des commandes dans les espaces de noms du conteneur sans modifier ses privilèges. Pour obtenir un shell dans un conteneur à des fins de débogage, préférez `docker exec` à `docker attach` pour éviter d'interférer avec le processus principal du conteneur.

## Vérification et diagnostics

Cette section fournit des vérifications concrètes et des résultats attendus pour faciliter le débogage.

### Vérifier la santé du conteneur

Si un conteneur a une vérification de santé définie, interrogez son état :

```bash
$ docker inspect --format='{{.State.Health.Status}}' <container_id>
healthy
```
Sortie attendue : `healthy` ou `unhealthy`. Si le conteneur est malsain, inspectez le journal de vérification de santé :

```bash
$ docker inspect --format='{{json .State.Health}}' <container_id> | python -m json.tool
```
Cela montre la dernière sortie de la vérification de santé et le code de sortie.

### Examiner les journaux

Utilisez `docker logs` pour voir la sortie du conteneur. Pour un conteneur avec beaucoup de journaux, utilisez `--since` et `--until` pour filtrer par heure, et `--tail` pour limiter les lignes. Exemple :

```bash
$ docker logs --since=2023-10-01T10:00:00 --until=2023-10-01T11:00:00 --tail=100 <container_id>
```
Sortie attendue : lignes de journal récentes. Recherchez les traces de pile d'erreurs, les délais d'attente ou les échecs de connexion.

### Diagnostiquer la connectivité réseau

Si le conteneur ne peut pas atteindre les services externes, testez la connectivité depuis l'intérieur du conteneur :

```bash
$ docker exec -it <container_id> bash
root@container:/# curl -v https://example.com
```
Sortie attendue : en-têtes de réponse HTTP. Si `curl` échoue, vérifiez la résolution DNS (`nslookup example.com`) et le routage (`ip route`). Inspectez également les règles `iptables` sur l'hôte (nécessite root sur l'hôte).

### Inspecter les processus et l'utilisation des ressources

Utilisez `docker top <container_id>` pour voir les processus en cours d'exécution dans le conteneur. Comparez avec les processus hôtes en utilisant `ps aux | grep <process>`. Pour vérifier les fuites de mémoire, surveillez la RSS au fil du temps avec `docker stats`. Une utilisation de mémoire en constante augmentation peut indiquer une fuite.

### Analyser les changements du système de fichiers

Pour voir quels fichiers ont changé depuis le démarrage du conteneur, comparez le système de fichiers du conteneur avec l'image en utilisant `docker diff <container_id>`. Cela montre les fichiers ajoutés (A), modifiés (C) ou supprimés (D). Exemple :

```bash
$ docker diff <container_id>
C /var/log/app.log
A /tmp/newfile.txt
D /etc/oldconfig.conf
```
Cela est utile pour identifier les modifications non intentionnelles ou confirmer que les changements de configuration ont été appliqués.

## Modes de défaillance et récupération

Même avec un débogage minutieux, des défaillances peuvent survenir. Préparez-vous aux modes de défaillance courants et sachez comment récupérer.

### Boucle de redémarrage du conteneur

Si un conteneur démarre et se termine à plusieurs reprises, inspectez son code de sortie et ses journaux :

```bash
$ docker inspect -f '{{.State.ExitCode}} {{.State.Error}}' <container_id>
```
Codes de sortie courants : 1 (erreur d'application), 137 (SIGKILL, souvent OOM), 143 (SIGTERM, terminaison gracieuse). Pour empêcher temporairement le redémarrage, arrêtez le conteneur : `docker stop <container_id>`. Ensuite, exécutez le conteneur au premier plan avec `--rm` pour voir la sortie directement :

```bash
$ docker run --rm -it --name debug <image> bash
```
Cela donne un shell interactif pour tester le démarrage manuellement.

### Mémoire insuffisante (OOM)

Si l'hôte manque de mémoire, le noyau peut tuer un processus de conteneur. Vérifiez `dmesg | grep -i oom` sur l'hôte. Pour prévenir l'OOM, augmentez la limite de mémoire du conteneur : `docker update --memory 512m <container_id>`. Analysez également les modèles d'utilisation de la mémoire de l'application.

### Échec de communication réseau

Si le conteneur ne peut pas se connecter à d'autres conteneurs ou services externes, vérifiez la configuration réseau. Pour les réseaux ponts définis par l'utilisateur, assurez-vous que les conteneurs sont attachés au bon réseau : `docker network inspect <network_name>`. Vérifiez les règles de pare-feu : `iptables -L -n -v | grep DOCKER`. Revenez en arrière en annulant les modifications réseau récentes ou en redémarrant le démon Docker : `systemctl restart docker`.

### Retour en arrière de la configuration

Gardez toujours les configurations précédentes dans le contrôle de version. Si un changement de configuration cause des problèmes, revenez à la dernière version connue et stable et redémarrez le conteneur. Pour les problèmes liés à l'image, revenez à une étiquette d'image précédente :

```bash
$ docker run -d --name myapp_rollback myapp:1.0.2
```
Ensuite, mettez à jour le service ou l'équilibreur de charge pour pointer vers le nouveau conteneur.

### Perte ou corruption de données

Si un volume est corrompu, restaurez à partir des sauvegardes. Vérifiez régulièrement l'intégrité des sauvegardes. Pour les données critiques, utilisez une procédure de migration ou de restauration de base de données. Testez les exercices de récupération dans un environnement de préproduction.

## Pièges courants et comment les éviter

Même les équipes expérimentées font des erreurs lors du débogage de conteneurs en production. Voici les pièges les plus courants, pourquoi ils surviennent et comment les éviter ou s'en remettre.

### Piège 1 : Modifier directement un conteneur en cours d'exécution

**Pourquoi cela arrive :** Il semble rapide d'utiliser `docker exec` dans un conteneur et de modifier un fichier de configuration ou d'installer un paquet pour tester un correctif.
**Risque :** Les modifications sont perdues lorsque le conteneur redémarre, et vous avez maintenant une configuration non reproductible.
**Comment éviter :** Effectuez toujours les modifications via une reconstruction d'image, des variables d'environnement ou des fichiers de configuration montés. Si vous devez faire un changement d'urgence, documentez-le et créez immédiatement un correctif approprié dans votre pipeline de construction.

### Piège 2 : Ignorer les limites de ressources

**Pourquoi cela arrive :** Les développeurs se concentrent souvent sur les erreurs d'application et négligent les limites de ressources des conteneurs.
**Risque :** Un conteneur atteignant sa limite de mémoire peut être tué par le tueur OOM, provoquant des redémarrages inexpliqués. La limitation du CPU peut faire paraître l'application bloquée.
**Comment éviter :** Définissez des limites de ressources appropriées dans votre manifeste de déploiement. Surveillez régulièrement `docker stats`. Lors du débogage, vérifiez toujours si le conteneur est proche de sa limite.

### Piège 3 : Se fier à l'étiquette `latest`

**Pourquoi cela arrive :** Utiliser `latest` est pratique pendant le développement.
**Risque :** En production, `latest` peut pointer vers une image différente de celle testée, entraînant un comportement inattendu et rendant les retours en arrière difficiles.
**Comment éviter :** Utilisez toujours des étiquettes de version explicites ou des empreintes d'image en production. Par exemple, utilisez `myapp:1.2.3` ou `myapp@sha256:...`.

### Piège 4 : Négliger la configuration de la journalisation

**Pourquoi cela arrive :** Les équipes supposent que les journaux sont capturés correctement.
**Risque :** Si le pilote de journalisation est mal configuré ou si l'espace disque est épuisé, vous perdez la visibilité au moment où vous en avez le plus besoin.
**Comment éviter :** Vérifiez le pilote de journalisation avec `docker info`. Configurez la rotation des journaux pour éviter l'épuisement du disque. Utilisez un système d'agrégation de journaux centralisé.

### Piège 5 : Exécuter des conteneurs en tant que root

**Pourquoi cela arrive :** De nombreuses images de base utilisent root par défaut pour simplifier.
**Risque :** Un conteneur compromis donne à un attaquant un accès root à l'hôte.
**Comment éviter :** Spécifiez un utilisateur non root dans votre Dockerfile (directive `USER`) et assurez-vous que votre application n'a pas besoin de root. Utilisez le drapeau `--user` de Docker si nécessaire.

## Liste de contrôle des opérations

Utilisez la liste de contrôle suivante pour un débogage systématique et des opérations continues. Cette liste aide les équipes à transformer les défis de débogage en tâches reproductibles et mesurables. Attribuez un seul responsable pour chaque étape et définissez une cadence de revue (par exemple, hebdomadaire pour la surveillance, mensuelle pour la revue de la liste).

| Étape | Action | Responsable (exemple) | Vérification | Fréquence |
|-------|--------|----------------------|--------------|-----------|
| 1 | Enregistrer les détails de l'environnement (version Docker, OS hôte, orchestration) | Priya Shah, ingénieure DevOps | Sortie de `docker version` et `docker info` capturée | À chaque incident |
| 2 | Identifier le conteneur défaillant et son objectif | Ingénieur d'astreinte | `docker ps -a` montre le statut | À chaque incident |
| 3 | Examiner les journaux du conteneur pour détecter les erreurs | Ingénieur d'astreinte | `docker logs --tail=100` ne montre aucune erreur inattendue | À chaque incident |
| 4 | Vérifier l'état de santé du conteneur | Ingénieur d'astreinte | `docker inspect --format='{{.State.Health.Status}}'` renvoie healthy | À chaque incident |
| 5 | Tester la connectivité réseau depuis l'intérieur du conteneur | Spécialiste réseau (si nécessaire) | `docker exec <container_id> curl -v <url>` réussit | Lorsque des problèmes réseau sont suspectés |
| 6 | Inspecter l'utilisation des ressources (CPU, mémoire, E/S disque) | Priya Shah, ingénieure DevOps | `docker stats --no-stream` montre une utilisation inférieure à 80 % | Hebdomadaire |
| 7 | Comparer le système de fichiers du conteneur à l'image | Ingénieur d'astreinte | `docker diff` ne montre que les changements attendus | Lorsque des changements sont suspectés |
| 8 | Reproduire le problème avec une configuration minimale | Responsable développement (ex. Alex Chen) | Le conteneur s'exécute avec `--rm` et un environnement minimal sans erreur | Pendant l'analyse des causes profondes |
| 9 | Appliquer le correctif de manière limitée (nouveau conteneur, surcharge d'environnement) | Responsable développement | `docker run` avec une configuration mise à jour réussit | Pendant le correctif |
| 10 | Surveiller après le correctif et documenter la cause profonde | Ingénieur d'astreinte | `docker stats` et les journaux ne montrent aucune erreur pendant 24 heures | Post-correctif et revue |

### Revue régulière des opérations

Effectuez des revues régulières de la santé des conteneurs, de la rotation des journaux et des alertes de ressources. Configurez une surveillance avec Prometheus et Grafana, ou utilisez la commande intégrée `docker stats` avec un script de collecte. Définissez des seuils d'alerte pour le CPU, la mémoire et les redémarrages. La liste de contrôle des opérations elle-même doit être examinée mensuellement par le responsable de l'équipe DevOps pour intégrer les nouveaux apprentissages.

## Conclusion

Le débogage de conteneurs Docker en production exige une approche systématique. Cette liste de contrôle fournit un cadre pratique : commencez par un inventaire de l'environnement, apportez des modifications de configuration limitées, utilisez des commandes de diagnostic concrètes, anticipez les modes de défaillance, suivez une liste de contrôle opérationnelle reproductible et évitez les pièges courants. En adoptant ces pratiques, les équipes peuvent réduire les temps d'arrêt et améliorer la fiabilité. N'oubliez pas de garder une focalisation étroite et mesurable pour chaque session de débogage, de toujours vérifier les correctifs avec des contrôles observables et d'attribuer une responsabilité claire pour chaque étape. Révisez et mettez à jour régulièrement vos procédures de débogage pour couvrir de nouveaux scénarios et technologies de conteneurs.

---

Remarque : Toutes les commandes et sorties sont illustratives. Adaptez-les à votre environnement spécifique et à votre moteur de conteneurs.