Comment Dark déploie le code en 50 ms

Comment Dark déploie le code en 50 ms

Plus le processus de développement est rapide, plus l'entreprise technologique se développe rapidement.

Malheureusement, les applications modernes travaillent contre nous - nos systĂšmes doivent ĂȘtre mis Ă  jour en temps rĂ©el tout en Ă©tant invisibles et sans provoquer de temps d'arrĂȘt ou d'interruptions. Le dĂ©ploiement dans de tels systĂšmes devient une tĂąche complexe qui nĂ©cessite des pipelines de livraison continue mĂȘme pour de petites Ă©quipes.

Ces pipelines ont souvent une application limitée, fonctionnent lentement et manquent de fiabilité. Les développeurs doivent d'abord les créer manuellement, puis les gérer, et les entreprises finissent souvent par embaucher des équipes DevOps entiÚres pour cela.

La vitesse de ces pipelines détermine la vitesse de développement. Pour les meilleures équipes, le déploiement prend de 5 à 10 minutes, mais en général, tout se fait beaucoup plus lentement, et un seul déploiement peut prendre plusieurs heures.

Chez Dark, cela prend 50 ms. Cinquante. Millisecondes.. Dark - c'est une solution complĂšte avec un langage de programmation, un Ă©diteur et une infrastructure, spĂ©cialement conçue pour la livraison continue, et tous les aspects de Dark, y compris le langage lui-mĂȘme, sont construits pour un dĂ©ploiement instantanĂ© et sĂ»r.

Pourquoi les pipelines de livraison continue sont-ils si lents ?

Supposons que nous avons une application web Python et que nous avons déjà créé un excellent et moderne pipeline de livraison continue. Pour un développeur qui travaille sur ce projet chaque jour, le déploiement d'un changement mineur ressemblerait à peu prÚs à cela :

Effectuer les modifications.

  • CrĂ©er une nouvelle branche dans git.
  • Apporter des modifications avec le commutateur de fonctionnalitĂ©s.
  • Test unitaire pour vĂ©rifier les modifications avec et sans le commutateur de fonctionnalitĂ©s.

Demande de tirage.

  • Valider les modifications.
  • Envoyer les modifications dans le dĂ©pĂŽt distant sur github.
  • Demande de tirage.
  • La compilation CI s'exĂ©cute automatiquement en arriĂšre-plan.
  • Revue de code.
  • Quelques autres revues si nĂ©cessaire.
  • Fusionner les modifications avec la branche principale de git.

CI s'exécute sur la branche principale.

  • Installer les dĂ©pendances frontend via npm.
  • Compiler et optimiser les ressources HTML+CSS+JS.
  • ExĂ©cuter des tests unitaires et fonctionnels en frontend.
  • Installer les dĂ©pendances Python depuis PyPI.
  • ExĂ©cuter des tests unitaires et fonctionnels en backend.
  • Test d'intĂ©gration aux deux extrĂ©mitĂ©s.
  • Envoyer les ressources frontend vers le CDN.
  • Construire le conteneur pour le programme Python.
  • Envoi du conteneur au registre
  • Mise Ă  jour du manifeste Kubernetes

Remplacement de l'ancien code par le nouveau

  • Kubernetes lance plusieurs instances du nouveau conteneur
  • Kubernetes attend que les instances soient opĂ©rationnelles
  • Kubernetes ajoute les instances au rĂ©partiteur de charge HTTP
  • Kubernetes attend que les anciennes instances cessent d'ĂȘtre utilisĂ©es
  • Kubernetes arrĂȘte les anciennes instances
  • Kubernetes rĂ©pĂšte ces opĂ©rations jusqu'Ă  ce que les nouvelles instances remplacent toutes les anciennes

Activation du nouveau commutateur de fonctionnalités

  • Le nouveau code est activĂ© uniquement pour lui-mĂȘme afin de s'assurer que tout fonctionne correctement
  • Le nouveau code est activĂ© pour 10% des utilisateurs, les indicateurs opĂ©rationnels et commerciaux sont suivis
  • Le nouveau code est activĂ© pour 50% des utilisateurs, les indicateurs opĂ©rationnels et commerciaux sont suivis
  • Le nouveau code est activĂ© pour 100% des utilisateurs, les indicateurs opĂ©rationnels et commerciaux sont suivis
  • Enfin, vous rĂ©pĂ©tez toute la procĂ©dure pour supprimer l'ancien code et le commutateur

