Instructie: hoe Ansible-rollen te testen en problemen vóór productie te ontdekken

Hallo allemaal!

Ik werk als DevOps-engineer bij een hotelboekingsservice Ostrovok.ru. In dit artikel wil ik onze ervaringen met het testen van Ansible-rollen delen.

Bij Ostrovok.ru gebruiken we Ansible als configuratiemanagementtool. Onlangs kwamen we tot de noodzaak om rollen te testen, maar het bleek dat er niet veel tools voor zijn — de meest populaire is waarschijnlijk het Molecule-framework, daarom hebben we besloten dit te gebruiken. Maar het bleek dat de documentatie veel verborgen valkuilen verdoezelt. We konden geen gedetailleerde handleiding in het Nederlands vinden, dus besloten we dit artikel te schrijven.

Instructie: hoe Ansible-rollen te testen en problemen vóór productie te ontdekken

Molecule

Molecule is een framework dat helpt bij het testen van Ansible-rollen.

Eenvoudige beschrijving: Molecule creëert een instantie op het door u opgegeven platform (cloud, virtuele machine, container; zie het gedeelte Driver), voert uw rol op deze instantie uit, voert dan tests uit en verwijdert de instantie. In het geval van een mislukking in een van de stappen, zal Molecule u hiervan op de hoogte stellen.

Nu wat meer details.

Een beetje theorie

Laten we twee sleutelentiteiten van Molecule bekijken: Scenario en Driver.

Scenario

Een scenario bevat een beschrijving van wat, waar, hoe en in welke volgorde zal worden uitgevoerd. Een rol kan meerdere scenario's hebben, en elk is een directory onder /molecule/, die beschrijvingen van de benodigde acties voor de test bevat. Er moet altijd een scenario aanwezig zijn, dat automatisch wordt aangemaakt als u de rol met Molecule initieert. De namen van de volgende scenario's worden naar uw keuze gekozen. defaultDe reeks acties voor het testen in een scenario wordt genoemd

matrix , en standaard is deze als volgt:(Stappen gemarkeerd

, worden standaard overgeslagen als ze niet door de gebruiker zijn beschreven) ?lint

  • is het uitvoeren van linters. Standaard worden flake8 yamllint en destroy,
  • is het verwijderen van instanties van de vorige Molecule-uitvoering (als die er zijn), syntax
  • dependency? — установка ansible-зависимости тестируемой роли,
  • is de syntaxiscontrole van de rol met behulp van ansible-playbook --syntax-check is het creëren van een instantie,,
  • create prepare
  • is het uitvoeren van het te testen playbook,? — подготовка инстанса; например, проверка / установка python2
  • converge idempotence
  • is het opnieuw uitvoeren van het playbook voor een test op idempotentie, side_effect
  • verify? — действия, не относящиеся непосредственно к роли, но нужные для тестов,
  • is het uitvoeren van tests op de verkregen configuratie met behulp van testinfra (standaard) /gossinspec/cleanup,
  • is het verwijderen van de instantie.? — (в новых версиях) — грубо говоря, «очистка» внешней инфраструктуры, задетой Молекулой,
  • is het verwijderen van instanties van de vorige Molecule-uitvoering (als die er zijn), Deze volgorde dekt de meeste gevallen, maar kan indien nodig worden gewijzigd.

Deze reeks dekt de meeste gevallen, maar kan indien nodig worden aangepast.

Elke van de bovenstaande stappen kan afzonderlijk worden uitgevoerd met behulp van molecule. Maar men moet begrijpen dat er voor elke dergelijke cli-opdracht een specifieke volgorde van acties kan bestaan, die kan worden achterhaald door het uitvoeren van molecule matrix. Bijvoorbeeld, bij het uitvoeren van de opdracht converge (uitvoering van de te testen playbook) worden de volgende acties uitgevoerd:

$ molecule matrix converge
...
└── default         # naam van het scenario
    ├── dependency  # installeren van afhankelijkheden
    ├── create      # aanmaken van de instantie
    ├── prepare     # voorbereiden van de instantie
    └── converge    # uitvoeren van de playbook

