## Introduction

L'architecture des Pods Kubernetes peut sembler abstraite tant que vous ne l'avez pas reliée à de vraies commandes kubectl et à des comportements observables du cluster. Ce guide s'adresse aux développeurs, aux consultants DevOps et aux équipes techniques de startups qui souhaitent comprendre de manière opérationnelle les composants d'un Pod, le flux de données, les design patterns et les opérations quotidiennes. Plutôt que de s'arrêter à la théorie, chaque section associe les concepts à des commandes, des sorties attendues, des signes de défaillance et des décisions de récupération.

L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des variables à la place des secrets, vérifier les résultats et documenter comment récupérer si l'état attendu n'est pas atteint. À la fin, vous serez capable d'inspecter un Pod, de raisonner sur son cycle de vie et de résoudre les défaillances courantes sans deviner.

## Inventaire de la version et de l'environnement

Avant de toucher à un Pod, vous devez avoir une vision claire de votre environnement. Commencez par identifier la version de Kubernetes installée, la topologie de déploiement, les prérequis et le composant exact inspecté. Ce contexte évite d'appliquer des conseils destinés à une version ou une configuration différente.

Exécutez d'abord ces commandes en lecture seule. Elles ne modifient rien et vous donnent une base de référence :

```bash
kubectl version --short
kubectl cluster-info
kubectl get nodes -o wide
```

La sortie attendue comprend la version du client et du serveur, le point de terminaison du plan de contrôle et l'état des nœuds. Par exemple, un nœud sain affiche `Ready` dans la colonne STATUS. Si vous voyez `NotReady`, examinez les conditions du nœud avec `kubectl describe node <nom-du-nœud>` avant de résoudre les problèmes de Pods sur ce nœud.

Ensuite, confirmez votre contexte actuel et les Pods déjà en cours d'exécution :

```bash
kubectl config current-context
kubectl get pods -o wide
```

L'option `-o wide` ajoute les informations sur le nœud et l'adresse IP, ce qui est précieux pour tracer les chemins de communication et repérer les problèmes d'ordonnancement.

Pour inspecter un Pod en profondeur, utilisez :

```bash
kubectl describe pod <nom>
```

Cette seule commande fait apparaître les événements, l'état des conteneurs, les demandes de ressources et les détails des montages. Recherchez les messages `FailedScheduling`, `CrashLoopBackOff` ou `OOMKilled`, qui pointent vers des problèmes spécifiques.

Si un conteneur est en boucle de crash, récupérez les journaux du conteneur précédent même si l'instance actuelle n'a pas encore produit de sortie :

```bash
kubectl logs <nom> --previous
```

Cela révèle souvent l'erreur de démarrage qui a provoqué le crash.

Enfin, ne supposez jamais qu'un déploiement a réussi. Vérifiez avec :

```bash
kubectl rollout status deployment/<nom>
```

Un déploiement réussi affiche `deployment "<nom>" successfully rolled out`. S'il se bloque ou signale une erreur, inspectez les Pods et les événements du déploiement.

Gardez les tests locaux légers. Appliquez un seul manifeste, inspectez les ressources générées et vérifiez le trafic avec `kubectl port-forward` ou un service de type local avant de passer à un équilibreur de charge cloud ou à un contrôleur d'entrée.

## Composants d'un Pod et leurs rôles

Un Pod est la plus petite unité déployable dans Kubernetes. Il exécute un ou plusieurs conteneurs qui partagent le même espace de noms réseau, les mêmes volumes de stockage et le même cycle de vie. Comprendre chaque composant vous aide à concevoir et à déboguer efficacement les Pods.

**Conteneur principal** : La charge de travail principale. Il exécute généralement votre application. Il a un nom, une image, des ports et des limites de ressources.

**Conteneurs d'initialisation (init containers)** : Ils s'exécutent avant le démarrage des conteneurs principaux. Ils préparent l'environnement, par exemple en attendant une dépendance, en configurant des paramètres ou en migrant une base de données. Les conteneurs d'initialisation doivent se terminer avec succès pour que le Pod démarre.