Le processus dépend des outils, du langage et de l'utilisation d'architectures orientées services, mais en général, il ressemble à cela. Je n'ai pas mentionné les déploiements avec migration de bases de données, car cela nécessite une planification minutieuse, mais ci-dessous, je vais expliquer comment Dark s'en occupe.

Il y a de nombreux composants ici, et beaucoup d'entre eux peuvent facilement ralentir, tomber en panne, provoquer une concurrence temporaire ou faire exploser un systĂšme de travail.

Et puisque ces pipelines sont presque toujours créés pour des cas particuliers, il est difficile de s'y fier. Beaucoup de gens rencontrent des jours oĂč le code ne peut pas ĂȘtre dĂ©ployĂ©, car il y a des problĂšmes dans le Dockerfile, un des dizaines de services a Ă©chouĂ© ou le spĂ©cialiste nĂ©cessaire est en congĂ©.

Pire encore, beaucoup de ces Ă©tapes ne font rien de utile. Elles Ă©taient nĂ©cessaires auparavant, lorsque nous dĂ©ployions le code immĂ©diatement pour les utilisateurs, mais maintenant nous avons des commutateurs pour le nouveau code, et ces processus sont sĂ©parĂ©s. Au final, l'Ă©tape oĂč le code est dĂ©ployĂ© (l'ancien Ă©tant remplacĂ© par le nouveau) est devenue simplement un risque inutile.

Bien sûr, c'est un pipeline trÚs bien pensé. L'équipe qui l'a créé n'a pas hésité à investir du temps et de l'argent pour un déploiement rapide. En général, les pipelines de déploiement sont beaucoup plus lents et moins fiables.

Mise en Ɠuvre de la livraison continue chez Dark

La livraison continue est si importante pour Dark que nous avons visé dÚs le départ un temps de moins d'une seconde. Nous avons passé en revue chaque étape du pipeline pour éliminer tout ce qui était superflu, et nous avons perfectionné le reste. Voici comment nous avons supprimé des étapes.

Jessie Frazelle (Jessie Frazelle) a inventé le nouveau mot deployless (sans déploiement) lors de la conférence Future of Software Development à Reykjavik.

Nous avons immĂ©diatement dĂ©cidĂ© que Dark serait basĂ© sur le concept « deployless » (merci Jessie Frazelle pour le nĂ©ologisme). Deployless signifie que tout code est dĂ©ployĂ© instantanĂ©ment et prĂȘt Ă  ĂȘtre utilisĂ© en production. Bien sĂ»r, nous ne laisserons pas passer du code dĂ©fectueux ou incomplet (je dĂ©crirai les principes de sĂ©curitĂ© ci-dessous).

Lors de la démonstration de Dark, on nous a souvent demandé comment nous avions réussi à accélérer le déploiement. Une question étrange. Les gens pensent probablement que nous avons inventé une sorte de super technologie qui compare le code, le compile, l'emballe dans un conteneur, lance une machine virtuelle, démarre le conteneur à froid, et tout ça en 50 ms. Ceci est peu probable. Mais nous avons créé un moteur de déploiement spécial qui n'a pas besoin de tout cela.

Dark exĂ©cute des interprĂštes dans le cloud. Supposons que vous Ă©criviez du code dans une fonction ou un gestionnaire HTTP ou d'Ă©vĂ©nements. Nous envoyons un diff Ă  un arbre syntaxique abstrait (reprĂ©sentation du code que notre Ă©diteur et nos serveurs utilisent en interne) Ă  nos serveurs, puis nous exĂ©cutons ce code lorsque des requĂȘtes arrivent. Ainsi, le dĂ©ploiement ressemble simplement Ă  une modeste entrĂ©e dans la base de donnĂ©es — instantanĂ© et Ă©lĂ©mentaire. Le dĂ©ploiement est si rapide car il inclut le strict minimum.

