Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Ceci est la transcription des performances sur DevOps-40 2020-03-18:

À partir du deuxième commit, tout code devient hérité, car les idées initiales commencent à s’écarter de la dure réalité. Ce n’est ni bon ni mauvais, c’est une donnée avec laquelle il est difficile de discuter et avec laquelle il faut vivre. Une partie de ce processus consiste à refactoriser. Refactoriser l'infrastructure en tant que code. Que l'histoire commence sur la façon de refactoriser Ansible en un an et de ne pas devenir fou.

La naissance de l'héritage

Jour n°1 : Patient zéro

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Il était une fois un projet conditionnel. Il y avait une équipe de développement Dev et des ingénieurs Ops. Ils résolvaient le même problème : comment déployer des serveurs et exécuter une application. Le problème était que chaque équipe a résolu ce problème à sa manière. Lors du projet, il a été décidé d'utiliser Ansible pour synchroniser les connaissances entre les équipes Dev et Ops.

Jour #89 : La naissance de l'héritage

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Sans s’en rendre compte eux-mêmes, ils ont voulu le faire du mieux possible, mais cela s’est avéré être un héritage. Comment cela peut-il arriver?

  • Nous avons une tâche urgente ici, faisons un sale hack puis réparons-le.
  • Vous n’êtes pas obligé d’écrire de la documentation et tout est clair sur ce qui se passe ici.
  • Je connais Ansible/Python/Bash/Terraform ! Regardez comme je peux esquiver !
  • Je suis un développeur Full Stack Overflow et j'ai copié ceci depuis stackoverflow, je ne sais pas comment cela fonctionne, mais cela a l'air cool et résout le problème.

En conséquence, vous pouvez obtenir un type de code incompréhensible pour lequel il n'y a pas de documentation, on ne sait pas ce qu'il fait, s'il est nécessaire, mais le problème est que vous devez le développer, le modifier, ajouter des béquilles et des supports , rendant la situation encore pire.

- hosts: localhost
  tasks:
    - shell: echo -n Z >> a.txt && cat a.txt
      register: output
      delay: 1
      retries: 5
      until: not output.stdout.find("ZZZ")

Jour #109 : Prise de conscience du problème

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Le modèle IaC initialement conçu et mis en œuvre ne répond plus aux exigences des utilisateurs/métiers/autres équipes, et le temps nécessaire pour apporter des modifications à l'infrastructure cesse d'être acceptable. À ce moment-là, on comprend qu’il est temps d’agir.

Refactorisation IaC

Jour #139 : Avez-vous vraiment besoin d'une refactorisation ?

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Avant de vous précipiter dans une refactorisation, vous devez répondre à un certain nombre de questions importantes :

  1. Pourquoi as-tu besoin de tout ça ?
  2. As-tu du temps?
  3. La connaissance est-elle suffisante ?

Si vous ne savez pas comment répondre aux questions, la refactorisation se terminera avant même de commencer, ou elle pourrait ne faire qu'empirer. Parce que avait de l'expérience ( Ce que j'ai appris en testant 200 000 lignes de code d'infrastructure), puis le projet a reçu une demande d'aide pour fixer les rôles et les couvrir par des tests.

Jour #149 : Préparer le refactoring

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

La première chose est de se préparer. Décidez de ce que nous ferons. Pour ce faire, nous communiquons, trouvons les problèmes et trouvons des moyens de les résoudre. Nous enregistrons les concepts résultants d'une manière ou d'une autre, par exemple un article en confluence, de sorte que lorsque la question se pose « qu'est-ce qui est le mieux ? » ou "qu'est-ce qui est correct?" Nous ne nous sommes pas perdus. Dans notre cas, nous sommes restés fidèles à l'idée diviser pour régner: nous divisons l'infrastructure en petits morceaux/briques. Cette approche permet de prendre une infrastructure isolée, de comprendre ce qu'elle fait, de la couvrir de tests et de la modifier sans craindre de casser quoi que ce soit.

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Il s’avère que les tests d’infrastructure deviennent la pierre angulaire et il convient ici de mentionner la pyramide des tests d’infrastructure. Exactement la même idée qui est en développement, mais pour l'infrastructure : nous passons de tests rapides bon marché qui vérifient des choses simples, comme l'indentation, à des tests à part entière coûteux qui déploient l'ensemble de l'infrastructure.

