Apprenez à construire un pipeline CI/CD fiable pour les déploiements Kubernetes avec des vérifications de déploiement sécurisées, une validation automatisée et un retour arrière rapide. Ce guide couvre les prérequis, la mise en œuvre étape par étape, les commandes de vérification, les modes de défaillance et une liste de contrôle opérationnelle, avec des exemples pratiques que vous pouvez adapter à votre cluster.

## Introduction

Les déploiements Kubernetes gèrent le cycle de vie de vos pods d'application, offrant des mises à jour déclaratives, une mise à l'échelle et un retour arrière. Mais appliquer manuellement des fichiers YAML en espérant que tout se passe bien est risqué. L'automatisation CI/CD apporte la répétabilité, la sécurité et la rapidité à votre processus de publication. Ce guide vous accompagne dans la construction d'un pipeline CI/CD pratique pour les déploiements Kubernetes, de la configuration de l'environnement aux vérifications automatisées du déploiement et aux procédures de retour arrière. Vous apprendrez à vérifier le comportement de votre pipeline, à diagnostiquer les défaillances et à établir une liste de contrôle opérationnelle qui maintient la fiabilité de vos versions.

À la fin de ce guide, vous disposerez de :

- Un flux de travail de déploiement automatisé et versionné utilisant GitHub Actions (ou votre outil CI/CD préféré)
- Un déploiement Kubernetes configuré avec des mises à jour progressives, des sondes de santé et des limites de ressources
- Des étapes de vérification servant de barrières de qualité avant la promotion en production
- Un plan documenté de récupération en cas d'échec et de retour arrière
- Une liste de contrôle opérationnelle pour maintenir la cohérence entre les versions

## Inventaire des versions et de l'environnement

Avant d'automatiser, confirmez les versions de votre chaîne d'outils et la topologie du cluster. Les incohérences de versions sont une source courante de défaillances de pipeline. Cette section répertorie les composants requis et une disposition minimale du cluster.

Prérequis :

- Cluster Kubernetes v1.19 ou ultérieur (recommandé pour un comportement kubectl stable et une compatibilité API)
- CLI kubectl v1.19+ installé et configuré pour atteindre votre cluster
- Accès à un registre de conteneurs (par exemple, Docker Hub, Google Container Registry, Amazon ECR)
- Une plateforme CI/CD (GitHub Actions, GitLab CI, Jenkins ou similaire)
- Code source de l'application avec un Dockerfile
- Un espace de noms dédié aux tests (nous en créerons un dans la section suivante)

Exécutez cette vérification de version pour confirmer la compatibilité :

```bash
kubectl version --short
# Sortie attendue :
# Client Version: v1.24.0
# Server Version: v1.24.0
```

Si les versions client et serveur diffèrent de plus d'une version mineure, mettez à niveau kubectl ou le cluster pour éviter les problèmes d'API obsolètes.

Topologie du cluster (hypothétique mais illustrative) :

- Espace de noms : `production`
- Déploiement : `myapp`
- Service : `myapp-svc` (NodePort ou LoadBalancer)
- Quotas de ressources par espace de noms : CPU 2 cœurs, Mémoire 4Gi

Conservez cet inventaire dans un document partagé (par exemple, un `README.md` dans votre référentiel d'infrastructure) afin que chaque membre de l'équipe travaille avec les mêmes hypothèses.

## Chemin de configuration sécurisé

Commencez par un déploiement pilote étroit et mesurable. Évitez les changements étendus qui affectent les services critiques. Utilisez un espace de noms séparé pour les tests et promouvez progressivement vers la production.

### Étape 1 : Créer un espace de noms dédié

Créez un espace de noms qui reflète la production, y compris les quotas de ressources et les politiques réseau si vous les utilisez.

```bash
kubectl create namespace myapp-test
# Attendu : namespace/myapp-test created
```

Appliquez un quota de ressources pour éviter une consommation de ressources incontrôlée :

```yaml
# quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: myapp-test-quota
  namespace: myapp-test
spec:
  hard:
    requests.cpu: "2"
    requests.memory: 4Gi
    limits.cpu: "4"
    limits.memory: 8Gi
```

```bash
kubectl apply -f quota.yaml -n myapp-test
# Attendu : resourcequota/myapp-test-quota created
```

### Étape 2 : Définir un manifeste de déploiement avec une stratégie de mise à jour progressive explicite

Une stratégie de mise à jour progressive garantit zéro temps d'arrêt en remplaçant progressivement les anciens pods par de nouveaux. Configurez `maxUnavailable` et `maxSurge` pour contrôler le rythme. Incluez des sondes de préparation et de vivacité afin que Kubernetes ne route le trafic que vers des pods sains.

Exemple `deployment.yaml` :

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: myapp-test
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myregistry/myapp:1.0.0
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 10
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "256Mi"
```

Appliquez-le :

```bash
kubectl apply -f deployment.yaml
# Attendu : deployment.apps/myapp created
```

Vérifiez que les pods démarrent :

```bash
kubectl get pods -n myapp-test
# Attendu : 3 pods avec statut Running et 1/1 Ready
```

### Étape 3 : Automatiser avec un pipeline CI/CD simple

Voici un workflow GitHub Actions minimal qui construit et déploie à chaque poussée sur `main`. Il utilise `kubectl` avec un jeton de compte de service stocké comme secret. Ajustez le registre et les noms d'image pour votre environnement.

Tout d'abord, créez un compte de service Kubernetes avec des autorisations limitées à l'espace de noms `myapp-test` :

```yaml
# service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: github-actions
  namespace: myapp-test
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: github-actions-role
  namespace: myapp-test
rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "update", "patch"]
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: github-actions-binding
  namespace: myapp-test
subjects:
- kind: ServiceAccount
  name: github-actions
  namespace: myapp-test
roleRef:
  kind: Role
  name: github-actions-role
  apiGroup: rbac.authorization.k8s.io
```

Appliquez cela et récupérez un jeton :

```bash
kubectl apply -f service-account.yaml -n myapp-test
# Attendu : serviceaccount/github-actions created, role..., rolebinding...

# Obtenir le jeton (en supposant Kubernetes 1.24+ avec l'API TokenRequest) :
kubectl create token github-actions -n myapp-test --duration=24h
# Copiez la sortie du jeton.
```

Stockez le jeton et l'URL du serveur du cluster comme secrets dans votre référentiel GitHub : `KUBE_TOKEN` et `KUBE_SERVER`.

Créez maintenant le fichier de workflow `.github/workflows/deploy.yml` :

```yaml
name: Deploy to Kubernetes
on:
  push:
    branches: [ main ]
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Build and push image
        env:
          REGISTRY: myregistry
          IMAGE: myapp
          TAG: ${{ github.sha }}
        run: |
          docker build -t $REGISTRY/$IMAGE:$TAG .
          echo ${{ secrets.REGISTRY_PASSWORD }} | docker login $REGISTRY -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin
          docker push $REGISTRY/$IMAGE:$TAG
      - name: Set up kubectl
        uses: azure/setup-kubectl@v1
      - name: Deploy to cluster
        env:
          KUBE_SERVER: ${{ secrets.KUBE_SERVER }}
          KUBE_TOKEN: ${{ secrets.KUBE_TOKEN }}
        run: |
          kubectl config set-cluster mycluster --server=$KUBE_SERVER --insecure-skip-tls-verify=true
          kubectl config set-credentials github-actions --token=$KUBE_TOKEN
          kubectl config set-context mycontext --cluster=mycluster --user=github-actions --namespace=myapp-test
          kubectl config use-context mycontext
          kubectl set image deployment/myapp myapp=myregistry/myapp:${{ github.sha }} -n myapp-test
          kubectl rollout status deployment/myapp -n myapp-test --timeout=120s