À l'avenir, nous prĂ©voyons de faire de Dark un compilateur d'infrastructure qui crĂ©era et lancera l'infrastructure idĂ©ale pour une haute performance et une fiabilitĂ© des applications. Le dĂ©ploiement instantanĂ© ne disparaĂźtra bien sĂ»r pas.

Déploiement sécurisé

Éditeur structurĂ©

Le code dans Dark est Ă©crit dans l'Ă©diteur Dark. L'Ă©diteur structurĂ© ne permet pas d'erreurs de syntaxe. En gros, il n'y a mĂȘme pas d'analiseur dans Dark. Tant que vous saisissez du texte, nous travaillons directement avec l'arbre syntaxique abstrait (AST), comme Paredit, Sketch-n-Sketch, Tofu, Prune et MPS.

Tout code incomplet dans Dark a une sémantique d'exécution valide, un peu comme des holes typés dans Hazel. Par exemple, si vous modifiez un appel de fonction, nous conservons l'ancienne fonction jusqu'à ce que la nouvelle soit opérationnelle.

Chaque programme dans Dark a son propre sens, donc le code incomplet n'empĂȘche pas le code complet de fonctionner.

Modes d'édition

Vous Ă©crivez du code dans Dark dans deux cas. Premier cas : vous Ă©crivez du nouveau code et ĂȘtes le seul utilisateur. Par exemple, il se trouve dans REPL, et d'autres utilisateurs n'y auront jamais accĂšs, ou c'est une nouvelle route HTTP Ă  laquelle vous ne faites rĂ©fĂ©rence nulle part. Vous pouvez travailler sans prĂ©cautions, et c'est exactement comme cela que vous travaillez actuellement dans un environnement de dĂ©veloppement.