**Conteneurs éphémères** : Ajoutés dynamiquement pour déboguer un Pod en cours d'exécution sans le redémarrer. Utiles lorsqu'un conteneur ne dispose pas de shell ou d'outils de débogage.

**Conteneurs sidecar** : Conteneurs secondaires qui s'exécutent aux côtés du conteneur principal, souvent pour la journalisation, le proxy ou la synchronisation de données. Ils partagent le même réseau et le même stockage.

**Conteneur pause** : Un conteneur d'infrastructure caché qui crée les espaces de noms partagés (réseau, IPC, PID) pour le Pod. Il est transparent pour les utilisateurs mais essentiel pour l'isolation du Pod.

Pour voir ces conteneurs en action, inspectez un Pod en cours d'exécution :

```bash
kubectl describe pod <nom>
```

Les sections `Containers`, `Init Containers` et `Conditions` listent chaque composant et son état. Vous pouvez également obtenir les noms des conteneurs avec :

```bash
kubectl get pod <nom> -o jsonpath='{.spec.containers[*].name}'
```

Pour un Pod avec un conteneur d'initialisation, la sortie pourrait être `init-myservice main-app`. Si le conteneur d'initialisation est encore en cours d'exécution, le conteneur principal n'a pas démarré.

## Flux de données et réseau d'un Pod

Chaque Pod reçoit une adresse IP unique. Les conteneurs à l'intérieur d'un Pod partagent cette IP et peuvent communiquer entre eux via `localhost`. Ils peuvent également partager des fichiers via des volumes et communiquer par des mécanismes inter-processus standard.

Les Pods communiquent entre eux sur les nœuds via le réseau du cluster. Par défaut, le réseau est plat : chaque Pod peut joindre tous les autres Pods sans traduction d'adresses réseau (NAT). Cette conception simplifie la découverte de services et l'équilibrage de charge.

Pour observer le réseau d'un Pod en action :

1. Obtenez l'IP du Pod :
   ```bash
   kubectl get pod <nom> -o wide
   ```
   Notez l'IP sous la colonne `IP`.

2. Testez la connectivité depuis un autre Pod :
   ```bash
   kubectl run -it --rm debug --image=busybox -- sh
   wget -qO- http://<ip-du-pod>:<port>
   ```
   Si la requête renvoie la réponse de votre application, le chemin réseau fonctionne.

3. Utilisez un Service pour exposer le Pod :
   ```yaml
   apiVersion: v1
   kind: Service
   metadata:
     name: my-service
   spec:
     selector:
       app: my-app
     ports:
       - port: 80
         targetPort: 8080
   ```
   Appliquez-le avec `kubectl apply -f service.yaml`. Testez ensuite l'IP du Service avec le même Pod de débogage.

Lorsqu'un Pod est supprimé et recréé, son IP change. Les Services fournissent une IP virtuelle stable et un nom DNS, de sorte que les clients n'ont jamais besoin de suivre les IP individuelles des Pods.

Le flux de données des volumes fonctionne de manière similaire. Les conteneurs d'un même Pod peuvent monter le même volume. Par exemple, un sidecar peut lire les fichiers journaux écrits par le conteneur principal et les transférer vers un système externe. Utilisez un volume `emptyDir` pour un stockage partagé temporaire ou un `persistentVolumeClaim` pour des données durables.

## Design patterns de Pods

Plusieurs design patterns de Pods aident à résoudre des problèmes courants. Choisissez le pattern en fonction des besoins de votre application.

**Pod à conteneur unique** : Le pattern le plus simple. Un conteneur exécute l'application. Utilisez-le sauf si vous avez un besoin clair de plusieurs conteneurs.

