Navodila: kako preizkusiti antabilne vloge in ugotoviti težave pred produkcijo

Pozdravljeni vsi!

Delam kot inženir DevOps v storitvi hotelskih rezervacij. Ostrovok.ru. V tem članku želim govoriti o naših izkušnjah pri testiranju antabilnih vlog.

Na Ostrovok.ru uporabljamo ansible kot upravljalnik konfiguracije. Pred kratkim smo prišli do potrebe po testiranju vlog, a kot se je izkazalo, za to ni toliko orodij - morda najbolj priljubljeno je ogrodje Molecule, zato smo se odločili, da ga uporabimo. A izkazalo se je, da njegova dokumentacija o številnih pasteh molči. Nismo mogli najti dovolj podrobnega priročnika v ruščini, zato smo se odločili napisati ta članek.

Navodila: kako preizkusiti antabilne vloge in ugotoviti težave pred produkcijo

Molekula

Molekula - okvir za pomoč pri testiranju možnih vlog.

Poenostavljen opis: Molekula ustvari primerek na platformi, ki jo določite (oblak, virtualni stroj, vsebnik; za več podrobnosti glejte razdelek Voznik), zažene vašo vlogo na njem, nato zažene preizkuse in izbriše primerek. V primeru napake na enem od korakov vas bo Molecule o tem obvestila.

Zdaj več.

Malo teorije

Razmislite o dveh ključnih entitetah molekule: scenariju in gonilniku.

Scenarij

Skripta vsebuje opis, kaj, kje, kako in v kakšnem zaporedju se bo izvajalo. Ena vloga ima lahko več skriptov in vsak je imenik na poti <role>/molecule/<scenario>, ki vsebuje opise dejanj, potrebnih za preizkus. Skript mora biti vključen default, ki bo samodejno ustvarjen, če inicializirate vlogo z Molecule. Imena naslednjih skriptov določite sami.

Pokliče se zaporedje dejanj testiranja v skriptu matrica, in privzeto je:

(Koraki označeni ?, privzeto preskočeno, če tega ne določi uporabnik)

  • lint - tekoči linterji. Privzeto se uporabljajo yamllint и flake8,
  • destroy - brisanje primerkov iz zadnjega zagona Molecule (če obstajajo),
  • dependency? — namestitev antabilne odvisnosti testirane vloge,
  • syntax - preverjanje sintakse uporabe vloge ansible-playbook --syntax-check,
  • create - ustvarjanje primerka,
  • prepare? — priprava primerka; na primer preveri/namesti python2
  • converge — lansiranje preizkušenega priročnika,
  • idempotence - ponovni zagon priročnika za test idempotence,
  • side_effect? - dejanja, ki niso neposredno povezana z vlogo, vendar so potrebna za preizkuse,
  • verify - izvajanje testov dobljene konfiguracije z uporabo testinfra(privzeto) /goss/inspec,
  • cleanup? - (v novih različicah) - grobo rečeno, "čiščenje" zunanje infrastrukture, na katero vpliva Molecule,
  • destroy - Brisanje primerka.

To zaporedje pokriva večino primerov, vendar ga je mogoče po potrebi spremeniti.

Vsakega od zgornjih korakov lahko izvajate ločeno z molecule <command>. Vendar je treba razumeti, da lahko za vsak tak cli-ukaz obstaja lastno zaporedje dejanj, ki jih lahko ugotovite z izvedbo molecule matrix <command>. Na primer, ko izvajate ukaz converge (zagon preizkusnega priročnika), bodo izvedena naslednja dejanja:

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

Zaporedje teh dejanj je mogoče urejati. Če je nekaj s seznama že narejeno, bo preskočeno. Trenutno stanje in konfiguracijo primerkov Molecule shrani v imenik $TMPDIR/molecule/<role>/<scenario>.

Dodajte korake z ? lahko opišete želena dejanja v formatu ansible-playbook in ustvarite ime datoteke v skladu s korakom: prepare.yml/side_effect.yml. Pričakujte te datoteke. Molekula bo v mapi s skripti.

Voznik

Gonilnik je entiteta, kjer se ustvarijo testni primerki.
Seznam standardnih gonilnikov, za katere ima Molecule pripravljene predloge, je naslednji: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

V večini primerov so predloge datoteke create.yml и destroy.yml v mapi s skripti, ki opisujejo ustvarjanje oziroma brisanje primerka.
Izjemi sta Docker in Vagrant, saj lahko interakcije z njunima moduloma potekajo brez prej omenjenih datotek.

Velja izpostaviti Delegirani gonilnik, saj če se uporablja v datotekah za ustvarjanje in brisanje instance, je opisano samo delo s konfiguracijo instanc, ostalo naj opiše inženir.

Privzeti gonilnik je Docker.

