Instructies: hoe u weerwortrollen kunt testen en problemen kunt ontdekken vóór de productie

Hallo iedereen!

Ik werk als DevOps-ingenieur bij een hotelboekingsservice. Ostrovok.ru. In dit artikel wil ik het hebben over onze ervaringen met het testen van weerwortrollen.

Bij Ostrovok.ru gebruiken we ansible als configuratiemanager. Onlangs kwamen we tot de noodzaak om rollen te testen, maar het bleek dat er niet zo veel tools hiervoor zijn - het meest populaire is misschien het Molecule-framework, dus besloten we het te gebruiken. Maar het bleek dat zijn documentatie over veel valkuilen zwijgt. We konden geen voldoende gedetailleerde handleiding in het Russisch vinden, dus besloten we dit artikel te schrijven.

Instructies: hoe u weerwortrollen kunt testen en problemen kunt ontdekken vóór de productie

molecule

Molecuul - een raamwerk om weerweerbare rollen te helpen testen.

Vereenvoudigde beschrijving: het molecuul maakt een instantie op het platform dat u opgeeft (cloud, virtuele machine, container; zie voor meer details de sectie bestuurder), voert uw rol erop uit, voert vervolgens tests uit en verwijdert de instantie. Als een van de stappen mislukt, zal de Molecule u hierover informeren.

Nu meer.

Een beetje theorie

Beschouw twee belangrijke entiteiten van het molecuul: Scenario en Driver.

Scenario

Het script bevat een beschrijving van wat, waar, hoe en in welke volgorde er wordt uitgevoerd. Eén rol kan meerdere scripts hebben, en elk is een map langs het pad <role>/molecule/<scenario>, dat beschrijvingen bevat van de acties die nodig zijn voor de test. Script moet worden opgenomen default, die automatisch wordt aangemaakt als u de rol initialiseert met een molecuul. De namen van de volgende scripts zijn aan jou.

De reeks testacties in een script wordt genoemd Matrix, en standaard is dit:

(Stappen gelabeld ?, standaard overgeslagen als dit niet is opgegeven door de gebruiker)

  • lint - lopende linters. Standaard worden gebruikt yamllint и flake8,
  • destroy - het verwijderen van instanties van de laatste lancering van de Molecule (indien aanwezig),
  • dependency? — installatie van de weerwerende afhankelijkheid van de geteste rol,
  • syntax - het controleren van de syntaxis van de rol die gebruikt wordt ansible-playbook --syntax-check,
  • create - een exemplaar maken,
  • prepare? — voorbereiding van de instantie; controleer/installeer bijvoorbeeld Python2
  • converge — lancering van het draaiboek dat wordt getest,
  • idempotence - het draaiboek voor de idempotentietest opnieuw opstarten,
  • side_effect? - acties die niet direct verband houden met de rol, maar wel noodzakelijk zijn voor tests,
  • verify - tests uitvoeren van de resulterende configuratie met behulp van testinfra(standaard) /goss/inspec,
  • cleanup? - (in nieuwe versies) - grofweg het "reinigen" van de externe infrastructuur die door de Molecule wordt beïnvloed,
  • destroy - Een exemplaar verwijderen.

Deze volgorde dekt de meeste gevallen, maar kan indien nodig worden gewijzigd.

Elk van de bovenstaande stappen kan afzonderlijk worden uitgevoerd met molecule <command>. Maar het moet duidelijk zijn dat er voor elk van deze cli-commando's een eigen reeks acties kan zijn, die u kunt achterhalen door het uitvoeren van molecule matrix <command>. Bijvoorbeeld bij het uitvoeren van de opdracht converge (door het testboek uit te voeren), worden de volgende acties uitgevoerd:

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

De volgorde van deze acties kan worden bewerkt. Als iets uit de lijst al is gedaan, wordt dit overgeslagen. De huidige status, evenals de configuratie van de instanties, slaat de Molecule op in de map $TMPDIR/molecule/<role>/<scenario>.

Voeg stappen toe met ? u kunt de gewenste acties beschrijven in het ansible-playbook-formaat en de bestandsnaam maken volgens de stap: prepare.yml/side_effect.yml. Verwacht deze bestanden. Het molecuul bevindt zich in de scriptmap.

bestuurder

Een driver is een entiteit waarin testinstanties worden gemaakt.
De lijst met standaard drivers waarvoor Molecule templates klaar heeft staan ​​is als volgt: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

In de meeste gevallen zijn sjablonen bestanden create.yml и destroy.yml in de scriptmap die respectievelijk het maken en verwijderen van een exemplaar beschrijft.
De uitzonderingen zijn Docker en Vagrant, omdat interacties met hun modules kunnen plaatsvinden zonder de bovengenoemde bestanden.

Het is de moeite waard om het gedelegeerde stuurprogramma te benadrukken, omdat als het wordt gebruikt in de bestanden voor het maken en verwijderen van een exemplaar, alleen het werk met de configuratie van exemplaren wordt beschreven, de rest moet door de ingenieur worden beschreven.

Het standaardstuurprogramma is Docker.

Laten we nu verder gaan met oefenen en verdere functies daar overwegen.