De volgorde van deze acties kan worden bewerkt. Als iets uit de lijst al is uitgevoerd, wordt het overgeslagen. De huidige status, evenals de configuratie van de instanties, worden door Molecule opgeslagen in de directory $TMPDIR/molecule//.

Stappen met ? kun je toevoegen door de gewenste acties te beschrijven in het formaat van een ansible-playbook, en de bestandsnaam overeenkomstig te maken: prepare.yml/side_effect.yml. Molecule verwacht deze bestanden in de scenario-map.

Driver

Een driver is een entiteit waar instanties voor tests worden aangemaakt.
De lijst van standaarddragers waarvoor Molecule sjablonen heeft, is als volgt: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

In de meeste gevallen zijn de sjablonen bestanden create.yml en destroy.yml in de scenario-map die respectievelijk de creatie en verwijdering van een instantie beschrijven.
Uitzonderingen zijn Docker en Vagrant, aangezien de interactie met hun modules kan plaatsvinden zonder de eerder genoemde bestanden.

Het is belangrijk om de driver Delegated te benadrukken, omdat in het geval dat deze wordt gebruikt in de bestanden voor de creatie en verwijdering van de instantie alleen de configuratie van de instanties wordt beschreven, de rest moet door de ingenieur worden beschreven.

De standaard driver is Docker.

Laten we nu naar de praktijk gaan en verdere details daar bespreken.

Aan de slag

Als ‘hello world’ testen we een eenvoudige rol voor het installeren van nginx. Als driver kiezen we Docker - ik denk dat de meeste van jullie dit al hebben geïnstalleerd (en vergeet niet dat Docker de standaard driver is).

Laten we voorbereiden virtualenv en installeren in deze molecule:

> pip install virtualenv
> virtualenv -p `which python2` venv
> source venv/bin/activate
> pip install molecule docker  # molecule installeert ansible als afhankelijkheid; docker voor de driver

De volgende stap is het initialiseren van een nieuwe rol.
Het initialiseren van een nieuwe rol, net als een nieuw scenario, gebeurt met het commando molecule init:

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

6 directories, 1 file

We hebben een typische Ansible-rol. Verder worden alle interacties met de Molecule CLI vanaf de hoofdrol uitgevoerd.

Laten we eens kijken wat er in de rolmap staat:

> tree molecule/default/
molecule/default/
├── Dockerfile.j2  # Jinja-sjabloon voor Dockerfile
├── INSTALL.rst.   # Enige informatie over de installatie van dependencies
├── molecule.yml   # Configuratiebestand
├── playbook.yml   # Playbook voor het starten van de rol
└── tests          # Map met tests voor de verificatiefase
    └── test_default.py

1 directory, 6 files

Laten we de configuratie bekijken molecule/default/molecule.yml (alleen de docker image vervangen):

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

dependency

Deze sectie beschrijft de oorsprong van de dependencies.

Mogelijke opties: galaxy, gilt, shell.

Shell is gewoon een command-line interface die wordt gebruikt als galaxy en gilt niet aan uw behoeften voldoen.

Ik zal hier niet lang bij stil staan, het is genoeg beschreven in de documentatie.

driver

De naam van de driver. Dit is in ons geval docker.

is het uitvoeren van linters. Standaard worden

Als linter wordt yamllint gebruikt.

Handige opties in dit deel van de configuratie zijn de mogelijkheid om een configuratiebestand voor yamllint op te geven, omgevingsvariabelen door te geven, 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 instanties.
In het geval van docker als de driver, iterates Molecule door deze sectie en elk element van de lijst is beschikbaar in Dockerfile.j2 als variabele item.

In het geval van een driver waarbij dwingend create.yml en destroy.yml, is de sectie in hen beschikbaar als molecule_yml.platforms, en de iteraties daarvan zijn al in deze bestanden beschreven.

Aangezien Molecule het beheer van instantiën aan Ansible-modules biedt, moet de lijst met mogelijke instellingen daar worden gezocht. Voor docker bijvoorbeeld, wordt de module docker_container_module. Welke modules worden gebruikt in de andere drivers, kan worden gevonden in de documentatie.

