Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

L'approche IaC (Infrastructure as Code) comprend non seulement le code stocké dans le référentiel, mais également les personnes et les processus qui entourent ce code. Est-il possible de réutiliser les approches allant du développement logiciel à la gestion et à la description des infrastructures ? Ce serait une bonne idée de garder cette idée à l’esprit pendant que vous lisez l’article.

Version anglaise

Ceci est une transcription de mon des performances sur DevopsConf 2019-05-28.

Diapositives et vidéos

L'infrastructure comme histoire de bash

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Supposons que vous arriviez à un nouveau projet et qu'ils vous disent : « nous avons L'infrastructure comme code". En réalité, il s'avère L'infrastructure comme histoire de bash ou par exemple Documentation comme historique bash. C'est une situation très réelle, par exemple, un cas similaire a été décrit par Denis Lysenko dans un discours Comment remplacer toute l’infrastructure et commencer à bien dormir, il a expliqué comment ils ont obtenu une infrastructure cohérente pour le projet à partir de l'histoire de bash.

Avec une certaine envie, on peut dire que L'infrastructure comme histoire de bash c'est comme le code :

  1. reproductibilité: Vous pouvez prendre l'historique bash, exécuter les commandes à partir de là et vous pourriez, en passant, obtenir une configuration fonctionnelle en sortie.
  2. gestion des versions: vous savez qui est entré et ce qu'ils ont fait, encore une fois, ce n'est pas un fait que cela vous mènera à une configuration fonctionnelle à la sortie.
  3. histoire: l'histoire de qui a fait quoi. seulement vous ne pourrez pas l'utiliser si vous perdez le serveur.

Que faire?

L'infrastructure comme code

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Même un cas aussi étrange que L'infrastructure comme histoire de bash tu peux le tirer par les oreilles L'infrastructure comme code, mais quand nous voulons faire quelque chose de plus compliqué que le bon vieux serveur LAMP, nous arriverons à la conclusion que ce code doit être modifié, changé, amélioré d'une manière ou d'une autre. Nous aimerions ensuite examiner les parallèles entre L'infrastructure comme code et développement de logiciels.

SÉCHER

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Dans le cadre d'un projet de développement de système de stockage, il y avait une sous-tâche configurer périodiquement SDS: nous publions une nouvelle version - elle doit être déployée pour des tests plus approfondis. La tâche est extrêmement simple :

  • connectez-vous ici via ssh et exécutez la commande.
  • copiez le fichier ici.
  • corrigez la configuration ici.
  • démarrez le service là-bas
  • ...
  • PROFIT!

Pour la logique décrite, bash est plus que suffisant, surtout dans les premiers stades du projet, lorsqu'il vient tout juste de démarrer. Ce ce n'est pas mal que tu utilises bash, mais au fil du temps, il y a des demandes pour déployer quelque chose de similaire, mais légèrement différent. La première chose qui me vient à l’esprit est le copier-coller. Et maintenant, nous avons déjà deux scripts très similaires qui font presque la même chose. Au fil du temps, le nombre de scripts a augmenté, et nous avons été confrontés au fait qu'il existe une certaine logique métier pour déployer une installation qui doit être synchronisée entre différents scripts, c'est assez compliqué.

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Il s'avère qu'il existe une pratique telle que DRY (Ne vous répétez pas). L'idée est de réutiliser le code existant. Cela semble simple, mais nous n’y sommes pas parvenus tout de suite. Dans notre cas, c'était une idée banale : séparer les configs des scripts. Ceux. logique métier de la façon dont l'installation est déployée séparément, configurations séparément.

SOLIDE pour CFM

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Au fil du temps, le projet s'est développé et continuation naturelle fut l’émergence d’Ansible. La principale raison de son apparition est qu'il y a une expertise au sein de l'équipe et que bash n'est pas conçu pour une logique complexe. Ansible a également commencé à contenir une logique complexe. Pour éviter qu'une logique complexe ne se transforme en chaos, il existe des principes d'organisation du code dans le développement de logiciels. SOLIDE En outre, par exemple, Grigory Petrov, dans le rapport «Pourquoi un informaticien a-t-il besoin d'une marque personnelle», a soulevé la question selon laquelle une personne est conçue de telle manière qu'il lui est plus facile d'opérer avec certaines entités sociales, dans le développement de logiciels, ces sont des objets. Si nous combinons ces deux idées et continuons à les développer, nous remarquerons que nous pouvons également utiliser SOLIDE pour faciliter le maintien et la modification de cette logique à l'avenir.