Tentatives de tests Ansible

Avant de décrire comment nous avons couvert les tests Ansible sur le projet, je décrirai les tentatives et approches que j'ai eu l'occasion d'utiliser plus tôt afin de comprendre le contexte des décisions prises.

Jour N° -997 : Mise à disposition des FDS

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

La première fois que j'ai testé Ansible, c'était sur un projet de développement de SDS (Software Defined Storage). Il y a un article séparé sur ce sujet
Comment casser des vélos avec des béquilles lors du test de votre distribution, mais en bref, nous nous sommes retrouvés avec une pyramide de tests inversée et nous avons passé 60 à 90 minutes de test sur un rôle, ce qui est long. La base était les tests e2e, c'est-à-dire nous avons déployé une installation à part entière puis l'avons testée. Ce qui était encore plus agaçant, c'était l'invention de son propre vélo. Mais je dois admettre que cette solution a fonctionné et a permis une version stable.

Jour #-701 : Ansible et cuisine de test

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Le développement de l'idée de test Ansible a consisté à utiliser des outils prêts à l'emploi, à savoir test kitchen / kitchen-ci et inspec. Le choix a été déterminé par la connaissance de Ruby (pour plus de détails, voir l'article sur Habré : Les programmeurs YML rêvent-ils de tester Ansible ?) a travaillé plus vite, environ 40 minutes pour 10 rôles. Nous avons créé un pack de machines virtuelles et effectué des tests à l'intérieur.

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

En général, la solution a fonctionné, mais il y avait quelques sédiments dus à l'hétérogénéité. Lorsque le nombre de personnes testées a été augmenté à 13 rôles de base et 2 méta-rôles combinant des rôles plus petits, les tests ont soudainement commencé à durer 70 minutes, soit presque 2 fois plus longtemps. Il était difficile de parler des pratiques XP (programmation extrême) car... personne ne veut attendre 70 minutes. C'est la raison pour laquelle nous avons changé d'approche

Jour # -601 : Ansible et molécule

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Conceptuellement, cela est similaire à testkitchen, sauf que nous avons déplacé les tests de rôle vers Docker et modifié la pile. En conséquence, le temps a été réduit à 20-25 minutes stables pour 7 rôles.

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

En augmentant le nombre de rôles testés à 17 et en peluchant 45 rôles, nous avons exécuté cela en 28 minutes sur 2 esclaves Jenkins.

Jour #167 : Ajout des tests Ansible au projet

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Très probablement, il ne sera pas possible d’effectuer la tâche de refactoring à la hâte. La tâche doit être mesurable pour que vous puissiez la briser en petits morceaux et manger l'éléphant morceau par morceau avec une cuillère à café. Il faut comprendre si vous avancez dans la bonne direction, combien de temps il vous reste.

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

En général, peu importe comment cela sera fait, vous pouvez écrire sur un morceau de papier, vous pouvez mettre des autocollants sur le placard, vous pouvez créer des tâches dans Jira ou vous pouvez ouvrir Google Docs et noter l'état actuel. là. Les jambes grandissent du fait que le processus n'est pas immédiat, il sera long et fastidieux. Il est peu probable que quiconque veuille que vous soyez à court d’idées, fatigué et dépassé pendant la refactorisation.

La refactorisation est simple :

  • Mangez.
  • Sommeil.
  • Code.
  • Test IAC.
  • Répéter

et nous répétons cela jusqu'à ce que nous atteignions l'objectif visé.

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Il n'est peut-être pas possible de commencer à tout tester tout de suite, notre première tâche a donc été de commencer par le peluchage et de vérifier la syntaxe.

Jour #181 : Maître de la construction verte

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Le Linting est un petit premier pas vers Green Build Master. Cela ne cassera presque rien, mais cela vous permettra de déboguer les processus et de créer des builds écologiques dans Jenkins. L’idée est de développer des habitudes au sein de l’équipe :

  • Les tests rouges sont mauvais.
  • Je suis venu réparer quelque chose et en même temps rendre le code un peu meilleur qu'il ne l'était avant vous.

Jour #193 : Du peluchage aux tests unitaires

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Après avoir construit le processus d'introduction du code dans le maître, vous pouvez commencer le processus d'amélioration étape par étape - en remplaçant le peluchage par des rôles de lancement, vous pouvez même le faire sans idempotence. Vous devez comprendre comment appliquer les rôles et comment ils fonctionnent.

Jour #211 : Des tests unitaires aux tests d'intégration

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Lorsque la plupart des rôles sont couverts par des tests unitaires et que tout est lissé, vous pouvez passer à l'ajout de tests d'intégration. Ceux. tester non pas une seule brique de l'infrastructure, mais une combinaison de celles-ci, par exemple une configuration d'instance complète.

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

À l'aide de jenkins, nous avons généré de nombreuses étapes qui lintaient les rôles/playbooks en parallèle, puis les tests unitaires dans des conteneurs et enfin les tests d'intégration.

Jenkins + Docker + Ansible = Tests

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

  1. Récupérez le dépôt et générez des étapes de construction.
  2. Exécutez les étapes du playbook Lint en parallèle.
  3. Exécutez les étapes du rôle Lint en parallèle.
  4. Exécutez les étapes du rôle de vérification de la syntaxe en parallèle.
  5. Exécutez les étapes de rôle de test en parallèle.
    1. Rôle de peluche.
    2. Vérifiez la dépendance sur d'autres rôles.
    3. Vérifiez la syntaxe.
    4. Créer une instance Docker
    5. Exécutez molécule/default/playbook.yml.
    6. Vérifiez l'idempotence.
  6. Exécuter des tests d'intégration
  7. Finition

Jour #271 : Facteur Bus

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Au début, le refactoring était réalisé par un petit groupe de deux ou trois personnes. Ils ont examiné le code dans le maître. Au fil du temps, l’équipe a développé des connaissances sur la façon d’écrire du code et la révision du code a contribué à la diffusion des connaissances sur l’infrastructure et son fonctionnement. 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.

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Et ça devrait être confortable ici. Il est pratique de faire un bilan, de voir dans le cadre de quelle tâche cela a été réalisé et l’historique des discussions. Nous avons intégré jenkins + bitbucket + jira.

Mais en tant que tel, une révision n’est pas une panacée ; d’une manière ou d’une autre, nous sommes entrés dans le code maître, ce qui nous a fait échouer les tests :

- get_url:
    url: "{{ actk_certs }}/{{ item.1 }}"
    dest: "{{ actk_src_tmp }}/"
    username: "{{ actk_mvn_user }}"
    password: "{{ actk_mvn_pass }}"
  with_subelements:
    - "{{ actk_cert_list }}"
    - "{{ actk_certs }}"
  delegate_to: localhost

- copy:
    src: "{{ actk_src_tmp }}/{{ item.1 }}"
    dest: "{{ actk_dst_tmp }}"
  with_subelements:
    - "{{ actk_cert_list }}"
    - "{{ actk_certs }}"

Ensuite, ils l'ont réparé, mais les sédiments sont restés.

get_url:
    url: "{{ actk_certs }}/{{ actk_item }}"
    dest: "{{ actk_src_tmp }}/{{ actk_item }}"
    username: "{{ actk_mvn_user }}"
    password: "{{ actk_mvn_pass }}"
  loop_control:
    loop_var: actk_item
  with_items: "{{ actk_cert_list }}"
  delegate_to: localhost

- copy:
    src: "{{ actk_src_tmp }}/{{ actk_item }}"
    dest: "{{ actk_dst_tmp }}"
  loop_control:
    loop_var: actk_item
  with_items: "{{ actk_cert_list }}"

Jour #311 : Accélération des tests

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Au fil du temps, il y a eu davantage de tests, les builds se sont déroulés plus lentement, jusqu'à une heure dans le pire des cas. Sur l'une des rétros, il y avait une phrase comme "c'est bien qu'il y ait des tests, mais ils sont lents". En conséquence, nous avons abandonné les tests d'intégration sur les machines virtuelles et les avons adaptés pour Docker pour le rendre plus rapide. Nous avons également remplacé testinfra par ansible verifier pour réduire le nombre d'outils utilisés.

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

À proprement parler, il y avait un ensemble de mesures :

  1. Passez au docker.
  2. Supprimez les tests de rôle, qui sont dupliqués en raison des dépendances.
  3. Augmentez le nombre d'esclaves.
  4. Ordre d’exécution des tests.
  5. Capacité à pelucher TOUS localement avec une seule commande.

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

En conséquence, Pipeline sur Jenkins a également été unifié

  1. Générez des étapes de construction.
  2. Lint tout en parallèle.
  3. Exécutez les étapes de rôle de test en parallèle.
  4. Terminer.

Les leçons apprises

Évitez les variables globales

Ansible utilise des variables globales, il existe une solution de contournement partielle sous la forme private_role_vars, mais ce n'est pas une panacée.

Laisse moi te donner un exemple. Laissez-nous role_a и role_b

# cat role_a/defaults/main.yml
---
msg: a

# cat role_a/tasks/main.yml
---
- debug:
    msg: role_a={{ msg }}

# cat role_b/defaults/main.yml
---
msg: b

# cat role_b/tasks/main.yml
---
- set_fact:
    msg: b
- debug:
    msg: role_b={{ msg }}

- hosts: localhost
  vars:
    msg: hello
  roles:
    - role: role_a
    - role: role_b
  tasks:
    - debug:
        msg: play={{msg}}

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Ce qui est drôle, c’est que le résultat des playbooks dépendra de choses qui ne sont pas toujours évidentes, comme l’ordre dans lequel les rôles sont listés. Malheureusement, c'est la nature d'Ansible et la meilleure chose à faire est d'utiliser une sorte d'accord, par exemple, au sein d'un rôle, utilisez uniquement la variable décrite dans ce rôle.

BAD: utilisez une variable globale.

# cat roles/some_role/tasks/main.yml
---
debug:
  var: java_home

BON: V defaults définir les variables nécessaires et les utiliser ensuite uniquement.

# cat roles/some_role/defaults/main.yml
---
r__java_home:
 "{{ java_home | default('/path') }}"

# cat roles/some_role/tasks/main.yml
---
debug:
  var: r__java_home

Variables de rôle de préfixe

BAD: utilisez une variable globale.

# cat roles/some_role/defaults/main.yml
---
db_port: 5432

BON: Dans les rôles pour les variables, utilisez des variables préfixées par le nom du rôle ; cela, en regardant l'inventaire, permettra de mieux comprendre ce qui se passe.

# cat roles/some_role/defaults/main.yml
---
some_role__db_port: 5432

Utiliser la variable de contrôle de boucle

BAD: Utiliser la variable standard dans les boucles item, si cette tâche/playbook est inclus quelque part, cela peut entraîner un comportement inattendu

---
- hosts: localhost
  tasks:
    - debug:
        msg: "{{ item }}"
      loop:
        - item1
        - item2

BON: Redéfinir une variable dans une boucle via loop_var.

---
- hosts: localhost
  tasks:
    - debug:
        msg: "{{ item_name }}"
      loop:
        - item1
        - item2
      loop_control:
        loop_var: item_name

Vérifier les variables d'entrée

Nous avons convenu d'utiliser des préfixes de variables ; il ne serait pas superflu de vérifier qu'ils sont définis comme prévu et, par exemple, qu'ils n'ont pas été remplacés par une valeur vide.

BON: Vérifiez les variables.

- name: "Verify that required string variables are defined"
  assert:
    that: ahs_var is defined and ahs_var | length > 0 and ahs_var != None
    fail_msg: "{{ ahs_var }} needs to be set for the role to work "
    success_msg: "Required variables {{ ahs_var }} is defined"
  loop_control:
    loop_var: ahs_var
  with_items:
    - ahs_item1
    - ahs_item2
    - ahs_item3

Évitez les dictionnaires de hachage, utilisez une structure plate

Si un rôle attend un hachage/dictionnaire dans l'un de ses paramètres, alors si nous voulons modifier l'un des paramètres enfants, nous devrons remplacer l'intégralité du hachage/dictionnaire, ce qui augmentera la complexité de la configuration.

BAD: Utilisez le hachage/dictionnaire.

---
user:
  name: admin
  group: admin

BON: Utilisez une structure variable plate.

---
user_name: admin
user_group: "{{ user_name }}"

Créer des playbooks et des rôles idempotents

Les rôles et les playbooks doivent être idempotents, car réduit la dérive de configuration et la peur de casser quelque chose. Mais si vous utilisez une molécule, c'est le comportement par défaut.

Évitez d'utiliser des modules de shell de commande

L'utilisation d'un module shell aboutit à un paradigme de description impérative, au lieu du paradigme déclaratif, qui est le cœur d'Ansible.

Testez vos rôles via une molécule

La molécule est une chose très flexible, examinons quelques scénarios.

Molécule Plusieurs instances

В molecule.yml dans la section platforms vous pouvez décrire de nombreux hôtes que vous pouvez déployer.

---
    driver:
      name: docker
    platforms:
      - name: postgresql-instance
        hostname: postgresql-instance
        image: registry.example.com/postgres10:latest
        pre_build_image: true
        override_command: false
        network_mode: host
      - name: app-instance
        hostname: app-instance
        pre_build_image: true
        image: registry.example.com/docker_centos_ansible_tests
        network_mode: host

En conséquence, ces hôtes peuvent alors être converge.yml utiliser:

---
- name: Converge all
  hosts: all
  vars:
    ansible_user: root
  roles:
    - role: some_role

- name: Converge db
  hosts: db-instance
  roles:
    - role: some_db_role

- name: Converge app
  hosts: app-instance
  roles:
    - role: some_app_role

Vérificateur Ansible

Dans molécule, il est possible d'utiliser ansible pour vérifier que l'instance a été correctement configurée, d'ailleurs, c'est la valeur par défaut depuis la version 3. Ce n'est pas aussi flexible que testinfra/inspec, mais on peut vérifier que le contenu du fichier correspond à nos attentes :

---
- name: Verify
  hosts: all
  tasks:
    - name: copy config
      copy:
        src: expected_standalone.conf
        dest: /root/wildfly/bin/standalone.conf
        mode: "0644"
        owner: root
        group: root
      register: config_copy_result

    - name: Certify that standalone.conf changed
      assert:
        that: not config_copy_result.changed

Ou déployez le service, attendez qu'il soit disponible et effectuez un test de fumée :

---
  - name: Verify
    hosts: solr
    tasks:
      - command: /blah/solr/bin/solr start -s /solr_home -p 8983 -force
      - uri:
          url: http://127.0.0.1:8983/solr
          method: GET
          status_code: 200
        register: uri_result
        until: uri_result is not failed
        retries: 12
        delay: 10
      - name: Post documents to solr
        command: /blah/solr/bin/post -c master /exampledocs/books.csv

Mettez une logique complexe dans les modules et plugins

Ansible préconise une approche déclarative, donc lorsque vous effectuez un branchement de code, une transformation de données, des modules shell, le code devient difficile à lire. Pour lutter contre cela et rester simple à comprendre, il ne serait pas superflu de lutter contre cette complexité en créant vos propres modules.

Résumer les trucs et astuces

  1. Évitez les variables globales.
  2. Variables de rôle de préfixe.
  3. Utilisez la variable de contrôle de boucle.
  4. Vérifiez les variables d'entrée.
  5. Évitez les dictionnaires de hachage, utilisez une structure plate.
  6. Créez des playbooks et des rôles idempotents.
  7. Évitez d'utiliser des modules de shell de commande.
  8. Testez vos rôles via une molécule.
  9. Mettez une logique complexe dans les modules et plugins.

Conclusion

Comment commencer à tester Ansible, refactoriser le projet en un an et ne pas devenir fou

Vous ne pouvez pas simplement refactoriser l’infrastructure d’un projet, même si vous disposez d’IaC. C'est un long processus qui demande de la patience, du temps et des connaissances.

UPD1 2020.05.01 20:30 — Pour le profilage principal des playbooks, vous pouvez utiliser callback_whitelist = profile_tasks pour comprendre ce qui fonctionne exactement pendant longtemps. Ensuite, nous passons par Classiques de l'accélération Ansible. Vous pouvez également essayer mitogène
UPD2 2020.05.03 16:34 - Version anglaise

Source: habr.com

Ajouter un commentaire