Voorbeelden van het gebruik van verschillende drivers kunnen worden gevonden in de tests van Molecule zelf.

Laten we hier vervangen centos:7 en een werkende opdracht krijgen. ubuntu.

provisioner

"Leverancier" is een entiteit die instantiën beheert. In het geval van Molecule is dit Ansible, ondersteuning voor andere wordt niet gepland, dus deze sectie kan met enige voorzichtigheid als uitgebreide configuratie van Ansible worden beschouwd.
Hier kunnen veel dingen worden vermeld, maar ik zal de belangrijkste punten uitlichten, naar mijn mening:

  • playbooks: het is mogelijk om aan te geven welke playbooks op specifieke momenten 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'"

  • options: Ansible parameters en omgevingsvariabelen

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

scenario

Naam en beschrijving van scenario sequenties.
De standaardactie matrix van een specifiek commando kan worden gewijzigd door een sleutel toe te voegen _sequence en als waarde voor deze sleutel de gewenste lijst van stappen te definiëren.
Stel dat we de volgorde van acties willen wijzigen wanneer we het commando voor het uitvoeren van de playbook starten: molecule converge

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

verifier

Instellen van het framework voor tests en de linter daarvan. Standaard wordt als linter gebruikt (standaard) / en destroy. Mogelijke opties zijn vergelijkbaar met de hierboven genoemde:

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. We zullen het bestand bewerken tasks/main.yml tot de volgende vorm:

---
- name: Installeer nginx
  apt:
    name: nginx
    state: present

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

En we voegen tests toe aan 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, we moeten alleen nog maar uitvoeren (vanuit de hoofdrol, ter herinnering):

> molecule test

Lange uitvoer onder de spoiler:

--> Het valideren van schema /nginx/molecule/default/molecule.yml.
Validatie succesvol voltooid.
--> Testmatrix

└── default
    ├── lint
    ├── vernietigen
    ├── afhankelijkheid
    ├── syntaxis
    ├── maken
    ├── voorbereiden
    ├── convergeren
    ├── idempotentie
    ├── neveneffect
    ├── verifiëren
    └── vernietigen

--> Scenario: 'default'
--> Actie: 'lint'
--> Yamllint uitvoeren op bestanden gevonden in /nginx/...
Lint succesvol voltooid.
--> Flake8 uitvoeren op bestanden gevonden in /nginx/molecule/default/tests/...
Lint succesvol voltooid.
--> Ansible Lint uitvoeren op /nginx/molecule/default/playbook.yml...
Lint succesvol voltooid.
--> Scenario: 'default'
--> Actie: 'vernietigen'

    SPEL [Vernietigen] *****************************************************************

    TAK [Vernietig molecule-instantie(s)] ********************************************
    gewijzigd: [localhost] => (item=None)
    gewijzigd: [localhost]

    TAK [Wacht op voltooiing van de verwijdering van instantie(s)] *******************************
    ok: [localhost] => (item=None)
    ok: [localhost]

    TAK [Verwijder docker netwerk(en)] ************************************************

    SPEL SAMENVATTING *********************************************************************
    localhost                  : ok=2    gewijzigd=1    onbereikbaar=0    mislukt=0

--> Scenario: 'default'
--> Actie: 'afhankelijkheid'
Overgeslagen, het vereistenbestand ontbreekt.
--> Scenario: 'default'
--> Actie: 'syntaxis'

    playbook: /nginx/molecule/default/playbook.yml

--> Scenario: 'default'
--> Actie: 'maken'

    SPEL [Maken] ******************************************************************

    TAK [Log in bij een Docker-register] **********************************************
    overgeslagen: [localhost] => (item=None)

    TAK [Maak Dockerfiles van afbeeldingsnamen] *************************************
    gewijzigd: [localhost] => (item=None)
    gewijzigd: [localhost]

    TAK [Ontdek lokale Docker-afbeeldingen] ********************************************
    ok: [localhost] => (item=None)
    ok: [localhost]

    TAK [Bouw een Ansible-compatibele afbeelding] ***************************************
    gewijzigd: [localhost] => (item=None)
    gewijzigd: [localhost]

    TAK [Maak docker netwerk(en)] ************************************************

    TAK [Maak molecule-instantie(s)] *********************************************
    gewijzigd: [localhost] => (item=None)
    gewijzigd: [localhost]

    TAK [Wacht op voltooiing van de creatie van instantie(s)] *******************************
    gewijzigd: [localhost] => (item=None)
    gewijzigd: [localhost]

    SPEL SAMENVATTING *********************************************************************
    localhost                  : ok=5    gewijzigd=4    onbereikbaar=0    mislukt=0