Le principe de responsabilité unique

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Chaque classe n'effectue qu'une seule tâche.

Pas besoin de mélanger le code et de créer des monstres spaghetti divins monolithiques. L'infrastructure doit être constituée de briques simples. Il s'avère que si vous divisez le playbook Ansible en petits morceaux et lisez les rôles Ansible, ils sont alors plus faciles à maintenir.

Le principe ouvert fermé

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Principe ouvert/fermé.

  • Ouvert à l'extension : signifie que le comportement d'une entité peut être étendu en créant de nouveaux types d'entités.
  • Fermé au changement : suite à l'extension du comportement d'une entité, aucune modification ne doit être apportée au code qui utilise ces entités.

Initialement, nous avons déployé l'infrastructure de test sur des machines virtuelles, mais comme la logique métier du déploiement était distincte de la mise en œuvre, nous avons ajouté le déploiement sur baremetall sans aucun problème.

Le principe de substitution de Liskov

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Le principe de substitution de Barbara Liskov. les objets d'un programme doivent être remplaçables par des instances de leurs sous-types sans modifier l'exécution correcte du programme

Si vous regardez les choses plus largement, ce n'est pas une caractéristique d'un projet particulier qui peut y être appliquée. SOLIDE, il s'agit généralement de CFM, par exemple, sur un autre projet il faut déployer une application Java boxée au-dessus de divers Java, serveurs d'applications, bases de données, OS, etc. En utilisant cet exemple, je considérerai d'autres principes SOLIDE

Dans notre cas, il existe un accord au sein de l'équipe d'infrastructure selon lequel si nous avons installé le rôle imbjava ou oraclejava, alors nous avons un exécutable binaire java. C'est nécessaire parce que Les rôles en amont dépendent de ce comportement ; ils attendent Java. Dans le même temps, cela nous permet de remplacer une implémentation/version Java par une autre sans modifier la logique de déploiement de l'application.

Le problème ici réside dans le fait qu'il est impossible de l'implémenter dans Ansible, ce qui entraîne l'apparition de certains accords au sein de l'équipe.

Le principe de ségrégation des interfaces

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Principe de séparation des interfaces : « De nombreuses interfaces spécifiques au client valent mieux qu'une seule interface à usage général.

Au départ, nous avons essayé de regrouper toute la variabilité du déploiement d'applications dans un seul playbook Ansible, mais c'était difficile à prendre en charge, et l'approche lorsque nous avons une interface externe spécifiée (le client attend le port 443), alors une infrastructure peut être assemblée à partir de données individuelles. briques pour une implémentation spécifique.

Le principe d'inversion de dépendance

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Le principe de l'inversion des dépendances. Les modules des niveaux supérieurs ne devraient pas dépendre des modules des niveaux inférieurs. Les deux types de modules doivent dépendre d'abstractions. Les abstractions ne devraient pas dépendre de détails. Les détails doivent dépendre des abstractions.

Ici, l'exemple sera basé sur un anti-modèle.

  1. L'un des clients disposait d'un cloud privé.
  2. Nous avons commandé des machines virtuelles dans le cloud.
  3. Mais en raison de la nature du cloud, le déploiement des applications était lié à l'hyperviseur sur lequel se trouvait la VM.

Ceux. La logique de déploiement d'applications de haut niveau s'accompagnait de dépendances vers les niveaux inférieurs de l'hyperviseur, ce qui impliquait des problèmes lors de la réutilisation de cette logique. Ne fais pas ça.

Interaction

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

L'infrastructure en tant que code ne concerne pas seulement le code, mais aussi la relation entre le code et les personnes, les interactions entre les développeurs d'infrastructures.