```

Ce pipeline construit l'image, la pousse vers le registre, met à jour l'image du déploiement et attend la fin du déploiement. La commande `rollout status` fait échouer le pipeline si le déploiement ne devient pas sain dans les 120 secondes.

## Vérification et diagnostic

Après avoir appliqué les modifications, vérifiez que le déploiement a réussi et que l'application sert correctement le trafic. Intégrez ces vérifications dans votre pipeline en tant que barrières automatisées.

### État du déploiement de base

```bash
kubectl rollout status deployment/myapp -n myapp-test
# Attendu : deployment "myapp" successfully rolled out
```

### Inspecter la santé des pods

```bash
kubectl get pods -n myapp-test
# Attendu : 3 pods avec statut Running et READY 1/1
```

### Afficher l'historique des déploiements

```bash
kubectl rollout history deployment/myapp -n myapp-test
# Sortie attendue :
# REVISION  CHANGE-CAUSE
# 1         <none>
# 2         <none>
```

Pour enregistrer une cause de changement, ajoutez une annotation avant d'appliquer :

```bash
kubectl annotate deployment/myapp kubernetes.io/change-cause="Deploy commit $(git rev-parse --short HEAD)" -n myapp-test --overwrite
```

### Décrire les événements pour le diagnostic

```bash
kubectl describe deployment myapp -n myapp-test
# Cherchez la section Events : ScalingReplicaSet, SuccessfulCreate, etc.
```

### Consulter les journaux en cas d'échec d'un pod

```bash
kubectl logs deployment/myapp -n myapp-test --tail=20
```

| Commande | Résultat attendu |
|---|---|
| `kubectl rollout status deployment/myapp -n myapp-test` | "successfully rolled out" |
| `kubectl get pods -n myapp-test` | Tous les pods Running et Ready |
| `kubectl get replicasets -n myapp-test` | Le nouveau ReplicaSet a les répliques souhaitées, l'ancien est réduit |
| `kubectl describe deployment myapp -n myapp-test` | Aucun événement d'erreur |

Utilisez ces vérifications comme barrières dans votre pipeline avant de promouvoir en production. Par exemple, après `rollout status`, ajoutez une étape qui exécute un test de fumée :

```bash
kubectl run smoke-test --image=curlimages/curl --rm -it --restart=Never -n myapp-test -- -s http://myapp-svc:8080/healthz
# Attendu : réponse HTTP 200
```

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

Même avec l'automatisation, des échecs surviennent. Les modes de défaillance courants incluent les erreurs d'extraction d'image, les échecs de sonde de préparation et les ressources insuffisantes. Savoir comment récupérer rapidement est essentiel.

### Défaillance 1 : ImagePullBackOff

- Cause : Étiquette d'image incorrecte ou informations d'identification du registre erronées.
- Détection : `kubectl get pods` affiche `ImagePullBackOff`.
- Récupération : Corrigez l'étiquette de l'image ou les informations d'identification, puis appliquez un manifeste corrigé ou mettez à jour le déploiement.

Exemple de diagnostic :

```bash
kubectl get pods -n myapp-test
# NAME                     READY   STATUS             RESTARTS   AGE
# myapp-765d459796-8s9k7   0/1     ImagePullBackOff   0          2m

kubectl describe pod myapp-765d459796-8s9k7 -n myapp-test
# Cherchez les événements : Failed to pull image ...
```

### Défaillance 2 : CrashLoopBackOff

- Cause : L'application plante au démarrage, souvent en raison d'une mauvaise configuration.
- Détection : `kubectl get pods` affiche `CrashLoopBackOff`.
- Récupération : Vérifiez les journaux avec `kubectl logs`, corrigez le code/la configuration, et poussez une nouvelle image.

```bash
kubectl logs pod/myapp-765d459796-8s9k7 -n myapp-test --previous
# Examinez la trace de pile ou le message d'erreur.
```

### Défaillance 3 : Déploiement bloqué en raison d'un échec de sonde de préparation

- Cause : Les nouveaux pods ne deviennent jamais prêts, donc le déploiement stagne.
- Détection : `kubectl rollout status` expire ou affiche une progression.
- Récupération : Étudiez l'endpoint de la sonde de préparation ou le comportement de l'application. Effectuez un retour arrière si nécessaire.

### Défaillance 4 : Ressources insuffisantes

- Cause : Quota de ressources dépassé ou capacité du cluster limitée.
- Détection : Les nouveaux pods restent en état `Pending`.
- Récupération : Réduisez d'autres charges de travail ou augmentez les quotas de ressources.

### Procédure de retour arrière

Ayez toujours un plan de retour arrière et testez-le dans un espace de noms hors production avant d'en avoir besoin en production.

```bash
# Retour à la révision précédente
kubectl rollout undo deployment/myapp -n myapp-test
# Attendu : deployment.apps/myapp rolled back

# Ou retour à une révision spécifique
kubectl rollout undo deployment/myapp --to-revision=2 -n myapp-test
# Attendu : deployment.apps/myapp rolled back
```

Après le retour arrière, vérifiez :

```bash
kubectl rollout status deployment/myapp -n myapp-test
# Attendu : successfully rolled out
```

| Mode de défaillance | Symptôme | Action de récupération |
|---|---|---|
| ImagePullBackOff | Le statut du pod affiche ImagePullBackOff | Corriger l'étiquette de l'image ou le secret du registre, appliquer le déploiement mis à jour |
| CrashLoopBackOff | Le pod redémarre à plusieurs reprises | Vérifier les journaux, corriger l'erreur d'application, pousser une nouvelle image |
| Échec de la sonde de préparation | Déploiement bloqué, nouveaux pods non prêts | Vérifier l'endpoint de la sonde, ajuster la sonde ou corriger l'application, retour arrière si nécessaire |
| Ressources insuffisantes | Pods en attente | Réduire la charge ou augmenter les quotas de ressources |

## Liste de contrôle opérationnelle

Utilisez cette liste de contrôle avant et après chaque déploiement pour garantir la cohérence et la sécurité. Conservez-la dans votre référentiel ou wiki et mettez-la à jour au fur et à mesure que votre processus évolue.

### Liste de contrôle avant déploiement

- [ ] Vérifier que les versions du cluster et de kubectl correspondent aux attentes (`kubectl version --short`)
- [ ] Examiner les modifications du manifeste de déploiement dans le contrôle de version (diff avec la dernière version)
- [ ] S'assurer que l'image est construite et poussée avec une étiquette unique (par exemple, SHA git, pas `latest`)
- [ ] Confirmer que les demandes et limites de ressources sont définies pour tous les conteneurs
- [ ] Vérifier que les sondes de préparation et de vivacité sont configurées et pointent vers les bons endpoints
- [ ] Vérifier que le pipeline CI/CD dispose des bonnes informations d'identification du cluster (jeton de compte de service, URL du serveur)
- [ ] Exécuter une application à blanc pour valider la syntaxe YAML : `kubectl apply -f deployment.yaml --dry-run=client -n myapp-test`

### Liste de contrôle après déploiement

- [ ] Exécuter `kubectl rollout status` et confirmer le succès
- [ ] Vérifier la préparation des pods et les journaux pour les erreurs (`kubectl get pods`, `kubectl logs`)
- [ ] Surveiller les métriques de l'application (taux d'erreur, latence) pendant au moins 5 minutes après le déploiement
- [ ] Enregistrer la révision du déploiement et tout changement notable (mettre à jour les notes de version ou le journal des modifications)
- [ ] En cas de problème, exécuter la procédure de retour arrière et documenter la cause racine dans un rapport d'incident

### Revue périodique

- [ ] Examiner la sécurité du pipeline : faire tourner les secrets, appliquer le principe du moindre privilège sur les comptes de service
- [ ] Mettre à jour les images de base et les dépendances pour corriger les vulnérabilités
- [ ] Tester le retour arrière dans un environnement de staging tous les trimestres
- [ ] Évaluer la vitesse et la fiabilité du pipeline ; optimiser le cache de construction et le parallélisme si nécessaire

## Conclusion

L'automatisation du déploiement CI/CD sur Kubernetes améliore la fiabilité et réduit les erreurs manuelles. En commençant par un pilote étroit, en implémentant un pipeline simple et en vérifiant chaque déploiement, vous créez une base pour des versions plus sûres. Lorsque des échecs surviennent, avoir une voie de retour arrière claire minimise les temps d'arrêt.

Adoptez la liste de contrôle opérationnelle pour garder votre processus cohérent, et étendez progressivement l'automatisation à d'autres services à mesure que la confiance grandit. N'oubliez pas d'itérer : commencez petit, mesurez le succès et affinez votre pipeline en fonction du comportement observé. Avec ces pratiques, vous pouvez livrer plus rapidement en toute confiance, sachant que vos déploiements Kubernetes sont sûrs, reproductibles et récupérables.

Prochaines étapes : implémentez ces modèles dans votre propre cluster, intégrez des notifications (par exemple, des alertes Slack) en cas d'échec du pipeline, et explorez des outils de livraison progressive comme Argo Rollouts ou Flagger pour des stratégies de déploiement plus avancées.