Udhëzime: si të testoni rolet e duhura dhe të mësoni për problemet përpara prodhimit

Përshëndetje të gjithëve!

Unë punoj si inxhinier DevOps në një shërbim rezervimi hotelesh. Ostrovok.ru. Në këtë artikull, unë dua të flas për përvojën tonë në testimin e roleve të besueshme.

Në Ostrovok.ru, ne përdorim ansible si një menaxher konfigurimi. Kohët e fundit, ne erdhëm në nevojën për të testuar rolet, por siç doli, nuk ka aq shumë mjete për këtë - më e popullarizuara, ndoshta, është korniza e Molekulës, kështu që vendosëm ta përdorim atë. Por doli që dokumentacioni i tij hesht për shumë gracka. Ne nuk mund të gjenim një manual mjaft të detajuar në Rusisht, kështu që vendosëm të shkruanim këtë artikull.

Udhëzime: si të testoni rolet e duhura dhe të mësoni për problemet përpara prodhimit

molekulë

Molekula - një kornizë për të ndihmuar në testimin e roleve të besueshme.

Përshkrimi i thjeshtuar: Molekula krijon një shembull në platformën që specifikoni (cloud, makinë virtuale, kontejner; për më shumë detaje, shihni seksionin Shofer), ekzekuton rolin tuaj në të, më pas ekzekuton testet dhe fshin shembullin. Në rast të dështimit në një nga hapat, molekula do t'ju informojë për këtë.

Tani më në detaje.

Pak teori

Konsideroni dy entitete kryesore të molekulës: Skenari dhe Drejtuesi.

skenar

Skenari përmban një përshkrim se çfarë, ku, si dhe në çfarë sekuence do të kryhet. Një rol mund të ketë disa skripta, dhe secili është një drejtori përgjatë rrugës <role>/molecule/<scenario>, i cili përmban përshkrime të veprimeve të kërkuara për testin. Skripti duhet të përfshihet default, i cili do të krijohet automatikisht nëse inicializon rolin me një molekulë. Emrat e skripteve të mëposhtme janë në dorën tuaj.

Sekuenca e veprimeve të testimit në një skenar quhet matricë, dhe si parazgjedhje është:

(Hapat e etiketuar ?, anashkaluar si parazgjedhje nëse nuk specifikohet nga përdoruesi)

  • lint - linja drejtimi. Si parazgjedhje përdoren yamllint и flake8,
  • destroy - fshirja e rasteve nga lëshimi i fundit i molekulës (nëse ka),
  • dependency? — instalimi i varësisë së dukshme të rolit të testuar,
  • syntax - kontrollimi i sintaksës së rolit duke përdorur ansible-playbook --syntax-check,
  • create - krijimi i një shembulli,
  • prepare? — përgatitja e shembullit; p.sh. kontrolloni/instaloni python2
  • converge — nisja e librit të lojërave që po testohet,
  • idempotence - rifillimi i librit të lojërave për testin e idempotencës,
  • side_effect? - veprime që nuk lidhen drejtpërdrejt me rolin, por të nevojshme për teste,
  • verify - ekzekutimi i testeve të konfigurimit që rezulton duke përdorur testinfra(e parazgjedhur) /goss/inspec,
  • cleanup? - (në versionet e reja) - përafërsisht "pastrimi" i infrastrukturës së jashtme të prekur nga molekula,
  • destroy - Fshirja e një shembulli.

Kjo sekuencë mbulon shumicën e rasteve, por mund të ndryshohet nëse është e nevojshme.

Secili nga hapat e mësipërm mund të ekzekutohet veçmas me molecule <command>. Por duhet kuptuar që për secilën komandë të tillë kliko mund të ketë sekuencën e vet të veprimeve, të cilat mund t'i zbuloni duke ekzekutuar molecule matrix <command>. Për shembull, kur ekzekutoni komandën converge (duke ekzekutuar librin e lojërave në provë), do të kryhen veprimet e mëposhtme:

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

Sekuenca e këtyre veprimeve mund të modifikohet. Nëse diçka nga lista është bërë tashmë, ajo do të anashkalohet. Gjendja aktuale, si dhe konfigurimi i instancave, Molekula ruan në drejtori $TMPDIR/molecule/<role>/<scenario>.

Shto hapat me ? mund të përshkruani veprimet e dëshiruara në formatin ansible-playbook dhe të bëni emrin e skedarit sipas hapit: prepare.yml/side_effect.yml. Prisni këto skedarë Molekula do të jetë në dosjen e skriptit.

Shofer

Një drejtues është një ent ku krijohen instancat e testimit.
Lista e drejtuesve standardë për të cilët Molecule ka gati shabllonet është si më poshtë: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

Në shumicën e rasteve, shabllonet janë skedarë create.yml и destroy.yml në dosjen e skriptit që përshkruajnë krijimin dhe fshirjen e një shembulli, përkatësisht.
Përjashtimet janë Docker dhe Vagrant, pasi ndërveprimet me modulet e tyre mund të ndodhin pa skedarët e lartpërmendur.

Vlen të theksohet drejtuesi i deleguar, pasi nëse përdoret në skedarë për krijimin dhe fshirjen e një shembulli, përshkruhet vetëm puna me konfigurimin e instancave, pjesa tjetër duhet të përshkruhet nga inxhinieri.

Drejtuesi i parazgjedhur është Docker.

Tani le të kalojmë në praktikë dhe të shqyrtojmë veçori të tjera atje.