DeuxiÚme situation : le code est déjà utilisé. Si le code reçoit du trafic (fonctions, gestionnaires d'événements, bases de données, etc.), il faut faire attention. Pour cela, nous bloquons tout code utilisé et exigeons que des outils plus structurés soient utilisés pour l'édition. Je parlerai des outils structuraux ci-dessous : des commutateurs de fonctionnalités pour les gestionnaires HTTP et d'événements, une puissante plateforme de migration pour les bases de données et une nouvelle méthode de gestion des versions pour les fonctions et types.

Commutateurs de fonctionnalités

Une des maniÚres d'éliminer la complexité inutile dans Dark est de résoudre plusieurs problÚmes avec une seule solution. Les commutateurs de fonctionnalités exécutent de nombreuses tùches différentes : remplacer l'environnement de développement local, créer des branches git, déployer le code et, bien sûr, le lancement traditionnel lent et contrÎlé de nouveau code.

La création et le déploiement d'un commutateur de fonctionnalité se font dans notre éditeur en une seule opération. Il crée un espace vide pour le nouveau code et fournit des contrÎles d'accÚs au code ancien et nouveau, ainsi que des boutons et des commandes pour passer progressivement au nouveau code ou l'exclure.

Les commutateurs de fonctionnalitĂ©s sont intĂ©grĂ©s au langage Dark, et mĂȘme les commutateurs inachevĂ©s accomplissent leur tĂąche : si la condition du commutateur n'est pas remplie, le code ancien bloquĂ© sera exĂ©cutĂ©.

Environnement de développement

Les commutateurs de fonctionnalitĂ©s remplacent l'environnement de dĂ©veloppement local. Aujourd'hui, il est difficile pour les Ă©quipes de s'assurer que tout le monde utilise les mĂȘmes versions des outils et des bibliothĂšques (outils de formatage de code, linters, gestionnaires de paquets, compilateurs, prĂ©processeurs, outils de test, etc.). Avec Dark, il n'est pas nĂ©cessaire d'installer les dĂ©pendances localement, de gĂ©rer une installation locale de Docker ou de prendre d'autres mesures pour garantir un semblant d'Ă©galitĂ© entre l'environnement de dĂ©veloppement et la production. Étant donnĂ© que cette Ă©galitĂ© est de toute façon impossible,nous ne ferons mĂȘme pas semblant de viser cela.

Au lieu de crĂ©er un environnement local clonĂ©, les commutateurs dans Dark crĂ©ent un nouveau bac Ă  sable en production, remplaçant l'environnement de dĂ©veloppement. À l'avenir, nous prĂ©voyons Ă©galement de crĂ©er des bacs Ă  sable pour d'autres parties de l'application (comme des clones instantanĂ©s de bases de donnĂ©es), mĂȘme si cela ne semble pas encore si important.

Branches et déploiements

Il existe actuellement plusieurs façons d'introduire du nouveau code dans les systĂšmes : branches git, Ă©tapes de dĂ©ploiement et commutateurs de fonctionnalitĂ©s. Elles rĂ©solvent un mĂȘme problĂšme Ă  diffĂ©rentes Ă©tapes du flux de travail : git - aux Ă©tapes avant le dĂ©ploiement, le dĂ©ploiement - au moment de la transition de l'ancien code vers le nouveau, et les commutateurs de fonctionnalitĂ©s - pour le dĂ©ploiement contrĂŽlĂ© de nouveau code.

Le moyen le plus efficace est d'utiliser des commutateurs de fonctionnalitĂ©s (qui sont en mĂȘme temps les plus simples Ă  comprendre et Ă  utiliser). Cela permet de se passer complĂštement des deux autres mĂ©thodes. En particulier, il est utile de supprimer le dĂ©ploiement - si nous utilisons dĂ©jĂ  des commutateurs de fonctionnalitĂ©s pour activer le code, alors l'Ă©tape de transition des serveurs vers le nouveau code ne fait qu'ajouter des risques inutiles.

Git est difficile à utiliser, surtout pour les débutants, et cela le limite énormément, mais il a l'avantage d'avoir des branches pratiques. Nous avons atténué de nombreux inconvénients de git. Dark permet l'édition en temps réel et offre des possibilités de collaboration à la Google Docs, ce qui évite d'avoir à envoyer du code et rend plus rare le besoin de rebaser et de fusionner.

Les commutateurs de fonctionnalitĂ©s sont essentiels pour un dĂ©ploiement sĂ©curisĂ©. CouplĂ©s aux dĂ©ploiements instantanĂ©s, ils permettent de tester rapidement des concepts en petits morceaux Ă  faible risque, plutĂŽt que d’appliquer un seul gros changement qui pourrait faire planter le systĂšme.

Versioning.

Pour modifier les fonctions et les types, nous utilisons la versioning. Si vous souhaitez changer une fonction, Dark crĂ©e une nouvelle version de cette fonction. Vous pouvez ensuite appeler cette version avec un commutateur dans le gestionnaire HTTP ou d'Ă©vĂ©nements. (Si cette fonction est profondĂ©ment ancrĂ©e dans le graphe d'appels, une nouvelle version de chaque fonction sera créée en cours de route. Cela peut sembler excessif, mais les fonctions ne posent pas de problĂšme si vous ne les utilisez pas, donc vous ne le remarquerez mĂȘme pas.)

Pour les mĂȘmes raisons, nous faisons du versioning pour les types. Nous avons dĂ©jĂ  parlĂ© en dĂ©tail de notre systĂšme de types. dans le post prĂ©cĂ©dent.

GrĂące au versioning des fonctions et des types, vous pouvez modifier l'application progressivement. Il est possible de s'assurer que chaque gestionnaire fonctionne avec la nouvelle version sans avoir Ă  apporter tous les changements Ă  l'application en mĂȘme temps (mais nous avons des outils pour le faire rapidement si vous le souhaitez).

C'est beaucoup plus sûr que de déployer tout d'un coup, comme cela se fait actuellement.

Nouvelles versions des paquets et bibliothĂšque standard

Lorsque vous mettez Ă  jour un paquet dans Dark, nous ne remplaçons pas immĂ©diatement chaque utilisation de fonction ou de type dans toute la base de code. Ce serait dangereux. Le code continue d'utiliser la mĂȘme version qu'il utilisait, et vous mettez Ă  jour les utilisations des fonctions et des types vers la nouvelle version pour chaque cas individuel Ă  l'aide des commutateurs.

Comment Dark déploie le code en 50 ms
Capture d'écran d'une partie du processus automatique dans Dark, montrant deux versions de la fonction Dict::get. Dict::get_v0 retournait le type Any (que nous abandonnons), tandis que Dict::get_v1 retourne le type Option.