Facteur d'autobus

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Supposons que Vasya soit sur votre projet. Vasya sait tout sur votre infrastructure, que se passera-t-il si Vasya disparaît soudainement ? C'est une situation bien réelle, car il pourrait être heurté par un bus. Des fois ça arrive. Si cela se produit et que les connaissances sur le code, sa structure, son fonctionnement, ses apparences et ses mots de passe ne sont pas réparties au sein de l'équipe, vous risquez alors de rencontrer un certain nombre de situations désagréables. Pour minimiser ces risques et diffuser les connaissances au sein de l'équipe, vous pouvez utiliser différentes approches

Développement de paires

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Ce n'est pas comme comme une blague, que les administrateurs ont bu de la bière, changé les mots de passe et un analogue de la programmation en binôme. Ceux. deux ingénieurs s'assoient devant un ordinateur, un clavier et commencent ensemble à configurer votre infrastructure : configuration d'un serveur, écriture d'un rôle Ansible, etc. Cela semble bien, mais cela n'a pas fonctionné pour nous. Mais des cas particuliers de cette pratique ont fonctionné. Un nouvel employé arrive, son mentor assume avec lui une vraie tâche, travaille et transfère des connaissances.

Un autre cas particulier est celui d’un appel incident. Lors d'un problème, un groupe de personnes en service et impliquées se réunit, un leader est nommé, qui partage son écran et exprime le fil de ses pensées. D’autres participants suivent les pensées du leader, espionnent les astuces depuis la console, vérifient qu’ils n’ont pas manqué une ligne dans le journal et apprennent de nouvelles choses sur le système. Cette approche a fonctionné le plus souvent.

Examen du code

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Subjectivement, il était plus efficace de diffuser les connaissances sur l'infrastructure et son fonctionnement en utilisant la revue de code :

  • L'infrastructure est décrite par du code dans le référentiel.
  • Les changements se produisent dans une branche distincte.
  • Lors d'une demande de fusion, vous pouvez voir le delta des modifications dans l'infrastructure.

Le point fort ici était que les évaluateurs étaient sélectionnés un par un, selon un calendrier, c'est-à-dire avec un certain degré de probabilité, vous grimperez dans une nouvelle infrastructure.

Style de code

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Au fil du temps, des querelles ont commencé à apparaître lors des révisions, car... les évaluateurs avaient leur propre style et la rotation des évaluateurs les empilait avec différents styles : 2 espaces ou 4, camelCase ou Snake_case. Il n’a pas été possible de mettre cela en œuvre tout de suite.

  • La première idée était de recommander l'utilisation de linter, après tout, tout le monde est ingénieur, tout le monde est intelligent. Mais différents éditeurs, OS, ne sont pas pratiques
  • Cela a évolué vers un robot qui écrivait sur Slack pour chaque commit problématique et joignait la sortie linter. Mais dans la plupart des cas, il y avait des choses plus importantes à faire et le code restait inchangé.

Maître de la construction verte

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Le temps passe et nous sommes arrivés à la conclusion que les commits qui ne réussissent pas certains tests ne peuvent pas être autorisés dans le maître. Voilà ! Nous avons inventé le Green Build Master, pratiqué depuis longtemps dans le développement logiciel :

  • Le développement est en cours dans une branche distincte.
  • Des tests sont en cours sur ce fil.
  • Si les tests échouent, le code ne parviendra pas au maître.

Prendre cette décision a été très douloureux, parce que... a suscité beaucoup de controverses, mais cela en valait la peine, car... Les avis ont commencé à recevoir des demandes de fusion sans différences de style et, au fil du temps, le nombre de domaines problématiques a commencé à diminuer.

Tests IaC

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

En plus de la vérification de style, vous pouvez utiliser d'autres éléments, par exemple pour vérifier que votre infrastructure peut réellement se déployer. Ou vérifiez que les changements dans les infrastructures n’entraîneront pas de perte d’argent. Pourquoi cela pourrait-il être nécessaire ? La question est complexe et philosophique, il vaut mieux répondre par une histoire selon laquelle il y avait d'une manière ou d'une autre un autoscaler sur Powershell qui ne vérifiait pas les conditions aux limites => plus de VM ont été créées que nécessaire => le client a dépensé plus d'argent que prévu. Ce n'est pas très agréable, mais il serait tout à fait possible de détecter cette erreur plus tôt.