**Pattern sidecar** : Un conteneur secondaire augmente l'application principale. Les utilisations courantes incluent l'expédition de journaux, les agents de surveillance ou les rechargeurs de configuration. Le sidecar partage le même cycle de vie et les mêmes ressources que le conteneur principal.

Exemple de sidecar pour l'acheminement des journaux :
```yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-with-sidecar
spec:
  containers:
  - name: main-app
    image: myapp:1.0
    volumeMounts:
    - name: logs
      mountPath: /var/log/app
  - name: log-shipper
    image: fluentd:latest
    volumeMounts:
    - name: logs
      mountPath: /var/log/app
  volumes:
  - name: logs
    emptyDir: {}
```

**Pattern ambassadeur** : Un conteneur proxy gère la communication externe. Il abstrait les complexités des protocoles réseau, des tentatives et de l'authentification pour l'application principale. Utile pour se connecter à des bases de données ou des API externes.

**Pattern adaptateur** : Un conteneur transforme la sortie de l'application principale dans un format attendu par un système externe. Par exemple, un adaptateur de métriques peut convertir des métriques personnalisées au format Prometheus.

**Pattern conteneur d'initialisation** : Utilisez des conteneurs d'initialisation pour configurer l'environnement avant le démarrage de l'application principale. Exemple : attendre qu'une base de données soit joignable :
```yaml
initContainers:
- name: wait-for-db
  image: busybox
  command: ['sh', '-c', 'until nc -z db 5432; do sleep 1; done']
```

Ce pattern évite une logique de démarrage complexe dans l'application principale et garantit que les dépendances sont prêtes.

## Erreurs courantes et comment les éviter

Même les opérateurs expérimentés commettent ces erreurs. Les reconnaître tôt permet d'économiser des heures de débogage.

**Ignorer les demandes et les limites de ressources**. Sans demandes, le planificateur peut placer trop de Pods sur un nœud, provoquant une famine de CPU ou de mémoire. Sans limites, un processus incontrôlé peut faire planter le nœud. Définissez toujours des valeurs réalistes basées sur l'utilisation observée.

Exemple :
```yaml
resources:
  requests:
    cpu: "100m"
    memory: "128Mi"
  limits:
    cpu: "500m"
    memory: "256Mi"
```

Si vous voyez `OOMKilled` dans `kubectl describe pod`, votre limite de mémoire est trop basse. Ajustez et redémarrez.

**Ne pas utiliser correctement les sondes de vivacité et de préparation**. Une sonde de vivacité qui échoue trop rapidement peut redémarrer un conteneur sain pendant le démarrage. Une sonde de préparation trop permissive envoie du trafic à un conteneur qui n'est pas prêt. Configurez des délais raisonnables.

Exemple :
```yaml
livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 15
  periodSeconds: 10
readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5
```

**Coder en dur la configuration ou les secrets dans les spécifications du Pod**. Cela fait fuiter les valeurs sensibles et rend les mises à jour pénibles. Utilisez plutôt des ConfigMaps et des Secrets montés comme volumes ou variables d'environnement.

**Supposer qu'une IP de Pod est stable**. Les IP des Pods changent au redémarrage. Exposez toujours les Pods via un Service et référez-vous au nom DNS du Service.

**Ne pas vérifier les événements du Pod avant de le supprimer**. Si un Pod échoue, inspectez d'abord `kubectl describe pod`. Les événements contiennent souvent la raison exacte, comme un échec de montage de volume ou une erreur d'extraction d'image.

**Exécuter plusieurs processus dans un conteneur sans superviseur**. Kubernetes s'attend à un processus par conteneur. Si vous avez besoin de plusieurs processus, répartissez-les dans des conteneurs séparés dans le même Pod ou utilisez un gestionnaire de processus comme `tini`.

## Vérification et diagnostic

Un dépannage efficace suit un chemin structuré. Commencez par la vue la plus globale et affinez.