Aan de slag

Laten we als "hallo wereld" een eenvoudige nginx-installatierol testen. Laten we docker als stuurprogramma kiezen - ik denk dat de meesten van jullie het geïnstalleerd hebben (en onthoud dat docker het standaardstuurprogramma is).

Laten we ons voorbereiden virtualenv en installeer daarin molecule:

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

De volgende stap is het initialiseren van de nieuwe rol.
Initialisatie van een nieuwe rol, evenals een nieuw script, wordt uitgevoerd met behulp van de opdracht 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

Het bleek een typische weerwortrol. Verder vinden alle interacties met CLI-moleculen plaats vanuit de basis van de rol.

Laten we eens kijken wat er in de rolmap staat:

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

1 directory, 6 files

Laten we de configuratie analyseren molecule/default/molecule.yml (vervang alleen docker-afbeelding):

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

afhankelijkheid

In deze sectie wordt de bron van afhankelijkheden beschreven.

Mogelijke opties: melkweg, verguld, schelp.

Shell is slechts een commandoshell die wordt gebruikt als Galaxy en Gilt niet aan uw behoeften voldoen.

Ik zal hier niet lang blijven wonen, het is genoeg beschreven documentatie.

bestuurder

De naam van de bestuurder. Die van ons is dokwerker.

pluis

Het linter is yamllint.

Handige opties in dit deel van de configuratie zijn de mogelijkheid om een ​​configuratiebestand voor yamllint te specificeren, omgevingsvariabelen door te sturen of de linter uit te schakelen:

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

platforms

Beschrijft de configuratie van de instances.
In het geval van docker als driver wordt de Molecule herhaald in deze sectie en is elk element van de lijst beschikbaar in Dockerfile.j2 als variabele item.

In het geval van een bestuurder die dit vereist create.yml и destroy.yml, de sectie is daarin beschikbaar als molecule_yml.platforms, en iteraties erover worden al beschreven in deze bestanden.

Omdat de Molecule controle geeft over instances van weerwortmodules, moet daar ook naar de lijst met mogelijke instellingen worden gezocht. Voor docker wordt bijvoorbeeld de module gebruikt docker_container_module. Welke modules in andere stuurprogramma's worden gebruikt, kunt u vinden in documentatie.

Evenals voorbeelden van het gebruik van verschillende stuurprogramma's zijn te vinden in de tests van het molecuul zelf.

Vervang hier cent: 7 op ubuntu.

bevoorrader

"Leverancier": een entiteit die instanties beheert. In het geval van Molecule is dit een weersbaard, ondersteuning voor anderen is niet gepland, dus deze sectie kan met een voorbehoud de weersbaarde uitgebreide configuratie worden genoemd.
Hier kun je veel dingen specificeren, ik zal naar mijn mening de belangrijkste punten benadrukken:

  • playbooks: u kunt opgeven welke draaiboeken in bepaalde fasen moeten worden gebruikt.

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

  • opties: Ansible-opties en omgevingsvariabelen

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

scenario

Naam en beschrijving van scriptreeksen.
U kunt de standaard actiematrix van elke opdracht wijzigen door de sleutel toe te voegen <command>_sequence en als waarde ervoor door de lijst met stappen te definiëren die we nodig hebben.
Laten we zeggen dat we de volgorde van acties willen wijzigen bij het uitvoeren van de opdracht Playbook run: molecule converge

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

verificateur

Opzetten van een raamwerk voor testen en een vervolg daarop. De standaardlinter is testinfra и flake8. De mogelijke opties zijn dezelfde als hierboven:

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

Laten we terugkeren naar onze rol. Laten we het bestand bewerken tasks/main.yml naar dit soort:

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

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

En voeg tests toe 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")

Klaar, het blijft alleen maar rennen (vanaf de wortel van de rol, laat me je eraan herinneren):

> molecule test

Lange uitlaat onder de 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

Onze eenvoudige rol werd zonder problemen getest.
Het is de moeite waard eraan te denken dat als er problemen zijn tijdens het werk molecule test, en als u de standaardreeks niet hebt gewijzigd, zal de Molecule de instantie verwijderen.

De volgende opdrachten zijn handig voor foutopsporing:

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

Bestaande rol

Het toevoegen van een nieuw script aan een bestaande rol is uit de rollenmap met de volgende commando's:

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

Als dit het eerste scenario in de rol is, dan de parameter -s kan worden weggelaten omdat er dan een script wordt gemaakt default.

Conclusie

Zoals u kunt zien, is de Molecule niet erg complex, en door uw eigen sjablonen te gebruiken, kan het implementeren van een nieuw script worden beperkt tot het bewerken van variabelen in de playbooks voor het maken en verwijderen van instanties. Het molecuul integreert naadloos met CI-systemen, waardoor u de ontwikkelingssnelheid kunt verhogen door de tijd voor het handmatig testen van playbooks te verkorten.

Bedankt voor uw aandacht. Als je ervaring hebt met het testen van weerwortrollen, en het is niet gerelateerd aan het molecuul, vertel het ons dan in de reacties!

Bron: www.habr.com

Voeg een reactie