Nous fournissons souvent une nouvelle fonction dans la bibliothÚque standard et excluons les anciennes versions. Les utilisateurs avec d'anciennes versions dans leur code pourront y accéder, mais les nouveaux utilisateurs ne pourront pas les obtenir. Nous prévoyons de fournir des outils pour transférer les utilisateurs des anciennes versions vers les nouvelles en une seule étape, encore une fois avec des commutateurs de fonctionnalités.

Dark offre Ă©galement une opportunitĂ© unique : Ă©tant donnĂ© que nous exĂ©cutons votre code de travail, nous pouvons tester nous-mĂȘmes les nouvelles versions, en comparant les rĂ©sultats pour les nouvelles et anciennes requĂȘtes afin de vous informer des changements. Au final, la mise Ă  jour des paquets, qui est souvent effectuĂ©e Ă  l'aveugle (ou nĂ©cessite des tests approfondis pour des raisons de sĂ©curitĂ©), reprĂ©sente beaucoup moins de risques et peut se faire automatiquement.

Nouvelles versions de Dark

La transition de Python 2 Ă  Python 3 s'est Ă©talĂ©e sur une dĂ©cennie et reste un problĂšme aujourd'hui. Étant donnĂ© que nous dĂ©veloppons Dark pour une livraison continue, ces changements de langage doivent ĂȘtre pris en compte.

Lorsque nous apportons de petites modifications au langage, nous créons une nouvelle version de Dark. L'ancien code reste dans l'ancienne version de Dark, tandis que le nouveau code est utilisé dans la nouvelle version. Pour passer à la nouvelle version de Dark, vous pouvez utiliser des bascules ou des versions de fonctionnalités.

C'est particuliÚrement utile, étant donné que Dark est apparu tout récemment. De nombreux changements dans la langue ou la bibliothÚque peuvent échouer. Le versionnage progressif du langage nous permet de procéder à des mises à jour mineures, ce qui signifie que nous pouvons prendre notre temps et différer de nombreuses décisions concernant le langage tant que nous n'avons pas plus d'utilisateurs, et donc plus d'informations.

Migrations de bases de données

Pour une migration sécurisée de la base de données, il existe une formule standard:

  • Réécrire le code pour prendre en charge les nouveaux et anciens formats
  • Convertir toutes les donnĂ©es dans le nouveau format
  • Supprimer l'ancien accĂšs aux donnĂ©es

En fin de compte, la migration de la base de donnĂ©es s'Ă©ternise et exige beaucoup de ressources. Et nous avons des schĂ©mas obsolĂštes qui s'accumulent, car mĂȘme des tĂąches simples, comme corriger le nom d'une table ou d'une colonne, ne valent pas l'effort engagĂ©.

Dark dispose d'une plateforme de migration de bases de données efficace qui (nous l'espérons) simplifiera tellement le processus que vous cesserez de le craindre. Tous les stockages de données dans Dark (les magasins de paires « clé-valeur » ou les tables de hachage persistantes) ont un type. Pour transférer un stockage de données, il vous suffit de lui attribuer un nouveau type et une fonction de retour en arriÚre et de retour vers l'avant pour convertir les valeurs entre les deux types.

L'accÚs aux stockages de données dans Dark se fait par des noms de variables versionnés. Par exemple, le stockage de données Users sera initialement nommé Users-v0. Lorsqu'une nouvelle version avec un type différent est créée, le nom change en Users-v1. Si des données sont sauvegardées via Users-v0, et que vous y accédez via Users-v1, une fonction de restauration est appliquée. Si des données sont sauvegardées via Users-v1, et que vous y accédez via Users-v0, une fonction de rollback est appliquée.

Comment Dark déploie le code en 50 ms
L'écran de migration de base de données affiche les noms de champs de l'ancienne base de données, les expressions de restauration et de rollback, ainsi que des instructions pour activer la migration.