--> Scenario: 'default'
--> Actie: 'voorbereiden'
Overgeslagen, voorbereidingsplaybook niet geconfigureerd.
--> Scenario: 'default'
--> Actie: 'convergeren'

    SPEL [Convergeren] ****************************************************************

    TAK [Feiten verzamelen] *********************************************************
    ok: [instance]

    TAK [nginx : Installeer nginx] ***************************************************
    gewijzigd: [instance]

    TAK [nginx : Start nginx] *****************************************************
    gewijzigd: [instance]

    SPEL SAMENVATTING *********************************************************************
    instance                   : ok=3    gewijzigd=2    onbereikbaar=0    mislukt=0

--> Scenario: 'default'
--> Actie: 'idempotentie'
Idempotentie succesvol voltooid.
--> Scenario: 'default'
--> Actie: 'neveneffect'
Overgeslagen, neveneffectplaybook niet geconfigureerd.
--> Scenario: 'default'
--> Actie: 'verifiëren'
--> Voer Testinfra-tests uit gevonden in /nginx/molecule/default/tests/...
    ============================= test sessie begint ==============================
    platform darwin -- Python 2.7.15, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
    rootdir: /nginx/molecule/default, inifile:
    plugins: testinfra-1.16.0
verzamelde 4 items

    tests/test_default.py ....                                               [100%]

    ========================== 4 geslaagd in 27.23 seconden ===========================
Verifier succesvol voltooid.
--> Scenario: 'default'
--> Actie: 'vernietigen'

    SPEL [Vernietigen] *****************************************************************

    TAK [Vernietig molecule-instantie(s)] ********************************************
    gewijzigd: [localhost] => (item=None)
    gewijzigd: [localhost]

    TAK [Wacht op voltooiing van de verwijdering van instantie(s)] *******************************
    gewijzigd: [localhost] => (item=None)
    gewijzigd: [localhost]

    TAK [Verwijder docker netwerk(en)] ************************************************

    SPEL SAMENVATTING *********************************************************************
    localhost                  : ok=2    gewijzigd=2    onbereikbaar=0    mislukt=0

Onze eenvoudige rol werd probleemloos getest.
Het is belangrijk om te onthouden dat als er problemen optreden bij het werken molecule test, dan, als je de standaard volgorde niet hebt gewijzigd, Molecule de instantie zal verwijderen.

Voor debugging zijn de volgende commando's handig:

> molecule --debug  # debug info. Bij een gewone uitvoering verbergt Molecule de logs.
> molecule converge          # Houdt de instantie na het uitvoeren van de testrol.
> molecule login             # Aanmelden bij de gemaakte instantie.
> molecule --help            # Volledige lijst van commando's.

Bestaande rol

Het toevoegen van een nieuw scenario aan een bestaande rol gebeurt uit de rolmap met de volgende commando's:

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

In het geval dat dit het eerste scenario in de rol is, kan de parameter -s worden weggelaten, aangezien er een scenario zal worden aangemaakt. default.

Conclusie

Zoals je ziet, is Molecule niet erg ingewikkeld, en met het gebruik van eigen sjablonen kun je het implementeren van een nieuw scenario reduceren tot het aanpassen van variabelen in de playbooks voor het maken en verwijderen van instanties. Molecule integreert probleemloos met CI-systemen, wat de ontwikkeling versnelt door de tijd voor handmatige testen van playbooks te verkorten.

Bedankt voor je aandacht. Als je ervaring hebt met het testen van ansible-rollen die niet gerelateerd zijn aan Molecule, laat het me weten in de reacties!

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster