Anleitung: Testen von Ansible-Rollen und Informieren ĂŒber Probleme vor der Produktion

Hallo allerseits!


Ich arbeite als DevOps-Ingenieur im Hotelreservierungsservice Ostrovok.ru . In diesem Artikel möchte ich ĂŒber unsere Erfahrungen beim Testen ansibler Rollen sprechen.


Bei Ostrovok.ru verwenden wir ansible als Konfigurationsmanager. Wir hatten kĂŒrzlich die Notwendigkeit, Rollen zu testen, aber wie sich herausstellte, gibt es dafĂŒr nicht viele Tools - das Molecule-Framework ist vielleicht das beliebteste, deshalb haben wir uns fĂŒr die Verwendung entschieden. Es stellte sich jedoch heraus, dass seine Dokumentation ĂŒber viele Fallstricke schweigte. Wir konnten keinen ausreichend detaillierten Leitfaden auf Russisch finden und haben uns daher entschlossen, diesen Artikel zu schreiben.



MolekĂŒl


MolekĂŒl - ein Framework zum Testen ansibler Rollen.


Vereinfachte Beschreibung: Das MolekĂŒl erstellt eine Instanz auf der von Ihnen angegebenen Plattform (Cloud, virtuelle Maschine, Container; weitere Einzelheiten finden Sie im Abschnitt Treiber ), fĂŒhrt Ihre Rolle darauf aus, fĂŒhrt dann die Tests aus und löscht die Instanz. Im Falle eines Fehlers bei einem der Schritte informiert Sie das MolekĂŒl darĂŒber.


Jetzt genauer.


Ein bisschen Theorie


Betrachten Sie die beiden SchlĂŒsselelemente des MolekĂŒls: Szenario und Treiber.


Szenario


Das Skript enthĂ€lt eine Beschreibung dessen, was, wo, wie und in welcher Reihenfolge ausgefĂŒhrt wird. Eine Rolle kann mehrere Skripte enthalten, und jedes ist ein Verzeichnis entlang des Pfads <role>/molecule/<scenario> , das Beschreibungen der fĂŒr den Test erforderlichen Aktionen enthĂ€lt. Das default muss vorhanden sein, das automatisch erstellt wird, wenn Sie die Rolle mit dem MolekĂŒl initialisieren. Die Namen der folgenden Szenarien werden nach Ihrem Ermessen ausgewĂ€hlt.


Die Testsequenz im Skript wird als Matrix bezeichnet und ist standardmĂ€ĂŸig wie folgt:


(Schritte markiert mit ? standardmĂ€ĂŸig ĂŒbersprungen, wenn sie nicht vom Benutzer beschrieben wurden.)


  • lint Linter. StandardmĂ€ĂŸig werden yamllint und flake8 .
  • destroy - Instanzen vom letzten MolekĂŒlstart entfernen (falls ĂŒbrig),
  • dependency ? - Installation der Ansible-AbhĂ€ngigkeit der getesteten Rolle,
  • syntax - ÜberprĂŒfen Sie die Syntax einer Rolle mit ansible-playbook --syntax-check ,
  • create - Instanz erstellen,
  • prepare ? - Vorbereitung der Instanz; B. Python2 ĂŒberprĂŒfen / installieren
  • converge - Start des getesteten Playbooks,
  • idempotence - Starten Sie das Playbook fĂŒr den Idempotenztest neu.
  • side_effect ? - Maßnahmen, die nicht direkt mit der Rolle zusammenhĂ€ngen, aber fĂŒr Tests erforderlich sind,
  • verify - FĂŒhren Sie Tests der resultierenden Konfiguration mit testinfra (Standard) / goss / inspec .
  • cleanup ? - (in neuen Versionen) - grob gesagt die „Reinigung“ der vom MolekĂŒl betroffenen externen Infrastruktur,
  • destroy - lösche eine Instanz.

Diese Sequenz deckt die meisten FÀlle ab, kann jedoch bei Bedarf geÀndert werden.


Jeder der obigen Schritte kann separat mit dem molecule <command> . Es lohnt sich jedoch zu verstehen, dass fĂŒr jeden solchen cli-Befehl eine eigene Abfolge von Aktionen existieren kann, die durch AusfĂŒhren der molecule matrix <command> erkannt werden kann. Wenn Sie beispielsweise den Befehl converge ausfĂŒhren (das getestete Playbook ausfĂŒhren), werden die folgenden Aktionen ausgefĂŒhrt:


 $ molecule matrix converge ... └── default #   ├── dependency #   ├── create #   ├── prepare #   └── converge #   