Zdaj pa preidimo na prakso in razmislimo o dodatnih funkcijah.

Začetek

Kot »zdravo, svet« preizkusimo preprosto namestitveno vlogo nginx. Za gonilnik bomo izbrali docker - mislim, da ga ima večina od vas nameščenega (in ne pozabite, da je docker privzeti gonilnik).

Pripravimo se virtualenv in vanj namestite molecule:

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

Naslednji korak je inicializacija nove vloge.
Inicializacija nove vloge in novega skripta se izvede z ukazom 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

Izkazalo se je tipično ansible vlogo. Poleg tega so vse interakcije z molekulami CLI narejene iz korenine vloge.

Poglejmo, kaj je v imeniku vlog:

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

1 directory, 6 files

Analizirajmo konfiguracijo molecule/default/molecule.yml (zamenjaj samo sliko dockerja):

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

odvisnost

Ta razdelek opisuje vir odvisnosti.

Možne možnosti: Galaksija, pozlata, školjka.

Shell je samo ukazna lupina, ki se uporablja v primeru, da galaxy in gilt ne pokrivata vaših potreb.

Tu se ne bom dolgo zadrževal, dovolj je opisano v dokumentacijo.

voznik

Ime voznika. Naš je docker.

vlakna

Linter je yamllint.

Uporabne možnosti v tem delu konfiguracije so možnost podajanja konfiguracijske datoteke za yamllint, posredovanje spremenljivk okolja ali onemogočanje linterja:

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

platforme

Opisuje konfiguracijo primerkov.
V primeru dockerja kot gonilnika se Molecule ponavlja čez ta razdelek in vsak element seznama je na voljo v Dockerfile.j2 kot spremenljivka item.

V primeru voznika, ki zahteva create.yml и destroy.yml, rubrika je v njih dostopna kot molecule_yml.platforms, in ponovitve nad njim so že opisane v teh datotekah.

Ker Molecule omogoča nadzor instanc modulom ansible, je treba seznam možnih nastavitev iskati tudi tam. Za docker se na primer uporablja modul docker_container_module. Katere module uporabljajo drugi gonilniki, lahko najdete v dokumentacijo.

Najdete lahko tudi primere uporabe različnih gonilnikov pri testih same Molekule.

Zamenjajte tukaj centov:7 o ubuntu.

ponudnik

"Dobavitelj" - subjekt, ki upravlja primerke. V primeru Molecule je to ansible, podpora za druge ni predvidena, zato lahko ta razdelek imenujemo ansible razširjena konfiguracija z opozorilom.
Tu lahko navedete veliko stvari, po mojem mnenju bom izpostavil glavne točke:

  • igroknjige: določite lahko, katere knjige naj se uporabljajo na določenih stopnjah.

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

  • Možnosti: Ansible možnosti in spremenljivke okolja

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

Scenarij

Ime in opis zaporedij skriptov.
Privzeto matriko dejanj katerega koli ukaza lahko spremenite tako, da dodate ključ <command>_sequence in kot vrednost zanj z definiranjem seznama korakov, ki jih potrebujemo.
Recimo, da želimo spremeniti zaporedje dejanj pri izvajanju ukaza playbook run: molecule converge

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

Preveritelj

Postavitev ogrodja za teste in linterja zanj. Privzeti linter je testinfra и flake8. Možne možnosti so enake kot zgoraj:

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

Vrnimo se k naši vlogi. Uredimo datoteko tasks/main.yml na to vrsto:

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

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

In dodajte teste 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")

Končano, ostane le še zagon (iz korena vloge, naj vas spomnim):

> molecule test

Dolg izpuh pod spojlerjem:

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

Našo preprosto vlogo smo preizkusili brez težav.
Vredno je zapomniti, da če med delom pride do težav molecule test, če niste spremenili privzetega zaporedja, bo Molecule izbrisala primerek.

Naslednji ukazi so uporabni za odpravljanje napak:

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

Obstoječa vloga

Dodajanje novega skripta obstoječi vlogi je iz imenika vlog z naslednjimi ukazi:

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

V primeru, da je to prvi scenarij v vlogi, potem parameter -s lahko izpustite, saj bo ustvaril skript default.

Zaključek

Kot lahko vidite, Molecule ni zelo zapleten in z uporabo lastnih predlog se lahko uvajanje novega skripta zmanjša na urejanje spremenljivk v priročnikih za ustvarjanje in brisanje primerkov. Molekula se brezhibno integrira s sistemi CI, kar vam omogoča, da povečate hitrost razvoja z zmanjšanjem časa za ročno testiranje knjig iger.

Hvala za vašo pozornost. Če imate izkušnje s testiranjem ansibilnih vlog in niso povezane z Molecule, nam o tem povejte v komentarjih!

Vir: www.habr.com

Dodaj komentar