Ennemis de la réalité par 12f-2Fin avril, alors que les marcheurs blancs assiégeaient Winterfell, quelque chose de plus intéressant s'est produit pour nous, nous avons fait un déploiement inhabituel. En principe, nous déployons constamment de nouvelles fonctionnalités dans la prod (comme tout le monde). Mais celui-ci n'était pas comme tout le monde. Son échelle était telle que toute erreur potentielle que nous pourrions commettre affecterait tous nos services et utilisateurs. En conséquence, nous avons tout déployé conformément au plan, dans les temps d'arrêt prévus et annoncés, sans conséquences pour la vente. L'article explique comment nous y sommes parvenus et comment ceux qui le souhaitent peuvent le répéter chez eux.
Je ne décrirai pas maintenant nos décisions architecturales et techniques, je ne dirai pas comment tout cela fonctionne. Il s'agit probablement de notes marginales sur la façon dont s'est déroulé l'un des déploiements les plus difficiles, que j'ai observées et auxquelles j'ai participé directement. Je ne prétends pas être des détails complets ou techniques, peut-être qu'ils apparaîtront dans un autre article.
Contexte + quel type de fonctionnalité est-ce
Nous construisons la plateforme cloud
Mail.ru Cloud Solutions (MCS), où je travaille en tant que CTO. Et maintenant - il est temps de se connecter à notre plateforme IAM (Identity and Access Management), qui fournit une gestion unifiée de tous les comptes d'utilisateurs, utilisateurs, mots de passe, rôles, services et plus encore. Pourquoi est-il nécessaire dans le cloud est une question évidente: toutes les informations utilisateur y sont stockées.
En règle générale, ces choses commencent à se construire au tout début d'un projet. Mais MCS a toujours été un peu différent. MCS a été construit en deux parties:
- Openstack avec son propre module d'autorisation Keystone,
- Hotbox (stockage S3) basé sur le projet Cloud Mail.ru,
autour duquel de nouveaux services sont alors apparus.
Il s'agissait essentiellement de deux types d'autorisation différents. De plus, nous avons utilisé des développements Mail.ru distincts, par exemple, le stockage général des mots de passe Mail.ru, ainsi qu'un connecteur openid auto-écrit, qui permettait la SSO (autorisation directe) dans le panneau Horizon des machines virtuelles (UI native OpenStack).
Faire IAM signifiait pour nous de combiner tout cela en un seul système, complètement le nôtre. Dans le même temps, ne perdez aucune fonctionnalité en cours de route, créez un backlog pour l'avenir, ce qui nous permettra de l'affiner de manière transparente sans refactoring et de le mettre à l'échelle par fonctionnalité. Toujours au début, les utilisateurs sont apparus comme un modèle d'accès aux services (RBAC central, contrôle d'accès basé sur les rôles) et quelques autres petites choses.
La tâche s'est avérée non triviale: python et perl, plusieurs backends, des services écrits de manière indépendante, plusieurs équipes de développement et des administrateurs. Et surtout, des milliers d'utilisateurs en direct sur le système de production de combat. Tout cela devait être écrit et, surtout, déployé sans faire de victimes.
Qu'allons-nous déployer
Si c'est très grossier, quelque part en 4 mois, nous avons préparé ceci:
- Ils ont créé plusieurs nouveaux démons qui ont agrégé des fonctions qui fonctionnaient auparavant dans différentes parties de l'infrastructure. D'autres services se sont vu imposer un nouveau backend sous la forme de ces démons.
- Nous avons écrit notre propre référentiel central de mots de passe et de clés, disponible pour tous nos services, qui peut être librement modifié selon nos besoins.
- À partir de zéro, ils ont écrit 4 nouveaux backends pour Keystone (utilisateurs, projets, rôles, attributions de rôles), qui, en fait, ont remplacé sa base et agissent désormais comme un référentiel unique de nos mots de passe utilisateur.
- Nous avons appris à tous nos services Openstack à appliquer leurs stratégies à un service de stratégie tiers au lieu de lire ces stratégies localement depuis chaque serveur (oui, par défaut, Openstack fonctionne comme ça!)
Une telle modification importante nécessite des changements importants, complexes et, surtout, synchrones dans plusieurs systèmes écrits par différentes équipes de développement. Après l'assemblage, l'ensemble du système devrait fonctionner.
Comment déployer de tels changements et ne pas les gâcher? Tout d'abord, nous avons décidé de regarder un peu vers l'avenir.
Déployer la stratégie
- Il serait possible de déployer en plusieurs étapes, mais cela augmenterait le temps de développement de trois fois. De plus, pendant un certain temps, nous aurions une désynchronisation complète des données dans les bases de données. Je devrais écrire mes propres outils de synchronisation et vivre avec plusieurs entrepôts de données pendant longtemps. Et cela crée une grande variété de risques.
- Tout ce qu'ils pouvaient préparer de manière transparente pour l'utilisateur était fait à l'avance. Cela a pris 2 mois.
- Nous nous sommes permis des temps d'arrêt pendant plusieurs heures - uniquement pour les opérations utilisateur pour créer et modifier des ressources.
- Pour le travail de toutes les ressources déjà créées, les temps d'arrêt étaient inacceptables. Nous avions prévu que lors du déploiement, les ressources devraient fonctionner sans temps d'arrêt et sans impact pour les clients.
- Pour réduire l'impact sur nos clients, en cas de problème, nous avons décidé de nous déployer dimanche soir. La nuit, moins de clients gèrent les machines virtuelles.
- Nous avons prévenu tous nos clients que pendant la période choisie pour le déploiement, la gestion des services ne serait pas disponible.
Digression: qu'est-ce que le déploiement?
<philosophie de prudence>Chaque spécialiste informatique répondra facilement à ce qu'est le déploiement. Vous mettez CI / CD, et automatiquement tout est livré au prod. :)
Bien sûr, c'est vrai. Mais la difficulté est qu'avec les outils modernes d'automatisation de la livraison de code, la compréhension du roulement lui-même est perdue. Comment oubliez-vous l'invention épique de la roue, en regardant les véhicules modernes. Tout est tellement automatisé que le déploiement se fait souvent sans se rendre compte de la situation dans son ensemble.
Et l'image est la suivante. Le déploiement se compose de quatre grands aspects:
- Livraison du code, y compris la modification des données. Par exemple, leur migration.
- Rollback de code - la possibilité de revenir en cas de problème. Par exemple, par la création de sauvegardes.
- L'heure de chaque opération de déploiement / annulation. Il faut comprendre le calendrier de toute opération des deux premiers points.
- Fonctionnalité affectée. Il est nécessaire d'évaluer à la fois les effets positifs et négatifs attendus.
Tous ces aspects doivent être pris en compte pour un déploiement réussi. Habituellement, ils n'évaluent que le premier, au mieux, le deuxième point, puis le déploiement est considéré comme réussi. Mais les troisième et quatrième sont encore plus importants. Quel utilisateur l'aimera si le déploiement prend 3 heures au lieu d'une minute? Ou si quelque chose de superflu affecte le déploiement? Ou le temps d'arrêt d'un service entraînera des conséquences imprévisibles?
Acte 1..n, préparation à la libération
Au début, j'ai pensé décrire brièvement nos réunions: toute l'équipe, ses parties, des tas de discussions en points café, des disputes, des tests, des tempêtes cérébrales. J'ai alors pensé que ce serait superflu. Quatre mois de développement consistent toujours en cela, surtout lorsque vous écrivez non pas quelque chose qui peut être livré en permanence, mais une grande caractéristique d'un système vivant. Ce qui affecte tous les services, mais les utilisateurs ne devraient rien changer sauf le "bouton unique dans l'interface Web".
Notre compréhension du déploiement, a changé à chaque nouvelle réunion, et de manière très significative. Par exemple, nous allions mettre à jour l'ensemble de notre base de facturation. Mais ils ont calculé le temps et se sont rendu compte qu'il était impossible de le faire dans un délai de déploiement raisonnable. Nous avons mis près d'une semaine supplémentaire pour partager et archiver la base de données de facturation. Et lorsque la vitesse de déploiement attendue n'a pas fonctionné après cela, ils ont commandé un fer supplémentaire, plus puissant, où ils ont traîné toute la base. Non pas que nous ne voulions pas le faire plus tôt, mais le besoin actuel de déploiement ne nous a laissé aucune option.
Lorsque l'un de nous a douté que le déploiement puisse affecter la disponibilité de nos machines virtuelles, nous avons passé une semaine à tester, expérimenter, analyser le code et avons clairement compris que cela ne se produirait pas dans notre production, et même les personnes les plus douteuses étaient d'accord avec cela.
Pendant ce temps, les gars du support technique ont mené leurs expériences indépendantes pour écrire aux clients des instructions sur la façon de se connecter, qui devaient changer après le déploiement. Ils ont travaillé sur une expérience utilisateur conviviale, préparé des instructions et fourni des conseils personnalisés.
Nous avons automatisé toutes les opérations de déploiement qui étaient possibles. Toute opération était scriptée, même la plus simple, conduisait constamment des tests. Ils ont discuté de la meilleure façon de désactiver le service - réduire le démon ou bloquer l'accès au service avec un pare-feu. Une check-list des équipes a été créée pour chaque étape de déploiement, elle a été constamment mise à jour. Nous avons dessiné et constamment mis à jour le diagramme de Gantt pour tous les travaux de déploiement, avec des horaires.
Et donc ...
Acte final, avant le déploiement
... il est temps de se déployer.
Comme dit le proverbe, une œuvre d'art ne peut pas être achevée, seulement pour finir de travailler dessus. Il est nécessaire de faire un effort volontaire, en comprenant que vous ne trouverez pas tout, mais en croyant que vous avez fait toutes les hypothèses raisonnables, prévues pour tous les cas possibles, fermé tous les bogues critiques et que tous les participants ont fait tout ce qu'ils pouvaient. Plus vous déployez de code, plus il est difficile de s'en convaincre (d'ailleurs, tout le monde comprend qu'il est impossible de tout prévoir).
Nous avons décidé que nous étions prêts à nous déployer lorsque nous avons été convaincus que nous avions fait tout ce qui était en notre pouvoir pour réduire tous les risques pour nos utilisateurs liés aux effets et aux temps d'arrêt inattendus. C'est-à-dire que tout peut aller mal sauf:
- L'affect (sacré pour nous, le plus précieux) de l'infrastructure utilisateur,
- Fonctionnalité: l'utilisation de notre service après le déploiement devrait être la même qu'avant.
Déployer
Deux roulent, 8 n'interfèrent pasNous prenons le temps d'arrêt pour toutes les demandes des utilisateurs dans les 7 heures. À l'heure actuelle, nous avons à la fois un plan de déploiement et un plan de retour en arrière.
- Le déploiement lui-même prend environ 3 heures.
- 2 heures - pour les tests.
- 2 heures - une réserve pour un éventuel retour en arrière des modifications.
Un diagramme de Gantt a été compilé pour chaque action, combien de temps cela prend, ce qui se passe en séquence, ce qui se fait en parallèle.
Une tranche du diagramme de déploiement de Gantt, l'une des versions antérieures (sans exécution parallèle). L'outil de synchronisation le plus précieuxTous les participants ont leur rôle dans le déploiement, quelles tâches ils font, dont ils sont responsables. Nous essayons de rendre chaque étape automatique, de revenir en arrière, de recueillir des commentaires et de recommencer.
Chronique des événements
Ainsi, 15 personnes sont venues travailler le dimanche 28 avril à 22h. En plus des participants clés, certains sont venus simplement pour soutenir l'équipe, pour laquelle un merci spécial à eux.
Séparément, il convient de mentionner que notre testeur de clés est en vacances. Il est impossible de le déployer sans test, nous travaillons sur des options. Une collègue accepte de nous tester hors vacances, pour laquelle elle a une immense gratitude de la part de toute l'équipe.
00:00. ArrêterNous arrêtons les demandes des utilisateurs, suspendons la plaque signalétique, disent-ils, les travaux techniques. La surveillance crie, mais tout est normal. Nous vérifions que rien n'est tombé, sauf qu'il devrait. Et nous commençons à travailler sur la migration.
Tout le monde a un plan de déploiement imprimé pour les points, tout le monde sait qui fait quoi et à quel moment. Après chaque action, nous vérifions les horaires qui ne les dépassent pas, et tout se passe comme prévu. Ceux qui ne sont pas directement impliqués dans le déploiement au stade actuel se préparent en lançant un jouet en ligne (Xonotic, type 3 kwaki), afin de ne pas gêner les collègues. :)
02h00 DéployéUne agréable surprise - nous avons terminé le déploiement une heure plus tôt, en raison de l'optimisation de nos bases de données et de nos scripts de migration. Le cri universel, "déployé!" Toutes les nouvelles fonctions de la prod, mais jusqu'ici seulement, nous pouvons voir l'interface. Tout le monde passe en mode test, trié en tas et commence à regarder ce qui s'est finalement passé.
Cela n’a pas très bien fonctionné, nous le comprenons au bout de 10 minutes, lorsque rien n’est connecté et ne fonctionne pas dans les projets des membres de l’équipe. Synchronisation rapide, exprimer nos problèmes, prioriser, se diviser en équipes et déboguer.
2 h 30 Deux gros problèmes contre quatre yeuxNous trouvons deux gros problèmes. Nous avons réalisé que les clients ne verront pas certains services connectés et qu'il y aura des problèmes avec les comptes partenaires. Les deux sont associés à des scripts de migration imparfaits pour certains cas marginaux. Nous devons le réparer maintenant.
Nous écrivons des requêtes qui corrigent cela, au moins 4 yeux. Nous roulons sur la pré-porte pour nous assurer qu'ils fonctionnent et ne cassent rien. Vous pouvez continuer. En parallèle, nos tests d'intégration habituels commencent, ce qui détecte quelques problèmes supplémentaires. Tous sont petits, mais doivent également être réparés.
3 h 00 -2 problèmes +2 problèmesLes deux grands problèmes précédents sont résolus, presque tous les problèmes mineurs aussi. Tous les correctifs inoccupés travaillent activement dans leurs comptes et signalent ce qu'ils trouvent. Nous priorisons, distribuons par commandes, laissons sans critique le matin.
En exécutant à nouveau les tests, ils révèlent deux nouveaux gros problèmes. Toutes les stratégies de service ne sont pas arrivées correctement, donc certaines demandes des utilisateurs ne s'authentifient pas. Plus un nouveau problème avec les comptes partenaires. Nous nous précipitons pour regarder.
03:20. Synchronisation d'urgenceUn nouveau problème a été corrigé. Pour la seconde, nous organisons une synchronisation d'urgence. Nous comprenons ce qui se passe: le correctif précédent a résolu un problème, mais en a créé un autre. Nous prenons une pause pour comprendre comment le faire correctement et sans conséquences.
3 h 30 Six yeuxNous sommes conscients de ce que devrait être l'état final de la base pour que tout soit bon pour tous les partenaires. Nous rédigeons une demande en 6 yeux, roulons sur la pré-tige, testons, roulons sur la prod.
04h00. Tout fonctionneTous les tests ont réussi, aucun problème critique n'est visible. De temps en temps, quelque chose ne fonctionne pas en équipe, nous réagissons rapidement. Le plus souvent, l'alarme est fausse. Mais parfois, quelque chose n'a pas atteint, quelque part une page séparée ne fonctionne pas. Nous nous asseyons, réparons, réparons, réparons. Une équipe distincte lance la dernière grande fonctionnalité - la facturation.
04h30. Point de non retourLe point de non-retour approche, c'est-à-dire le moment où, si nous commençons à reculer, nous ne respecterons pas le temps d'arrêt qui nous est donné. Il y a des problèmes avec la facturation, qui sait tout et écrit, mais qui ne veut pas obstinément annuler l'argent des clients. Il y a plusieurs bogues sur des pages individuelles, des actions, des statuts. La fonctionnalité principale fonctionne, tous les tests réussissent. Nous décidons que le déploiement a eu lieu, nous ne reculerons pas.
6 h 00 Nous ouvrons du tout dans l'interface utilisateurLes bugs sont corrigés. Certains utilisateurs non concernés sont laissés pour plus tard. Nous ouvrons l'interface à tout le monde. Nous continuons à évoquer la facturation, à attendre les commentaires des utilisateurs et à surveiller les résultats.
07h00 Problèmes de chargement d'APIIl devient clair que nous avons une petite charge mal planifiée sur notre API et testons cette charge, ce qui n'a pas pu identifier le problème. En conséquence, environ 5% des demandes échouent. Nous nous mobilisons, recherchons une raison.
La facturation est têtue, ne veut pas travailler non plus. Nous décidons de le reporter pour plus tard afin d'apporter des modifications en mode calme. Autrement dit, toutes les ressources qu'il contient sont accumulées, mais les radiations des clients ne passent pas. Bien sûr, c'est un problème, mais par rapport au déploiement général, il ne semble pas fondamental.
08h00. Fix APINous avons déployé un correctif pour la charge, les échecs sont restés. Nous commençons à rentrer à la maison.
10 h 00 TousTout est réparé. Dans le suivi et les clients sont silencieux, l'équipe se couche progressivement. La facturation demeure, nous la rétablirons demain.
Puis, au cours de la journée, des déploiements ont corrigé les journaux, les notifications, les codes retour et les codes personnalisés de certains de nos clients.
Le déploiement a donc été un succès! Bien sûr, cela pourrait être mieux, mais nous avons tiré des conclusions sur ce que nous n'avions pas assez pour atteindre la perfection.
Total
En moins de 2 mois de préparation active au moment du déploiement, 43 tâches ont été réalisées, d'une durée de quelques heures à plusieurs jours.
Pendant le déploiement:
- démons nouveaux et modifiés - 5 pièces, remplaçant 2 monolithes;
- changements dans les bases de données - les 6 de nos bases de données avec les données des utilisateurs sont affectées, les déchargements de trois anciennes bases de données vers une nouvelle sont terminés;
- interface entièrement refaite;
- le nombre de code pompé - 33 mille lignes de nouveau code, ≈ 3 mille lignes de code dans les tests, ≈ 5 mille lignes de code de migration;
- toutes les données sont intactes, pas une seule machine virtuelle du client n'a souffert. :)
Bonnes pratiques pour un bon déploiement
Nous avons été guidés par eux dans cette situation difficile. Mais, d'une manière générale, il est utile de les observer dans tout déploiement. Mais plus le déploiement est difficile, plus leur rôle est important.
- La première chose que vous devez faire est de comprendre comment le déploiement peut affecter ou affecter les utilisateurs. Y aura-t-il des temps d'arrêt? Si c'est le cas, quel est le temps d'arrêt? Comment cela affectera-t-il les utilisateurs? Quels sont les meilleurs et les pires scénarios? Et fermez les risques.
- Planifiez tout. À chaque étape, vous devez comprendre tous les aspects du déploiement:
- livraison de code;
- restauration du code;
- l'heure de chaque opération;
- fonctionnalité affectée.
- Jouez des scénarios jusqu'à ce que toutes les étapes de déploiement soient claires, ainsi que les risques pour chacune d'elles. En cas de doute, vous pouvez faire une pause et explorer la scène douteuse séparément.
- Chaque étape peut et doit être améliorée si elle aide nos utilisateurs. Par exemple, cela réduira les temps d'arrêt ou supprimera certains risques.
- Le test de restauration est beaucoup plus important que le test de livraison de code. Il est nécessaire de vérifier qu'à la suite de la restauration, le système reviendra à son état d'origine, confirmez-le avec des tests.
- Tout ce qui peut être automatisé doit être automatisé. Tout ce qui ne peut pas être automatisé doit être pré-écrit sur la feuille de triche.
- Enregistrer les critères de réussite. Quelles fonctionnalités devraient être disponibles et à quelle heure? Si cela ne se produit pas, démarrez un plan de restauration.
- Et surtout, les gens. Chacun doit être conscient de ce qu'il fait, de quoi et de ce qui dépend de ses actions en cours de déploiement.
Et si en une phrase, alors avec une bonne planification et élaboration, vous pouvez déployer tout ce que vous voulez sans conséquences pour la vente. Même cela affecte tous vos services en prod.