Si T'ia Fillohet

Si një "botë përshëndetje", le të testojmë një rol të thjeshtë instalimi nginx. Le të zgjedhim docker si drejtues - mendoj se shumica prej jush e kanë të instaluar (dhe mbani mend se docker është drejtuesi i parazgjedhur).

përgatit virtualenv dhe instaloni në të molecule:

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

Hapi tjetër është inicializimi i rolit të ri.
Inicializimi i një roli të ri, si dhe i një skripti të ri, kryhet duke përdorur komandën 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

Doli një rol tipik ansible. Më tej, të gjitha ndërveprimet me molekulat CLI bëhen nga rrënja e rolit.

Le të shohim se çfarë është në drejtorinë e roleve:

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

1 directory, 6 files

Le të analizojmë konfigurimin molecule/default/molecule.yml (zëvendësoni vetëm imazhin e dokerit):

---
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

varësi

Ky seksion përshkruan burimin e varësive.

Opsione të mundshme: Kashta e Kumtrit, i praruar, guaskë.

Shell është vetëm një guaskë komandimi që përdoret në rast se galaktika dhe arrat nuk mbulojnë nevojat tuaja.

Unë nuk do të qëndroj këtu për një kohë të gjatë, është mjaft e përshkruar në dokumentacionin.

shofer

Emri i shoferit. E jona është doker.

garzë

Linteri është yamllint.

Opsionet e dobishme në këtë pjesë të konfigurimit janë aftësia për të specifikuar një skedar konfigurimi për yamllint, variablat e mjedisit përpara ose për të çaktivizuar linterin:

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

Platformat

Përshkruan konfigurimin e instancave.
Në rastin e docker-it si drejtues, molekula përsëritet mbi këtë seksion dhe çdo element i listës është i disponueshëm në Dockerfile.j2 si një variabël item.

Në rastin e një shoferi që kërkon create.yml и destroy.yml, seksioni është i disponueshëm në to si molecule_yml.platforms, dhe përsëritjet mbi të janë përshkruar tashmë në këto skedarë.

Meqenëse Molekula siguron kontrollin e instancave në modulet ansible, lista e cilësimeve të mundshme duhet gjithashtu të kërkohet atje. Për docker, për shembull, përdoret moduli docker_container_module. Në cilat module përdoren në drejtuesit e tjerë mund të gjenden dokumentacionin.

Si dhe shembuj të përdorimit të drejtuesve të ndryshëm mund të gjenden në testet e vetë molekulës.

Zëvendëso këtu cent: 7 mbi ubuntu.

ofrues

"Furnizuesi" - një ent që menaxhon instancat. Në rastin e Molekulës, kjo është e mundur, mbështetja për të tjerët nuk është planifikuar, kështu që ky seksion mund të quhet konfigurim i zgjatur i pasigurt me një paralajmërim.
Këtu mund të specifikoni shumë gjëra, unë do të theksoj pikat kryesore, sipas mendimit tim:

  • libra lojërash: mund të specifikoni se cilët libra lojërash duhet të përdoren në faza të caktuara.

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

  • opsionet_lidhja: opsione lidhje

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

  • opsione: Opsionet ansible dhe variablat e mjedisit

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

skenar

Emri dhe përshkrimi i sekuencave të skenarit.
Ju mund të ndryshoni matricën e paracaktuar të veprimit të çdo komande duke shtuar çelësin <command>_sequence dhe si vlerë për të duke përcaktuar listën e hapave që na duhen.
Le të themi se duam të ndryshojmë sekuencën e veprimeve kur ekzekutojmë komandën e ekzekutimit të playbook: molecule converge

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

verifikuesi

Vendosja e një kornize për teste dhe një linter për të. Linter i parazgjedhur është testinfra и flake8. Opsionet e mundshme janë të njëjta si më sipër:

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

Le të kthehemi te roli ynë. Le të modifikojmë skedarin tasks/main.yml për këtë lloj:

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

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

Dhe shtoni teste në 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")

Mbaroi, mbetet vetëm për të vrapuar (nga rrënja e rolit, më lejoni t'ju kujtoj):

> molecule test

Shter i gjatë nën 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

Roli ynë i thjeshtë u testua pa probleme.
Vlen të kujtohet se nëse ka probleme gjatë punës molecule test, atëherë nëse nuk e keni ndryshuar sekuencën e paracaktuar, Molekula do ta fshijë shembullin.

Komandat e mëposhtme janë të dobishme për korrigjimin e gabimeve:

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

Roli ekzistues

Shtimi i një skenari të ri në një rol ekzistues është nga drejtoria e roleve me komandat e mëposhtme:

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

Në rast se ky është skenari i parë në rol, atëherë parametri -s mund të hiqet pasi do të krijojë një skript default.

Përfundim

Siç mund ta shihni, Molekula nuk është shumë komplekse dhe duke përdorur shabllonet tuaja, vendosja e një skripti të ri mund të reduktohet në modifikimin e variablave në librat e krijimit dhe fshirjes së shembullit. Molekula integrohet pa probleme me sistemet CI, gjë që ju lejon të rritni shpejtësinë e zhvillimit duke reduktuar kohën për testimin manual të librave të lojës.

Faleminderit per vemendjen. Nëse keni përvojë në testimin e roleve të besueshme dhe nuk ka lidhje me molekulën, na tregoni për këtë në komente!

Burimi: www.habr.com

Shto një koment