On pourrait se demander pourquoi rendre des infrastructures complexes encore plus complexes ? Les tests d'infrastructure, tout comme pour le code, ne visent pas à simplifier, mais à savoir comment votre infrastructure doit fonctionner.

Pyramide de tests IaC

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Tests IaC : analyse statique

Si vous déployez l'ensemble de l'infrastructure en même temps et vérifiez qu'elle fonctionne, vous constaterez peut-être que cela prend beaucoup de temps et nécessite beaucoup de temps. Par conséquent, la base doit être quelque chose qui fonctionne rapidement, il y en a beaucoup et elle couvre beaucoup d'endroits primitifs.

Bash est délicat

Regardons un exemple trivial. sélectionnez tous les fichiers du répertoire actuel et copiez-les vers un autre emplacement. La première chose qui me vient à l'esprit :

for i in * ; do 
    cp $i /some/path/$i.bak
done

Que faire s'il y a un espace dans le nom du fichier ? Bon ok, on est malin, on sait utiliser les guillemets :

for i in * ; do cp "$i" "/some/path/$i.bak" ; done

Bien joué? Non! Que se passe-t-il s'il n'y a rien dans le répertoire, c'est-à-dire la globalisation ne fonctionnera pas.

find . -type f -exec mv -v {} dst/{}.bak ;

Bien joué maintenant ? Non... J'ai oublié ce que peut contenir le nom du fichier n.

touch x
mv x  "$(printf "foonbar")"
find . -type f -print0 | xargs -0 mv -t /path/to/target-dir

Outils d'analyse statique

Le problème de l'étape précédente pourrait être détecté lorsque nous oubliions les guillemets, pour cela il existe de nombreux remèdes dans la nature Vérification des coquilles, en général, il y en a beaucoup, et vous pourrez très probablement trouver un linter pour votre pile sous votre IDE.

Langue
Outil

bash
Vérification des coquilles

Rubi
RuboCop

python
pylint

ansible
Charpie Ansible

Tests IaC : tests unitaires

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Comme nous l'avons vu dans l'exemple précédent, les linters ne sont pas omnipotents et ne peuvent pas signaler tous les problèmes. De plus, par analogie avec les tests dans le développement de logiciels, on peut rappeler les tests unitaires. Ce qui me vient immédiatement à l'esprit, c'est shunit, Junit, rspec, question. Mais que faire d'ansible, chef, saltstack et autres comme eux ?

Au tout début, nous avons parlé SOLIDE et que notre infrastructure devrait être constituée de petites briques. Leur heure est venue.

  1. L'infrastructure est divisée en petites briques, par exemple les rôles Ansible.
  2. Une sorte d'environnement est déployé, qu'il s'agisse d'un docker ou d'une VM.
  3. Nous appliquons notre rôle Ansible à cet environnement de test.
  4. Nous vérifions que tout a fonctionné comme prévu (nous effectuons des tests).
  5. Nous décidons ok ou pas ok.

Tests IaC : outils de tests unitaires

Question, que sont les tests pour CFM ? Vous pouvez simplement exécuter le script ou utiliser des solutions prêtes à l'emploi pour cela :

CFM
Outil

Ansible
Testinfra

Chef
Inspecter

Chef
Spécification du serveur

pile de sel
Goss

Exemple pour testinfra, vérifiant que les utilisateurs test1, test2 exister et faire partie d'un groupe sshusers:

def test_default_users(host):
    users = ['test1', 'test2' ]
    for login in users:
        assert host.user(login).exists
        assert 'sshusers' in host.user(login).groups

Que choisir ? La question est complexe et ambiguë, voici un exemple d'évolution des projets sur github pour 2018-2019 :

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Cadres de tests IaC

La question se pose : comment tout mettre en place et le lancer ? Peut prends-le et fais-le toi-même s'il y a un nombre suffisant d'ingénieurs. Ou vous pouvez prendre des solutions toutes faites, même si elles ne sont pas très nombreuses :

CFM
Outil

Ansible
Molécule