Die Reihenfolge dieser Aktionen kann bearbeitet werden. Wenn etwas aus der Liste bereits abgeschlossen ist, wird es ĂŒbersprungen. Der aktuelle Status sowie die $TMPDIR/molecule/<role>/<scenario> werden im $TMPDIR/molecule/<role>/<scenario> gespeichert.


Schritte hinzufĂŒgen mit ? Nachdem Sie die gewĂŒnschten Aktionen im Format von Ansible-Playbook beschrieben haben, können Sie den Dateinamen gemĂ€ĂŸ dem folgenden Schritt prepare.yml : prepare.yml / side_effect.yml . Das MolekĂŒl wartet im Skriptordner auf diese Dateien.


Fahrer


Ein Treiber ist eine EntitÀt, in der Testinstanzen erstellt werden.
Die Liste der Standardtreiber, fĂŒr die das MolekĂŒl Vorlagen bereit hĂ€lt, lautet wie folgt: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegiert.


In den meisten FÀllen handelt es sich bei den Vorlagen um die destroy.yml create.yml und destroy.yml im destroy.yml , die das Erstellen bzw. Löschen der Instanz beschreiben.
Ausnahmen sind Docker und Vagrant, da Interaktionen mit ihren Modulen ohne die oben genannten Dateien auftreten können.


Es lohnt sich, den delegierten Treiber hervorzuheben, da, wenn er in den Dateien zum Erstellen und Löschen einer Instanz verwendet wird, nur die Arbeit mit der Konfiguration von Instanzen beschrieben wird, der Rest vom Techniker beschrieben werden sollte.


Der Standardtreiber ist Docker.


Nun wenden wir uns der Praxis zu und betrachten dort weitere Funktionen.


Erste Schritte


Als "Hallo Welt" testen wir die einfache Rolle der Installation von Nginx. Wir wÀhlen Docker als Treiber - ich denke, es ist auf den meisten von Ihnen installiert (und denken Sie daran, dass Docker der Standardtreiber ist).


virtualenv Sie virtualenv und installieren Sie das molecule darin:


 > pip install virtualenv > virtualenv -p `which python2` venv > source venv/bin/activate > pip install molecule docker # molecule  ansible  ; docker   

Der nÀchste Schritt besteht darin, eine neue Rolle zu initialisieren.
Die Initialisierung einer neuen Rolle sowie eines neuen Szenarios erfolgt mit dem molecule init <params> :


 > molecule init role -r nginx --> Initializing new role nginx... Initialized role in <path>/nginx successfully. > cd nginx > tree -L 1 . ├── README.md ├── defaults ├── handlers ├── meta ├── molecule ├── tasks └── vars 6 directories, 1 file 

Das Ergebnis war eine typische ansible Rolle. Ferner werden alle Wechselwirkungen mit den CLI-MolekĂŒlen von der Wurzel der Rolle aus hergestellt.


Mal sehen, was sich im Rollenverzeichnis befindet:


 > tree molecule/default/ molecule/default/ ├── Dockerfile.j2 # Jinja-  Dockerfile ├── INSTALL.rst. #       ├── molecule.yml #   ├── playbook.yml #    └── tests #     verify └── test_default.py 1 directory, 6 files 

Lassen Sie uns die molecule/default/molecule.yml Konfiguration analysieren (wir ersetzen nur das Docker-Bild):


 --- dependency: name: galaxy driver: name: docker lint: name: yamllint platforms: - name: instance image: centos:7 provisioner: name: ansible lint: name: ansible-lint scenario: name: default verifier: name: testinfra lint: name: flake8 

AbhÀngigkeit


Dieser Abschnitt beschreibt die Quelle der AbhÀngigkeiten.


Mögliche Optionen: Galaxie , vergoldet , Muschel.


Shell ist nur eine Befehls-Shell, die verwendet wird, wenn Galaxie und Gold Ihre Anforderungen nicht erfĂŒllen.


Ich werde hier nicht lange aufhören, es ist in der Dokumentation ausreichend beschrieben.


Fahrer


Der Name des Fahrers. Wir haben diesen Docker.


Flusen


Als Linter wird Yamllint verwendet.


NĂŒtzliche Optionen in diesem Teil der Konfiguration sind die Möglichkeit, eine Konfigurationsdatei fĂŒr yamllint anzugeben, Umgebungsvariablen weiterzuleiten oder den Linter zu deaktivieren:


 lint: name: yamllint options: config-file: foo/bar env: FOO: bar enabled: False 

Plattformen


Beschreibt die Konfiguration von Instanzen.
Im Fall des Dockers als Treiber wird das MolekĂŒl ĂŒber diesen Abschnitt iteriert, und jedes Listenelement ist in Dockerfile.j2 als Dockerfile.j2 verfĂŒgbar.


