Ce que j’ai appris de la migration d'Heroku vers un cluster Kubernetes
Photo par Markus Spiske sur Unsplash
Une partie de la mission qui m’a été confiée à mon arrivée dans mon entreprise actuelle était la migration complète de notre hébergement Rails d’un service Heroku vers une solution Kubernetes. C’était ma première expérience de migration d’une stack de production, et ma première expérience avec Kubernetes également. Et au cas où vous penseriez que la tâche n’était pas assez intimidante, le précédent et unique développeur a décidé de partir pour une autre opportunité quelques semaines après mon arrivée.
Ce départ a été vite oublié avec l’embauche par l’entreprise d’un autre développeur qui avait déjà fait la transition d’une app vers Kubernetes. J’ai donc suivi un cours sur Udemy, lu la documentation de Kubernetes en profondeur, pris des notes, et joué avec un cluster de test. Puis je me suis lancé dans le voyage de la transition.
Six mois plus tard, la transition Heroku-Kubernetes est maintenant terminée. J’ai acquis beaucoup d’expérience. Et je pense qu’il est temps de la partager.
La stack
Le produit phare de notre entreprise est une lampe intelligente qui détecte les mouvements et les activités des personnes âgées et envoie une alarme en cas de chute. Elle est principalement utilisée dans les maisons de retraite françaises, mais nous avons reçu beaucoup d’attention dans le domaine de la silver économie et nous sommes sur le point de nous développer à l’échelle mondiale, et de vendre notre produit, ainsi que son infrastructure web, à des revendeurs franchisés. C’est là que Kubernetes devient une solution pratique, car il permet une réplication et une mise à l’échelle rapides d’une seule stack.
La stack se compose donc d’un broker MQTT (hébergé avec CloudMQTT) qui reçoit les messages envoyés par les lampes intelligentes et leurs accessoires. Un worker Sidekiq interroge ensuite constamment le broker pour obtenir les messages et prendre des mesures en fonction du contenu : envoyer des alertes, surveiller l’activité, ou simplement enregistrer la température, etc. L’application web Rails est en charge d’une interface d’administration et de quelques endpoints API utilisés par les applications mobiles. Les autres services connectés incluent Heroku Postgres pour les données, Redis comme backend Sidekiq, Elasticsearch pour indexer et rechercher les payloads MQTT enregistrés, Logentries pour suivre le log Rails, Sentry pour les alertes et Sendgrid pour les emails.
Tous ces services avaient été souscrits en tant que Saas depuis la console d’application Heroku.
Ce que j’ai bien fait
J’ai demandé du temps
Étant donné le contexte, c’était la première chose que j’ai faite. L’entreprise voulait un déménagement rapide, mais j’ai dit que je devais apprendre la stack, me familiariser avec le codebase et résoudre quelques problèmes avant de pouvoir avoir une bonne idée de ce que les implications d’une telle migration signifiaient. Ils ont accepté et m’ont donné quelques mois pour effectuer la transition.
Je ne peux qu’imaginer à quel point il aurait été douloureux d’entreprendre une telle tâche avec une connaissance limitée de l’application.
J’ai demandé de l’aide
Mon expérience devops précédente se limitait à éditer ma configuration Capistrano et maintenir quelques VPS. Pousser une nouvelle mise à jour dans mon nouveau lieu de travail consistait simplement à taper git push heroku master et peut-être exécuter une migration sur le serveur par la suite. Régler la stack consistait à ajouter ou supprimer un dyno, et à changer le plan de facturation Saas pour obtenir plus de ressources.
Quand j’ai commencé à regarder la façon dont Kubernetes est architecturé, j’ai rapidement compris que j’avais besoin de l’aide d’un consultant pour me guider et me conseiller sur la façon de construire la nouvelle stack et prendre des décisions judicieuses sur la myriade d’options de configuration disponibles. Je suis tellement reconnaissant envers ce type, qui s’est avéré très sympathique et patient. Chapeau.
J’ai joué et pris des notes
C’est important. J’ai détruit et reconstruit le cluster à partir de zéro au moins trois fois. À chaque fois, j’ai écrit des choses dans un wiki pour référence. Et à chaque fois, j’ai amélioré le workflow et acquis beaucoup d’expérience.
J’ai supprimé des pods, des services, les ai recréés, joué avec des PVC, essayé de nombreux helm charts… Cela m’a donné une expérience pratique et m’a permis de casser les choses plusieurs fois avant de savoir comment faire fonctionner les choses.
J’ai amélioré le workflow de production
Peut-être devrais-je dire “il”, parce que c’était le travail du consultant Kubernetes.
Nous avons maintenant un beau flux CI entièrement intégré qui crée des environnements Kubernetes pour la production, les tests et le staging. Il doit encore être amélioré, mais nous sommes presque au même niveau que git push heroku master maintenant.
Ce que j’ai mal fait
Beaucoup de choses. Voici les détails.
J’ai perdu du temps à adapter la stack
Quand j’ai introduit Elasticsearch dans la stack, notre consommation de mémoire est devenue folle. Nous avons donc décidé de trouver une alternative. Elasticsearch n’est pas utilisé comme fonctionnalité destinée à l’utilisateur final. Il est utilisé par notre service après-vente et nos développeurs. Nous avons donc décidé que la recherche dans les logs pouvait prendre 3 secondes au lieu de 300ms et nous nous sommes complètement débarrassés d’Elasticsearch.
Nous avions tort. Non seulement j’ai passé beaucoup de temps à rechercher des solutions, à régler les indices, à partitionner les tables, à refactoriser le code, mais au final je n’ai pas trouvé d’alternative viable qui puisse être utilisée au quotidien par mes collègues. J’ai donc décidé de revenir temporairement à Elasticsearch pour la transition, et de faire la recherche plus tard. Cela aurait dû être notre décision dès le départ, car nous avons perdu beaucoup d’argent en heures de travail pour économiser quelques centaines d’euros par an.
J’ai ajouté des fonctionnalités
Quand on vous donne un nouveau jouet, il est tentant de l’essayer dans chaque situation qui se présente.
Ne le faites pas.
Après quelques semaines, la branche k8s avait divergé de master dans une mesure énorme. Encore une fois, cela aurait pu très mal tourner, et c’est arrivé dans une certaine mesure, car j’ai dû faire quelques correctifs en direct le jour 2 après que quelques clients ont expliqué que certaines parties du service ne se comportaient pas comme prévu.
J’ai changé les versions
Hé. Postgres 12 est disponible. Utilisons-le.
C’est peut-être une bonne idée de mettre à niveau votre base de données. Mais gardez cela pour plus tard, une fois que la poussière est retombée. J’ai rencontré quelques bugs liés à cette mise à niveau. Ce n’étaient pas des bugs gigantesques. Mais ils auraient pu être évités, ou reportés.
J’ai tout déplacé d’un coup
Nous avons décidé que nous voulions rendre notre cluster totalement autonome et arrêter de compter sur le Saas, sauf pour Sentry et Sendgrid. Nous avons donc opté pour Stolon comme base de données Postgresql haute disponibilité, VerneMQ pour le broker MQTT, et les helm charts Bitnami pour Elasticsearch et Redis.
C’est bien. Mais c’est trop à gérer en un seul déplacement. J’avais pas mal d’expérience dans la gestion d’une base de données Postgres, Redis c’est OK, mais j’étais un débutant complet en administration d’Elasticsearch. Le jour de la migration, c’était le service qui a causé le plus de problèmes, et j’ai dû réindexer la base de données de 80 millions de logs deux fois pour que ce soit correct sans planter le serveur.
Avec du recul, les choses auraient pu très mal tourner.
J’aurais dû prendre les choses progressivement :
- D’abord, l’application Rails, Redis et Postgres. C’est le cœur de notre stack. Et c’est assez de travail pour un premier passage. Corriger les bugs, régler l’application, et laisser reposer pendant une semaine ou deux.
- Deuxièmement, configurer Grafana. J’utilise Loki pour les logs, donc c’est un bon remplacement pour Logentries.
- Ensuite, installer le broker MQTT. C’est facile, car vous pouvez simplement faire un pont des messages de l’un à l’autre. Ensuite, c’est juste une question de pointer les appareils vers la nouvelle URL. C’est le problème de l’équipe de développement IoT, pas le mien.
- Enfin, essayer Elasticsearch avec un sous-ensemble de logs. Voir comment il se comporte. Puis déplacer progressivement le reste vers la nouvelle infrastructure.
TL; DR; Comment vous devriez le faire
Ne soyez pas trop gourmand, soyez humble et essayez de déplacer les choses petit à petit. Essayez de garder la stack aussi similaire que possible à la stack Heroku pour commencer : mêmes versions de logiciels, même environnement. Ce n’est qu’ensuite que vous pourrez mettre à niveau les logiciels si vous le souhaitez. Gardez le Saas connecté en fonctionnement, et ajoutez-les progressivement à votre stack si c’est ce que vous voulez faire. Mais assurez-vous d’avoir un environnement de test et de staging approprié au préalable.
MoskitoHero