Chef
Cuisine d'essai

Terraform
Test de terrasse

Exemple de changements dans les projets sur github pour 2018-2019 :

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Molécule contre Cuisine d'essai

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Au départ nous j'ai essayé d'utiliser testkitchen:

  1. Créez une VM en parallèle.
  2. Appliquez des rôles Ansible.
  3. Exécutez une inspection.

Pour 25 à 35 rôles, cela durait 40 à 70 minutes, ce qui était long.

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

L'étape suivante a été la transition vers jenkins/docker/ansible/molecule. Idiologiquement, tout est pareil

  1. Livres de jeu Lint.
  2. Alignez les rôles.
  3. Conteneur de lancement
  4. Appliquez des rôles Ansible.
  5. Exécutez testinfra.
  6. Vérifiez l'idempotence.

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Le peluchage de 40 rôles et les tests d'une douzaine ont commencé à prendre environ 15 minutes.

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Le choix dépend de nombreux facteurs, tels que la pile utilisée, l'expertise de l'équipe, etc. ici, chacun décide lui-même comment clôturer la question du test unitaire

Tests IaC : tests d'intégration

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

La prochaine étape de la pyramide des tests d’infrastructure sera celle des tests d’intégration. Ils sont similaires aux tests unitaires :

  1. L'infrastructure est divisée en petites briques, par exemple les rôles Ansible.
  2. Une sorte d'environnement est déployé, qu'il s'agisse d'un docker ou d'une VM.
  3. Pour cet environnement de test, postulez beaucoup Rôles Ansibles.
  4. Nous vérifions que tout a fonctionné comme prévu (nous effectuons des tests).
  5. Nous décidons ok ou pas ok.

En gros, nous ne vérifions pas les performances d'un élément individuel du système comme dans les tests unitaires, nous vérifions comment le serveur est configuré dans son ensemble.

Tests IaC : tests de bout en bout

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Au sommet de la pyramide, nous sommes accueillis par les tests End to End. Ceux. Nous ne vérifions pas les performances d'un serveur distinct, d'un script distinct ou d'une brique distincte de notre infrastructure. Nous vérifions que de nombreux serveurs sont connectés entre eux et que notre infrastructure fonctionne comme nous l'espérons. Malheureusement, je n'ai jamais vu de solutions prêtes à l'emploi, probablement parce que... L'infrastructure est souvent unique et difficile à modéliser et à créer un cadre de test. En conséquence, chacun crée ses propres solutions. Il y a une demande, mais il n’y a pas de réponse. Par conséquent, je vais vous dire ce qu'il y a pour pousser les autres à réfléchir ou me frotter le nez sur le fait que tout a été inventé il y a longtemps avant nous.

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Un projet avec une histoire riche. Il est utilisé dans les grandes organisations et chacun d’entre vous l’a probablement croisé indirectement. L'application prend en charge de nombreuses bases de données, intégrations, etc. Savoir à quoi pourrait ressembler l'infrastructure nécessite de nombreux fichiers Docker-Compose et savoir quels tests exécuter dans quel environnement est Jenkins.

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Ce schéma a fonctionné assez longtemps, jusqu'à ce que dans le cadre recherche nous n'avons pas essayé de transférer cela vers Openshift. Les conteneurs restent les mêmes, mais l'environnement de lancement a changé (bonjour encore DRY).

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

L'idée de recherche est allée plus loin et dans openshift, ils ont trouvé un élément tel que APB (Ansible Playbook Bundle), qui vous permet de regrouper les connaissances sur la façon de déployer une infrastructure dans un conteneur. Ceux. il existe un point de connaissances reproductible et testable sur la manière de déployer l’infrastructure.

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

Tout cela semblait bien jusqu'à ce que nous tombions sur une infrastructure hétérogène : nous avions besoin de Windows pour les tests. En conséquence, la connaissance de quoi, où, comment déployer et tester se trouve dans Jenkins.

Conclusion

Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure

L'infrastructure telle que le code est

  • Code dans le référentiel.
  • Interaction humaine.
  • Tests d'infrastructures.

Gauche

Source: habr.com

Ajouter un commentaire