Im Fall des Treibers, in dem create.yml und destroy.yml , ist der Abschnitt create.yml als destroy.yml verfĂŒgbar, und die Iterationen darauf sind bereits in diesen Dateien beschrieben.


Da das MolekĂŒl eine Instanzsteuerung fĂŒr ansible Module bietet, muss dort eine Liste möglicher Einstellungen gesucht werden. FĂŒr Docker wird beispielsweise das Modul docker_container_module verwendet . Welche Module in anderen Treibern verwendet werden, finden Sie in der Dokumentation .


Beispiele fĂŒr die Verwendung verschiedener Treiber finden sich in Tests des MolekĂŒls selbst .


Ersetzen Sie Centos: 7 auf Ubuntu hier .


Provisioner


"Provider" ist die EntitĂ€t, die die Instanzen steuert. Im Fall des MolekĂŒls ist dies ansible, UnterstĂŒtzung fĂŒr andere ist nicht geplant, so dass dieser Abschnitt mit Vorbehalt die erweiterte Konfiguration von ansible genannt werden kann.
Hier können Sie viele Dinge spezifizieren, ich werde die wichtigsten Momente meiner Meinung nach hervorheben:


  • Playbooks : Sie können festlegen, welche Playbooks in bestimmten Phasen verwendet werden sollen.

 provisioner: name: ansible playbooks: create: create.yml destroy: ../default/destroy.yml converge: playbook.yml side_effect: side_effect.yml cleanup: cleanup.yml 


 provisioner: name: ansible config_options: defaults: fact_caching: jsonfile ssh_connection: scp_if_ssh: True 

  • Verbindungsoptionen : Verbindungsparameter

 provisioner: name: ansible connection_options: ansible_ssh_common_args: "-o 'UserKnownHostsFile=/dev/null' -o 'ForwardAgent=yes'" 

  • Optionen : Ansible Optionen und Umgebungsvariablen

 provisioner: name: ansible options: vvv: true diff: true env: FOO: BAR 

Szenario


Der Name und die Beschreibung der Skriptsequenzen.
Sie können die Standardaktionsmatrix eines <command>_sequence Ă€ndern, indem Sie den <command>_sequence und die Liste der Schritte festlegen, die wir als Wert dafĂŒr benötigen.
Angenommen, wir möchten die Reihenfolge der Aktionen Ă€ndern, wenn wir den Befehl playbook run ausfĂŒhren: molecule converge


 # : # - dependency # - create # - prepare # - converge scenario: name: default converge_sequence: - create - converge 

PrĂŒfer


