mitiger-bug

Publié le 4 janvier 2024.

Implémenter les critères de la catégorie Résilience de notre framework de qualité, nous permet de prévenir les incidents sur nos infrastructures Cloud. En tant que SRE c’est notre rôle principal, mais on est aussi confronté à des incidents en production donc on a l’habitude de mitiger nos problèmes.

La mitigation

Chez Padok, on utilise le framework ROSE qui contient 100 critères qui caractérisent une bonne infrastructure. Ce qui nous permet de minimiser les risques d’incidents sur nos infrastructures. Cependant, on est tout de même confrontés régulièrement à des incidents en production avec l’équipe d’infogérence. Quand ça se produit, on doit prêt et entraîné pour gérer cette urgence.

Durant ces situations, il y a deux enjeux clés, mitiger puis résoudre le problème. La mitigation est utile pour minimiser l’impact sur les utilisateurs, éviter que le problème ne s’étende et qu’il n’y ait pas de répercussions plus importantes. Une fois le problème mitigé, on peut approfondir les recherches pour apporter une solution durable.

Assez souvent on passe directement à la résolution du problème sans passer par la mitigation. Mais trop souvent le problème n’est pas résolu efficacement. C’est pour limiter l’impact de cette lente résolution qu’il est important de mitiger vos problèmes.

Mitiger, c’est bien


Mitiger les feux de forêts


Ce concept de mitigation est évoqué dans des standards de gestion de crise comme celui des pompiers. Comme précisé dans l’article incident managment du book SRE de Google, ils se sont inspirés du standard ICS des pompiers de Californie pour construire leur standard de gestion de crise.

Cela peut sembler contre-intuitif, mais parfois les pompiers brûlent d’eux-mêmes les bordures de champs ou une partie de la forêt d’une manière contrôlée. Brûler volontairement dans un but préventif permet d’endiguer la propagation du feu. C’est cette méthode que j’essaye d’appliquer dans le contexte du cloud.


Mitiger dans le cloud


Dans le cloud, cette pratique est bien trop souvent négligée. Des incidents durent souvent plus longtemps que nécessaire. Les SRE cherchent avant tout à trouver puis à corriger un bug, alors qu’ils pourraient dans premier temps se concentrer sur la mitigation pour limiter l’impacte du bug. Et donc réduire la nuisance occasionnée.

En effet, il est parfois plus facile d’empêcher l’accès aux services pour pouvoir trouver la source d’un problème. C’est le cas, avec les pics de charge sur une application qui ne marche pas par exemple.

De plus, si on peut se soustraire à l’impact néfaste d’un trafic important, tout en avertissant les utilisateurs que le service qu’il cherche à joindre n’est pas disponible, c’est encore mieux. En effet, vous allez donner une visibilité à la situation et éviter aux utilisateurs de réessayer d’accéder en vain à votre service, ce qui nuit à votre image de marque.

Des façons de mitiger


La page de maintenance


La meilleure manière d’atteindre les deux objectifs cités précédemment est d’avoir préparé en amont une belle page de maintenance et de l’afficher aux utilisateurs. Une simple page statique qui avertit vos utilisateurs qu’une maintenance est en cours calmera toutes leurs ardeurs à rafraîchir leur page lorsqu’ils ont des erreurs.

Selon moi c'est la meilleure solution qui peut être facilement mise en place avec un service tel que Cloudfront. En une redirection DNS plus tard, ou en une modification d’un ingress dans kubernetes, vous évitez que vos utilisateurs fassent exploser votre service déjà KO.

Ainsi, si vous êtes bien préparé, en quelques minutes vous êtes apte à vous lancer dans le debug du véritable problème, sans la pression des utilisateurs.


Couper le service simplement


Pour ceux qui n’ont pas de page de maintenance préparée, il est alors tout simplement possible de couper le service. En effet, que votre site timeout, renvoie des erreurs 5XX ou 404, il n’est pas accessible.

Il est donc alors possible de couper le service pour éviter que les utilisateurs n’aggravent la situation. C’est un moyen d’avoir de l’air pour pouvoir debuguer dans de meilleures conditions. Attention, il se peut aussi que votre problème ne se produise que quand votre plateforme est stressée et donc cette solution n’est pas toujours adaptée.


Couper partiellement le service


Dans certains cas, vous n’arriverez pas à identifier le problème sans un minimum de trafic et d’utilisateurs. Vous pouvez essayer de faire une répartition du trafic 95%-5% pour ne subir qu’une partie supportable du trafic. 5% des utilisateurs vont servir à reproduire le problème et les 95% restant peuvent être redirigés vers une page de maintenance.

La plupart de vos utilisateurs ne pourront pas atteindre l’application, mais au moins, vous soulagerez chaque composant de votre infrastructure. Ainsi, vous ne ferez plus face à une masse des utilisateurs mais vous en aurez toujours suffisamment pour reproduire les comportements problématiques.

Voici différentes manières de limiter l’impact d’un incident. Ces méthodes ne sont pas révolutionnaires, mais sont simples à mettre en place. Toute la difficulté réside dans le choix d’accepter de détourner son propre trafic et de savoir décider si une situation se prête ou non à ce genre de mitigation.

Le retour d’expérience

On va revenir sur un problème que j’ai rencontré en tant qu’Ops de l’équipe RUN, qui démontre l’efficacité d’une méthode de mitigation qu’on utilise.

Mise en contexte

  • Il est 18h, on est un vendredi soir.
  • Je suis la personne de mon équipe en charge de répondre aux incidents lorsque notre système de monitoring nous alerte.
  • Ma rotation se termine à 18h30, et je serai en week-end.
  • Mon Lead SRE est en train d’aider une autre société pour faire face à un incident majeur de façon bénévole.

L’identification du problème


18h05 mon téléphone sonne, c’est une alerte et je me lance sur l’identification du problème. Je préviens mon client qu’il y a des perturbations sur certaines de ces API. L’équipe en charge de ces APIs est disponible, et au bout de 10 minutes d’investigation on se rejoint dans un meet.

Le but étant de partager nos découvertes et réfléchir ensemble à la situation à laquelle ont fait face. À ce stade, je sais juste qu’un endpoint ne répond plus, on a un système de monitoring ‘blackbox’.

Les symptômes observés lors de l’investigation
  • On a vu qu’il y avait beaucoup de requêtes sur certaines API
  • On a augmenté les max pods du HPA, pour valider que le problème n’est pas lié au trafic. Mais ça n’a pas eu d’impacts.
  • Un dev a fouillé dans les logs applicatifs et identifie une IP problématique, elle fait beaucoup trop de requêtes.
  • Je m’aperçois que c’est une IP interne à notre cluster Kubernetes. Je rassure les craintes de mon client, non on ne se fait pas attaquer. On n’est pas victime d’attaque DDOS venant d’un utilisateur malveillant, mais ce trafic est interne au cluster.
  • On se rend compte que certaines requêtes à mon.api font une requête à toto.api ou a tata.api. Sauf que pour chaque requête venant de mon.api, allant à toto.api ou tata.api, il y a N requêtes qui repartent vers mon.api.
  • J’ai créé un schéma de la situation pour comprendre et expliqué ce qui se passe.

investigation

Trouver comment mitiger


Comme on vient de le comprendre avec le schéma, il y a une boucle d’appels infinie entre les différentes API qui est problématique. Or mon.api est également utilisée par de nombreux autres utilisateurs qui n’utilisent ni toto.api ni tata.api.

Avec le client, on se met d’accord notre objectif est de trouver un moyen de mitiger le problème pour le week-end. Puis il le résoudra réellement dès le lundi matin.

Les contraintes à ma connaissance sont les suivantes :

  • Il n’est pas acceptable de couper mon.api tout le week-end
  • Il est acceptable de stopper toto.api et tata.api tout le week-end
  • La mitigation doit me permettre de revenir à la situation initiale

Dans l’idéal je préfère ne pas toucher aux ressources actuelles, et malgré toutes ces contraintes, j’ai trouvé une solution pour mitiger ce problème. Je veux rediriger toutes les requêtes de mon.api à destination de toto.api ou de tata.api vers un service qui n’existe pas.

Ainsi je brise la chaîne infinie qui posait problème. Je suis capable de le tester super rapidement car justement je ne change aucune ressources existante. Et moins d’une minute après la validation de mon client, j’applique la configuration à l’aide d’un kubectl apply -f ingress-blabla.yaml.

apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: fix-ingress
			tag: to-delete
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
    spec:
      ingressClassName: nginx
      rules:
      - host: toto.api
        http:
          paths:
          - backend:
              service:
                name: this-service-doesnt-exist
                port:
                  number: 80
            path: /certificate/metadata/toto
            pathType: Prefix
      - host: tata.api
        http:
          paths:
          - backend:
              service:
                name: this-service-doesnt-exist
                port:
                  number: 80
            path: /certificate/metadata/tata
            pathType: Prefix

Le nombre de requêtes a diminué instantanément et a mitigé l’incident. J’adore cet exemple car il illustre parfaitement comment, en cassant une partie de l’infrastructure, j’ai eu de nouveau le contrôle de la situation.

casser-pour-reconstruire

Conclusion

Pour résoudre un incident efficacement, il faut parfois accepter de casser temporairement une infrastructure ou de fermer un service. Ce n’est pas grave surtout si elle ne fonctionne pas. Dans l’exemple que j’ai raconté, ce qui est cool, c’est qu’il est très simple d’annuler mes changements pour revenir à une situation normale.

Cette solution est pratique pour faire un test rapide sans aucun risque. On a géré un incident qui a nécessité aux développeurs plusieurs heures de debug intense la semaine suivante en 45 minutes. On a évité à notre client de faire un travail de debug applicatif en plein week-end, sous stress.

Et enfin, on a limité l’impact pour les utilisateurs finaux. Voici un cas de figure typique, où il est important de mitiger un problème plutôt que de chercher à le résoudre. Et voici une bonne histoire où j’ai cassé mon infrastructure pour mieux la réparer.