**1. Vérifiez la santé globale du cluster :**
```bash
kubectl get nodes
kubectl get pods --all-namespaces
```
Si des nœuds sont `NotReady` ou des Pods bloqués en `Pending`, examinez-les en premier.

**2. Inspectez le Pod cible :**
```bash
kubectl describe pod <nom>
```
Concentrez-vous sur `Events`, `Conditions` et l'`State` des conteneurs. États courants : `Running`, `Waiting`, `Terminated`. Si `Waiting`, vérifiez `Reason` (par exemple, `ImagePullBackOff`, `CrashLoopBackOff`).

**3. Obtenez les journaux :**
```bash
kubectl logs <nom> -c <nom-du-conteneur>
```
Utilisez `--previous` si le conteneur a redémarré. Si les journaux sont vides, l'application peut ne pas produire de sortie sur stdout. Vérifiez si elle journalise dans un fichier à la place.

**4. Testez la connectivité réseau :**
Dans un Pod de débogage :
```bash
kubectl exec -it <nom-du-pod> -- sh
curl http://nom-du-service.namespace.svc.cluster.local:port
```
Si la résolution DNS échoue, vérifiez CoreDNS et les points de terminaison du Service.

**5. Vérifiez l'utilisation des ressources :**
```bash
kubectl top pod <nom>
```
Nécessite metrics-server. Une CPU ou une mémoire élevée peut indiquer une fuite ou une mauvaise configuration.

**6. Inspectez la configuration :**
```bash
kubectl get pod <nom> -o yaml
```
Recherchez des erreurs dans les variables d'environnement, les montages de volumes ou les étiquettes.

Documentez vos constatations au fur et à mesure. Notez l'heure, la commande, la sortie et votre interprétation. Ce journal devient précieux lors de l'examen d'un incident.

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

Les Pods échouent pour de nombreuses raisons. Voici les modes de défaillance les plus fréquents et les étapes de récupération.

**CrashLoopBackOff** : Le conteneur démarre et se termine de manière répétée, souvent en raison d'une erreur d'application ou d'une mauvaise configuration.
- **Diagnostic** : `kubectl describe pod <nom>` affiche `CrashLoopBackOff` dans les événements. `kubectl logs <nom> --previous` révèle le message d'erreur.
- **Récupération** : Corrigez l'erreur d'application ou la configuration, puis mettez à jour le déploiement. Atténuation temporaire : augmentez `failureThreshold` ou `initialDelaySeconds` si l'application a besoin de plus de temps pour démarrer.

**ImagePullBackOff** : Kubernetes ne peut pas extraire l'image du conteneur.
- **Diagnostic** : `kubectl describe pod` affiche `Failed to pull image`. La raison peut être un mauvais nom d'image, des identifiants manquants ou une indisponibilité du registre.
- **Récupération** : Vérifiez le nom et l'étiquette de l'image. Assurez-vous que les imagePullSecrets sont définis si nécessaire. Testez l'extraction localement avec `docker pull`.

**OOMKilled** : Le conteneur a dépassé sa limite de mémoire.
- **Diagnostic** : `kubectl describe pod` affiche `OOMKilled` dans le dernier état du conteneur.
- **Récupération** : Augmentez la limite de mémoire si l'application en a légitimement besoin de plus. Enquêtez sur les fuites de mémoire. Définissez une demande plus élevée pour garantir que le planificateur le place sur un nœud avec suffisamment de capacité.

**Pod en attente (Pending)** : Le Pod ne peut pas être ordonnancé, généralement en raison de ressources insuffisantes ou de règles d'affinité de nœud.
- **Diagnostic** : `kubectl describe pod` affiche `FailedScheduling` avec des raisons comme `Insufficient cpu` ou `node(s) didn't match`.
- **Récupération** : Réduisez les demandes de ressources, faites évoluer les nœuds ou ajustez les affinités/taints.