Einrichten des Frameworks fĂŒr Tests und des Linter dazu. StandardmĂ€ĂŸig werden testinfra und flake8 testinfra flake8 . Mögliche Optionen sind Ă€hnlich wie oben:


 verifier: name: testinfra additional_files_or_dirs: - ../path/to/test_1.py - ../path/to/test_2.py - ../path/to/directory/* options: n: 1 enabled: False env: FOO: bar lint: name: flake8 options: benchmark: True enabled: False env: FOO: bar 

Kommen wir zurĂŒck zu unserer Rolle. Bearbeiten Sie die tasks/main.yml :


 --- - name: Install nginx apt: name: nginx state: present - name: Start nginx service: name: nginx state: started 

Und fĂŒgen Sie die Tests zu molecule/default/tests/test_default.py


 def test_nginx_is_installed(host): nginx = host.package("nginx") assert nginx.is_installed def test_nginx_running_and_enabled(host): nginx = host.service("nginx") assert nginx.is_running assert nginx.is_enabled def test_nginx_config(host): host.run("nginx -t") 

Fertig, es bleibt nur zu laufen (von der Wurzel der Rolle, erinnere ich Sie):


 > molecule test 

Langer Auspuff unter dem Spoiler:
 --> Validating schema <path>/nginx/molecule/default/molecule.yml. Validation completed successfully. --> Test matrix └── default ├── lint ├── destroy ├── dependency ├── syntax ├── create ├── prepare ├── converge ├── idempotence ├── side_effect ├── verify └── destroy --> Scenario: 'default' --> Action: 'lint' --> Executing Yamllint on files found in <path>/nginx/... Lint completed successfully. --> Executing Flake8 on files found in <path>/nginx/molecule/default/tests/... Lint completed successfully. --> Executing Ansible Lint on <path>/nginx/molecule/default/playbook.yml... Lint completed successfully. --> Scenario: 'default' --> Action: 'destroy' PLAY [Destroy] ***************************************************************** TASK [Destroy molecule instance(s)] ******************************************** changed: [localhost] => (item=None) changed: [localhost] TASK [Wait for instance(s) deletion to complete] ******************************* ok: [localhost] => (item=None) ok: [localhost] TASK [Delete docker network(s)] ************************************************ PLAY RECAP ********************************************************************* localhost : ok=2 changed=1 unreachable=0 failed=0 --> Scenario: 'default' --> Action: 'dependency' Skipping, missing the requirements file. --> Scenario: 'default' --> Action: 'syntax' playbook: <path>/nginx/molecule/default/playbook.yml --> Scenario: 'default' --> Action: 'create' PLAY [Create] ****************************************************************** TASK [Log into a Docker registry] ********************************************** skipping: [localhost] => (item=None) TASK [Create Dockerfiles from image names] ************************************* changed: [localhost] => (item=None) changed: [localhost] TASK [Discover local Docker images] ******************************************** ok: [localhost] => (item=None) ok: [localhost] TASK [Build an Ansible compatible image] *************************************** changed: [localhost] => (item=None) changed: [localhost] TASK [Create docker network(s)] ************************************************ TASK [Create molecule instance(s)] ********************************************* changed: [localhost] => (item=None) changed: [localhost] TASK [Wait for instance(s) creation to complete] ******************************* changed: [localhost] => (item=None) changed: [localhost] PLAY RECAP ********************************************************************* localhost : ok=5 changed=4 unreachable=0 failed=0 --> Scenario: 'default' --> Action: 'prepare' Skipping, prepare playbook not configured. --> Scenario: 'default' --> Action: 'converge' PLAY [Converge] **************************************************************** TASK [Gathering Facts] ********************************************************* ok: [instance] TASK [nginx : Install nginx] *************************************************** changed: [instance] TASK [nginx : Start nginx] ***************************************************** changed: [instance] PLAY RECAP ********************************************************************* instance : ok=3 changed=2 unreachable=0 failed=0 --> Scenario: 'default' --> Action: 'idempotence' Idempotence completed successfully. --> Scenario: 'default' --> Action: 'side_effect' Skipping, side effect playbook not configured. --> Scenario: 'default' --> Action: 'verify' --> Executing Testinfra tests found in <path>/nginx/molecule/default/tests/... ============================= test session starts ============================== platform darwin -- Python 2.7.15, pytest-4.3.0, py-1.8.0, pluggy-0.9.0 rootdir: <path>/nginx/molecule/default, inifile: plugins: testinfra-1.16.0 collected 4 items tests/test_default.py .... [100%] ========================== 4 passed in 27.23 seconds =========================== Verifier completed successfully. --> Scenario: 'default' --> Action: 'destroy' PLAY [Destroy] ***************************************************************** TASK [Destroy molecule instance(s)] ******************************************** changed: [localhost] => (item=None) changed: [localhost] TASK [Wait for instance(s) deletion to complete] ******************************* changed: [localhost] => (item=None) changed: [localhost] TASK [Delete docker network(s)] ************************************************ PLAY RECAP ********************************************************************* localhost : ok=2 changed=2 unreachable=0 failed=0 

Unsere einfache Rolle wurde ohne Probleme getestet.
Es ist zu beachten, dass das molecule test die Instanz löscht, wenn wÀhrend des Betriebs des molecule test Probleme molecule test sind. Wenn Sie die Standardsequenz nicht geÀndert haben.


Die folgenden Befehle sind zum Debuggen hilfreich:


 > molecule --debug <command> # debug info.      . > molecule converge #      . > molecule login #    . > molecule --help #   . 

Bestehende Rolle


Das HinzufĂŒgen eines neuen Skripts zu einer vorhandenen Rolle erfolgt aus dem Rollenverzeichnis mit den folgenden Befehlen:


 #     > molecule init scenarion --help #    > molecule init scenario -r <role_name> -s <scenario_name> 

Falls dies das erste Skript in der Rolle ist, kann die -s weggelassen werden, da das default erstellt wird.


Fazit


Wie Sie sehen, ist das MolekĂŒl nicht sehr kompliziert. Wenn Sie Ihre eigenen Vorlagen verwenden, können Sie die Bereitstellung eines neuen Skripts auf das Bearbeiten von Variablen in Playbooks zum Erstellen und Löschen von Instanzen reduzieren. Das MolekĂŒl lĂ€sst sich nahtlos in CI-Systeme integrieren, wodurch Sie die Entwicklungsgeschwindigkeit erhöhen können, indem Sie weniger Zeit fĂŒr das manuelle Testen von Playbooks benötigen.


Vielen Dank fĂŒr Ihre Aufmerksamkeit. Wenn Sie Erfahrung mit dem Testen ansibler Rollen haben und diese nicht mit dem MolekĂŒl zusammenhĂ€ngen, teilen Sie uns dies in den Kommentaren mit!

Source: https://habr.com/ru/post/de448136/


All Articles