Utilisez des commutateurs de fonctionnalitĂ©s pour rediriger les appels de Users-v0 vers la version Users-v1. Cela peut se faire un gestionnaire HTTP Ă  la fois, afin de rĂ©duire les risques, et ces commutateurs fonctionnent pour des utilisateurs individuels, vous permettant de vĂ©rifier que tout fonctionne comme prĂ©vu. Une fois que les utilisateurs de Users-v0 ne seront plus, Dark convertira toutes les donnĂ©es restantes en arriĂšre-plan de l'ancien format vers le nouveau. Vous ne remarquerez mĂȘme pas.

Test

Dark est un langage de programmation fonctionnel avec typage statique et des valeurs immuables, ce qui rĂ©duit considĂ©rablement la surface de test par rapport aux langages orientĂ©s objet avec typage dynamique. Mais il faut quand mĂȘme tester.
Dans Dark, l'Ă©diteur exĂ©cute automatiquement des tests unitaires en arriĂšre-plan pour le code modifiable, et exĂ©cute par dĂ©faut ces tests pour tous les commutateurs de fonctionnalitĂ©s. À l'avenir, nous souhaitons utiliser des types statiques pour exĂ©cuter automatiquement le fuzzing du code afin de repĂ©rer les bugs.

De plus, Dark exĂ©cute votre infrastructure en production, ce qui ouvre de nouvelles possibilitĂ©s. Nous conservons automatiquement les requĂȘtes HTTP dans l'infrastructure Dark (pour l'instant, nous conservons toutes les requĂȘtes, mais nous souhaitons passer Ă  un Ă©chantillonnage plus tard). Nous testons le nouveau code sur celles-ci et rĂ©alisons des tests unitaires, et si vous le souhaitez, vous pouvez facilement transformer les requĂȘtes intĂ©ressantes en tests unitaires.

Ce dont nous nous sommes débarrassés

Étant donnĂ© que nous n'avons pas de dĂ©ploiement, mais des commutateurs de fonctionnalitĂ©s, environ 60 % du pipeline de dĂ©ploiement est laissĂ© de cĂŽtĂ©. Nous n'avons pas besoin de branches git ou de pull requests, de construction de ressources backend et de conteneurs, d'envoi de ressources et de conteneurs dans des registres ou d'Ă©tapes de dĂ©ploiement dans Kubernetes.

Comment Dark déploie le code en 50 ms
Comparaison entre un pipeline de livraison continue standard (à gauche) et la livraison continue de Dark (à droite). Dans Dark, la livraison se compose de 6 étapes et d'un cycle, tandis que la version traditionnelle comprend 35 étapes et 3 cycles.

Dans Dark, il n'y a que 6 Ă©tapes et 1 cycle dans le dĂ©ploiement (Ă©tapes qui se rĂ©pĂštent plusieurs fois), tandis que le pipeline moderne de livraison continue comprend 35 Ă©tapes et 3 cycles. Dans Dark, les tests se lancent automatiquement, et vous ne le voyez mĂȘme pas ; les dĂ©pendances s'installent automatiquement ; tout ce qui est liĂ© Ă  git ou Github n'est plus nĂ©cessaire ; la construction, les tests et l'envoi des conteneurs Docker ne sont plus requis ; le dĂ©ploiement sur Kubernetes n'est plus nĂ©cessaire.

MĂȘme les Ă©tapes restantes dans Dark sont devenues plus simples. Comme les fonctionnalitĂ©s peuvent ĂȘtre gĂ©rĂ©es par une seule action, il n'est plus nĂ©cessaire de passer Ă  nouveau par tout le pipeline de dĂ©ploiement pour enlever le vieux code.

Nous avons simplifié la livraison de code autant que possible, réduisant le temps et les risques associés à la livraison continue. De plus, nous avons considérablement simplifié la mise à jour des paquets, les migrations de bases de données, les tests, la gestion des versions, l'installation des dépendances, l'égalité entre l'environnement de développement et de production et des mises à jour rapides et sécurisées des versions de langage.

Je réponds aux questions à ce sujet sur HackerNews.

Pour en savoir plus sur l'appareil Dark, lisez l'article sur Dark, suivez-nous sur Twitter (ou sur moi) ou inscrivez-vous Ă  la version bĂȘta et recevez des notifications sur les prochains articles. Si vous assistez Ă  StrangeLoop en septembre, venez nous voir pour le lancement.

Source : habr.com

Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster