Instruktioune: wéi een ansible Rollen testen an iwwer Problemer virun der Produktioun erausfannen

Hallo jiddereen!

Ech schaffen als DevOps Ingenieur an engem Hotelbuchungsservice. Ostrovok.ru. An dësem Artikel wëll ech iwwer eis Erfahrung am Test vun ansible Rollen schwätzen.

Bei Ostrovok.ru benotze mir ansible als Konfiguratiounsmanager. Viru kuerzem si mir op d'Noutwennegkeet komm fir Rollen ze testen, awer wéi et sech erausstellt, ginn et net sou vill Tools fir dëst - déi populärste ass vläicht de Molecule Kader, also hu mir beschloss et ze benotzen. Awer et huet sech erausgestallt datt seng Dokumentatioun iwwer vill Falen schwëmmt. Mir konnten net genuch detailléiert Handbuch op Russesch fannen, also hu mir décidéiert dësen Artikel ze schreiwen.

Instruktioune: wéi een ansible Rollen testen an iwwer Problemer virun der Produktioun erausfannen

Molekül

Eng Molekül - e Kader fir ze hëllefen ansible Rollen ze testen.

Vereinfacht Beschreiwung: De Molekül erstellt eng Instanz op der Plattform déi Dir spezifizéiert (Cloud, virtuell Maschinn, Container; fir méi Detailer, kuckt d'Sektioun driver), leeft Är Roll drop, leeft dann Tester a läscht d'Instanz. Am Fall vun engem Echec op ee vun de Schrëtt, wäert d'Molekül Iech doriwwer informéieren.

Elo méi.

E bësse vun der Theorie

Betruecht zwee Schlësselentitéite vun der Molekül: Szenario a Chauffeur.

Szenario

De Skript enthält eng Beschreiwung vu wat, wou, wéi a wéi eng Sequenz wäert gemaach ginn. Eng Roll kann e puer Skripte hunn, an all ass e Verzeechnes laanscht de Wee <role>/molecule/<scenario>, déi Beschreiwunge vun den Aktiounen, déi fir den Test erfuerderlech sinn, enthält. Skript muss abegraff sinn default, déi automatesch erstallt gëtt wann Dir d'Roll mat engem Molekül initialiséiert. D'Nimm vun de folgende Skripte sinn un Iech.

D'Sequenz vun Testaktiounen an engem Skript gëtt genannt Matrix, an par défaut ass et:

(Schrëtt markéiert ?, par défaut iwwersprangen wann net vum Benotzer uginn)

  • lint - lafen linters. Par défaut gi benotzt yamllint и flake8,
  • destroy - Instanzen aus dem leschte Start vun der Molekül läschen (wann iwwerhaapt),
  • dependency? - Installatioun vun der méiglecher Ofhängegkeet vun der gepréifter Roll,
  • syntax - Iwwerpréift d'Syntax vun der Roll benotzt ansible-playbook --syntax-check,
  • create - eng Instanz erstellen,
  • prepare? - Virbereedung vun der Instanz; zB kontrolléieren / installéieren python2
  • converge - Start vum Spillbuch dat getest gëtt,
  • idempotence - d'Spillbuch nei starten fir den Idempotenztest,
  • side_effect? - Aktiounen déi net direkt mat der Roll verbonne sinn, awer néideg fir Tester,
  • verify - Lafen Tester vun der resultéierender Konfiguratioun benotzt testinfra(Standard) /goss/inspec,
  • cleanup? - (an neie Versiounen) - ongeféier geschwat, "Botzen" vun der externer Infrastruktur, déi vun der Molekül betraff ass,
  • destroy - Läschen eng Instanz.

Dës Sequenz deckt déi meescht Fäll, awer kann geännert ginn wann néideg.

Jiddereng vun den uewe Schrëtt kann separat mat lafen ginn molecule <command>. Awer et sollt verstane ginn datt fir all sou Cli-Kommando seng eege Sequenz vun Aktiounen kann sinn, déi Dir erausfannen andeems Dir ausféiert molecule matrix <command>. Zum Beispill, wann Dir de Kommando leeft converge (laaft d'Spillbuch ënner Test), ginn déi folgend Aktiounen ausgefouert:

$ molecule matrix converge
...
└── default         # название сценария
    ├── dependency  # установка зависимостей
    ├── create      # создание инстанса
    ├── prepare     # преднастройка инстанса
    └── converge    # прогон плейбука

D'Sequenz vun dësen Aktiounen kann geännert ginn. Wann eppes aus der Lëscht scho gemaach ass, gëtt et iwwersprangen. Den aktuellen Zoustand, souwéi d'Konfiguratioun vun den Instanzen, späichert d'Molekül am Verzeechnes $TMPDIR/molecule/<role>/<scenario>.

Dobäizemaachen Schrëtt mat ? Dir kënnt déi gewënscht Handlungen am Ansible-Playbook-Format beschreiwen, a maacht den Dateinumm no dem Schrëtt: prepare.yml/side_effect.yml. Erwaart dës Dateien D'Molekül wäert am Skript Dossier sinn.

driver

E Chauffer ass eng Entitéit wou Testinstanzen erstallt ginn.
D'Lëscht vun Standard Chauffeuren fir déi Molekül Template prett huet ass wéi follegt: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegéiert.

An deene meeschte Fäll sinn Template Dateien create.yml и destroy.yml am Skript Dossier deen d'Schafung an d'Läschen vun enger Instanz beschreiwen, respektiv.
D'Ausnahmen sinn Docker a Vagrant, well Interaktioune mat hire Moduler kënnen optrieden ouni déi genannte Dateien.

Et ass derwäert den Delegéierte Chauffer ze markéieren, well wann et an de Dateien benotzt gëtt fir eng Instanz ze kreéieren an ze läschen, gëtt nëmmen d'Aarbecht mat der Konfiguratioun vun Instanzen beschriwwen, de Rescht soll vum Ingenieur beschriwwe ginn.

De Standard Chauffer ass Docker.

Loosst eis elo weider üben a weider Features do betruechten.

Schrëtt;

Als "Hallo Welt", loosst eis eng einfach nginx Installatiounsroll testen. Mir wäerten Docker als Chauffer wielen - ech mengen datt déi meescht vun iech et installéiert hunn (an erënnere mech datt den Docker de Standard Chauffer ass).

Preparéieren virtualenv an installéiert an et molecule:

> pip install virtualenv
> virtualenv -p `which python2` venv
> source venv/bin/activate
> pip install molecule docker  # molecule установит ansible как зависимость; docker для драйвера

De nächste Schrëtt ass déi nei Roll ze initialiséieren.
Initialiséierung vun enger neier Roll, souwéi engem neie Skript, gëtt mam Kommando gemaach 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

Et huet sech eng typesch ansible-Roll erausgestallt. Weider sinn all Interaktioune mat CLI Moleküle aus der Wuerzel vun der Roll gemaach.

Loosst eis kucken wat am Rollverzeichnis ass:

> tree molecule/default/
molecule/default/
├── Dockerfile.j2  # Jinja-шаблон для Dockerfile
├── INSTALL.rst.   # Немного информации об установке зависимостей сценария
├── molecule.yml   # Файл конфигурации
├── playbook.yml   # Плейбук запуска роли
└── tests          # Директория с тестами стадии verify
    └── test_default.py

1 directory, 6 files

Loosst eis d'Konfiguratioun analyséieren molecule/default/molecule.yml (ersetzen nëmmen 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

Ofhängegkeet

Dës Sektioun beschreift d'Quell vun Ofhängegkeeten.

Méiglech Optiounen: Galaxis, vergëlltener, Schuel.

Shell ass just eng Kommandoshell déi benotzt gëtt am Fall wou Galaxis a Gilt Är Bedierfnesser net ofdecken.

Ech wäert net laang hei wunnen, et ass genuch beschriwwen an Dokumentatioun.

Chauffeur

Den Numm vum Chauffer. Eis ass Docker.

Lint

D'Linter ass Yamlint.

Nëtzlech Optiounen an dësem Deel vun der Configuratioun sinn d'Fäegkeet fir eng Konfiguratiounsdatei fir Yamllint ze spezifizéieren, Forward Ëmfeldvariablen oder d'Linter auszeschalten:

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

Plattformen

Beschreift d'Konfiguratioun vun den Instanzen.
Am Fall vum Docker als Chauffeur gëtt d'Molekül iwwer dës Sektioun iteréiert, an all Element vun der Lëscht ass verfügbar an Dockerfile.j2 als Variabel item.

Am Fall vun engem Chauffer déi verlaangt create.yml и destroy.yml, der Rubrik ass sinn an hinnen als molecule_yml.platforms, an Iteratiounen doriwwer si schonn an dëse Fichieren beschriwwen.

Zënter datt d'Molekül d'Kontroll vun Instanzen un ansible Moduler ubitt, sollt d'Lëscht vu méiglechen Astellungen och do gesicht ginn. Fir Docker, zum Beispill, gëtt de Modul benotzt docker_container_modul. Wéi eng Moduler an anere Chauffeuren benotzt ginn, fannt Dir an Dokumentatioun.

Wéi och Beispiller fir d'Benotzung vu verschiddene Chauffeuren kënne fonnt ginn an den Tester vun der Molekül selwer.

Ersetzen hei cent:7 op Ubuntu.

provisor

"Liwwerant" - eng Entitéit déi Instanzen geréiert. Am Fall vu Molekül ass dëst méiglech, Ënnerstëtzung fir anerer ass net geplangt, sou datt dës Sektioun als eng verlängert Konfiguratioun mat engem Opgepasst bezeechent ka ginn.
Hei kënnt Dir vill Saache spezifizéieren, ech wäert d'Haaptpunkte ervirhiewen, menger Meenung no:

  • Spillbicher: Dir kënnt uginn, wéi eng Spillbicher a bestëmmte Stadien benotzt ginn.

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

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

  • Optiounen: Ansible Optiounen an Ëmwelt Verännerlechen

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

Szenario

Numm an Beschreiwung vun Skript Sequenzen.
Dir kënnt d'Standardaktiounsmatrix vun all Kommando änneren andeems Dir de Schlëssel bäidréit <command>_sequence an als Wäert fir et duerch d'Lëscht vun Schrëtt definéieren mir brauchen.
Loosst eis soen, mir wëllen d'Sequenz vun den Aktiounen änneren wann Dir de Playbook Run Kommando ausféiert: molecule converge

# изначально:
# - dependency
# - create
# - prepare
# - converge
scenario:
  name: default
  converge_sequence:
    - create
    - converge

kontrolléieren

Opstelle vun engem Kader fir Tester an engem linter derfir. De Default Linter ass testinfra и flake8. Déi méiglech Optiounen sinn déiselwecht wéi hei uewen:

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

Komme mer zréck op eis Roll. Loosst eis d'Datei änneren tasks/main.yml zu dëser Aart:

---
- name: Install nginx
  apt:
    name: nginx
    state: present

- name: Start nginx
  service:
    name: nginx
    state: started

A fügen Tester un 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")

Gemaach, et bleift just ze lafen (vum Wuerzel vun der Roll, loosst mech Iech drun erënneren):

> molecule test

Laang Auspuff ënner 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

Eis einfach Roll gouf ouni Problemer getest.
Et ass derwäert ze erënneren datt wann et Problemer während der Aarbecht sinn molecule test, dann wann Dir d'Standardsequenz net geännert hutt, läscht d'Molekül d'Instanz.

Déi folgend Kommandoen sinn nëtzlech fir Debugging:

> molecule --debug <command> # debug info. При обычном запуске Молекула скрывает логи.
> molecule converge          # Оставляет инстанс после прогона тестируемой роли.
> molecule login             # Зайти в созданный инстанс.
> molecule --help            # Полный список команд.

Bestehend Roll

En neie Skript op eng existent Roll ze addéieren ass aus dem Rollverzeichnis mat de folgende Kommandoen:

# полный список доступных параметров
> molecule init scenarion --help
# создание нового сценария
> molecule init scenario -r <role_name> -s <scenario_name>

Am Fall ass dëst den éischte Szenario an der Roll, dann de Parameter -s kann ewech gelooss ginn well et e Skript erstellt default.

Konklusioun

Wéi Dir gesitt, ass d'Molekül net ganz komplex, an andeems Dir Är eege Template benotzt, kann en neit Skript ofbauen reduzéiert ginn fir Variabelen z'änneren an der Instanz Kreatioun a Läschen Playbooks. D'Molekül integréiert nahtlos mat CI Systemer, wat Iech erlaabt d'Geschwindegkeet vun der Entwécklung ze erhéijen andeems d'Zäit fir manuell Tester vu Playbooks reduzéiert gëtt.

Merci fir är Opmierksamkeet. Wann Dir Erfahrung am Test vun ansible Rollen hutt, an et ass net mat der Molekül Zesummenhang, sot eis doriwwer an de Kommentaren!

Source: will.com

Setzt e Commentaire