**Échec de la sonde de préparation** : Le Pod est en cours d'exécution mais ne reçoit pas de trafic.
- **Diagnostic** : `kubectl get endpoints <nom-du-service>` n'affiche aucun point de terminaison pour le Pod.
- **Récupération** : Corrigez le chemin, le port ou le timing de la sonde de préparation.

**Éviction** : Le nœud est sous pression et évince les Pods.
- **Diagnostic** : `kubectl describe node` affiche `MemoryPressure` ou `DiskPressure`.
- **Récupération** : Libérez des ressources sur le nœud, ajoutez des nœuds ou ajustez les priorités des Pods.

Vérifiez toujours la récupération. Après avoir apporté une modification, surveillez la stabilisation du Pod :
```bash
kubectl rollout status deployment/<nom>
kubectl get pods -w
```
L'option `-w` surveille les changements, ce qui vous permet de voir le Pod passer à l'état `Running`.

## Liste de contrôle des opérations

Utilisez cette liste de contrôle pour des opérations de Pod sûres. Elle met l'accent sur l'observation, les changements minimaux et la vérification.

- [ ] **Confirmez le contexte du cluster** : Exécutez `kubectl config current-context` pour vous assurer d'être sur le bon cluster.
- [ ] **Vérifiez la santé des nœuds** : `kubectl get nodes` pour voir si les nœuds sont `Ready`.
- [ ] **Inspectez l'état du Pod** : `kubectl get pods -o wide` et `kubectl describe pod <nom>` pour le Pod cible.
- [ ] **Examinez les journaux** : `kubectl logs <nom> --previous` si redémarré, sinon `kubectl logs <nom>`.
- [ ] **Vérifiez l'utilisation des ressources** : `kubectl top pod <nom>` si metrics-server est disponible.
- [ ] **Vérifiez les points de terminaison du Service** : `kubectl get endpoints <nom-du-service>` pour confirmer que le Pod est sélectionné.
- [ ] **Effectuez une modification à la fois** : Mettez à jour uniquement le champ nécessaire dans le manifeste. Évitez les modifications en masse.
- [ ] **Appliquez la modification** : `kubectl apply -f manifeste-mis-à-jour.yaml`. Utilisez d'abord `--dry-run=client` pour voir ce qui changerait.
- [ ] **Surveillez le déploiement** : `kubectl rollout status deployment/<nom>` et `kubectl get pods -w`.
- [ ] **Testez l'application** : Utilisez `kubectl port-forward` pour accéder directement à un Pod, ou testez le point de terminaison du Service.
- [ ] **Mettez à jour la documentation** : Enregistrez le changement, la raison et les étapes de vérification dans votre runbook.

Pour chaque décision majeure, attribuez un responsable unique. Par exemple, le responsable d'ingénierie est propriétaire des limites de ressources des Pods et les examine mensuellement. L'ingénieur DevOps est propriétaire des retours en arrière de déploiement et examine le processus après chaque incident. Réexaminez ces attributions au moins chaque trimestre pour vous assurer qu'elles conviennent toujours.

## Conclusion

L'architecture des Pods Kubernetes devient gérable lorsque vous la considérez comme un ensemble de composants observables et de modes de défaillance prévisibles. Ce guide a fourni des commandes et des patterns pratiques pour inspecter les Pods, comprendre leur flux de données, concevoir des Pods multi-conteneurs robustes et récupérer des défaillances courantes.

Commencez petit : choisissez une vérification à faible risque de cet article, exécutez-la sur votre cluster actuel et comparez la sortie avec les signaux attendus décrits. Par exemple, exécutez `kubectl describe pod <nom>` sur un Pod sain et notez les conditions et les événements. Introduisez ensuite une défaillance contrôlée dans un espace de noms de test et entraînez-vous à la récupération.

Un flux de travail technique fiable rend la défaillance visible, protège les valeurs sensibles, limite les changements à la ressource prévue et définit la vérification de la récupération avant qu'un incident ne force la décision. Avec ces pratiques, vous pouvez opérer des Pods Kubernetes avec confiance et sécurité.