Istruzzioni: cumu pruvà i roli ansible è scopre i prublemi prima di pruduzzione

Bonghjornu ognunu!

U travagliu cum'è un ingegnere DevOps in un serviziu di prenotazione di hotel. Ostrovok.ru. In questu articulu, vogliu parlà di a nostra sperienza in a prova di roli ansible.

À Ostrovok.ru, usemu ansible cum'è gestore di cunfigurazione. Ricertamenti, avemu ghjuntu à a necessità di pruvà roli, ma cum'è si girò fora, ùn ci sò tanti arnesi per questu - u più populari, forsi, hè u framework Molecule, cusì avemu decisu di usà. Ma hè stata chì a so ducumentazione hè silenziu annantu à parechje trappule. Ùn pudemu micca truvà un manuale abbastanza detallatu in Russu, cusì avemu decisu di scrive stu articulu.

Istruzzioni: cumu pruvà i roli ansible è scopre i prublemi prima di pruduzzione

Molecula

Molécula - un framework per aiutà à pruvà roli ansible.

Descrizzione simplificata: A molécula crea una istanza nantu à a piattaforma chì specificate (nuvola, macchina virtuale, cuntainer; per più dettagli, vede a sezione cunduttori), eseguisce u vostru rolu nantu à questu, poi eseguite testi è sguassate l'istanza. In casu di fallimentu nantu à unu di i passi, a Molecule vi informarà.

Avà più.

Un pocu di tiurìa

Cunsiderate duie entità chjave di a Molecule: Scenariu è Driver.

Scenario

U script cuntene una descrizzione di ciò chì, induve, cumu è in quale sequenza serà realizatu. Un rolu pò avè parechje script, è ognunu hè un repertoriu longu u percorsu <role>/molecule/<scenario>, chì cuntene descrizzioni di l'azzioni necessarii per a prova. U script deve esse inclusu default, chì serà automaticamente creatu si inizializza u rolu cù una Molecule. I nomi di i seguenti scripts sò à voi.

A sequenza di l'azzioni di teste in un script hè chjamatu Matrici, è per difettu hè:

(Passi marcati ?, saltatu per difettu se ùn hè micca specificatu da l'utilizatore)

  • lint - corsa linters. Per automaticamente sò usati yamllint и flake8,
  • destroy - sguassà istanze da l'ultimu lanciu di a Molecule (se ci hè),
  • dependency? - stallazione di a dependenza ansible di u rolu testatu,
  • syntax - cuntrollà a sintassi di u rolu usendu ansible-playbook --syntax-check,
  • create - crià un esempiu,
  • prepare? - preparazione di l'istanza; per esempiu, verificate / installate python2
  • converge - lanciazione di u playbook in prova,
  • idempotence - riavvia u playbook per a prova di idempotenza,
  • side_effect? - azzioni micca direttamente ligati à u rolu, ma necessarii per e teste,
  • verify - Esecuzione di teste di a cunfigurazione risultante utilizendu testinfra(default) /goss/inspec,
  • cleanup? - (in e versioni novi) - grosso modo, "pulizia" l'infrastruttura esterna affettata da a Molecule,
  • destroy - Eliminazione di una istanza.

Questa sequenza copre a maiò parte di i casi, ma pò esse cambiatu se ne necessariu.

Ciascuna di i passi sopra pò esse eseguitu separatamente molecule <command>. Ma deve esse capitu chì per ogni tali cli-command pò esse a so propria sequenza d'azzioni, chì pudete scopre eseguendu. molecule matrix <command>. Per esempiu, quandu eseguisce u cumandamentu converge (eseguendu u playbook in prova), e seguenti azzioni seranu realizate:

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

A sequenza di sti azzioni pò esse editatu. Se qualcosa di a lista hè digià fattu, serà saltatu. U statu attuale, è ancu a cunfigurazione di l'istanze, a Molecule guarda in u cartulare $TMPDIR/molecule/<role>/<scenario>.

Aghjunghjite i passi cù ? pudete discrive l'azzioni desiderate in u formatu ansible-playbook, è fate u nome di u schedariu secondu u passu: prepare.yml/side_effect.yml. Aspettate questi schedari A molécula serà in u cartulare di script.

cunduttori

Un driver hè una entità induve l'istanze di prova sò create.
A lista di i driver standard per i quali Molecule hà mudelli pronti hè a seguente: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

In a maiò parte di i casi, i mudelli sò schedari create.yml и destroy.yml in u cartulare di script chì descrizanu a creazione è l'eliminazione di una istanza, rispettivamente.
L'eccezzioni sò Docker è Vagrant, postu chì l'interazzione cù i so moduli ponu accade senza i schedarii sopra citati.

Vale a pena mette in risaltu u driver Delegatu, postu chì s'ellu hè utilizatu in i schedari per creà è sguassà una istanza, solu travaglià cù a cunfigurazione di l'istanze hè descrittu, u restu deve esse descrittu da l'ingegnere.

U driver predeterminatu hè Docker.

Avà andemu à a pratica è cunsiderà più funzioni quì.

Getting passé

Cum'è un "salutu mondu", pruvemu un rolu simplice di installazione nginx. Scegliemu docker cum'è u driver - Pensu chì a maiò parte di voi l'avete installatu (è ricordate chì docker hè u driver predeterminatu).

Preparate virtualenv è stallà in lu molecule:

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

U prossimu passu hè di inizializà u novu rolu.
L'inizializazione di un novu rolu, è ancu un novu script, hè realizatu cù u cumandamentu 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

Risultò un rolu tipicu ansible. Inoltre, tutte l'interazzione cù Molecules CLI sò fatti da a radica di u rolu.

Videmu ciò chì hè in u cartulare di u rolu:

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

1 directory, 6 files

Analizemu a cunfigurazione molecule/default/molecule.yml (sustituisci solu l'imaghjini docker):

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

dipendenza

Questa sezione descrive a fonte di dipendenze.

Opzioni pussibuli: aise, giltar, cunchiglia.

Shell hè solu una cunchiglia di cumanda chì hè aduprata in casu chì a galaxia è u doru ùn copre micca i vostri bisogni.

Ùn staraghju micca quì per un bellu pezzu, hè abbastanza descrittu in ducumentazione.

mutori

U nome di u cunduttore. U nostru hè docker.

lintà

U linter hè yamllint.

Opzioni utili in questa parte di a cunfigurazione sò a capacità di specificà un schedariu di cunfigurazione per yamllint, variabili di l'ambienti in avanti, o disattivà u linter:

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

Plataformi

Descrive a cunfigurazione di l'istanze.
In u casu di docker cum'è driver, a Molecule hè iterata nantu à sta sezione, è ogni elementu di a lista hè dispunibule in Dockerfile.j2 cum'è una variabile item.

In u casu di un cunduttore chì esige create.yml и destroy.yml, a rùbbrica hè dispunibule in elli cum'è molecule_yml.platforms, è iterazioni sopra sò digià descritte in questi schedari.

Siccomu a Molecule furnisce u cuntrollu di l'istanze à i moduli ansible, a lista di paràmetri pussibuli deve ancu esse cercata quì. Per docker, per esempiu, u modulu hè utilizatu docker_container_module. Quali moduli sò usati in altri drivers ponu esse truvati in ducumentazione.

In quantu esempi di l'usu di diversi drivers ponu esse truvati in i testi di a Molecule stessu.

Sustituisci quì centu: 7 nantu ubuntu su.

prestatore

"Fornitore" - una entità chì gestisce i casi. In u casu di Molecule, questu hè ansible, u supportu per l'altri ùn hè micca pianificatu, perchè sta sezione pò esse chjamata cunfigurazione estesa ansible cun un caveat.
Quì pudete specificà assai cose, aghju da mette in risaltu i punti principali, in my opinion:

  • libri di ghjocu: pudete specificà quale playbooks deve esse usatu in certi tappe.

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

  • ozzione: Opzioni Ansible è variabili d'ambiente

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

situazione

Nome è descrizzione di e sequenze di script.
Pudete cambià a matrice di azzione predeterminata di qualsiasi cumanda aghjunghjendu a chjave <command>_sequence è cum'è un valore per ellu definendu a lista di passi chì avemu bisognu.
Diciamu chì vulemu cambià a sequenza di l'azzioni quandu eseguisce u cumandamentu di run playbook: molecule converge

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

cuntrolla

Stabbilimentu di un quadru per e teste è un linter à questu. U linter predeterminatu hè testinfra и flake8. L'opzioni pussibuli sò listessi cum'è sopra:

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

Riturnemu à u nostru rolu. Editemu u schedariu tasks/main.yml à stu tipu:

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

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

È aghjunghje testi à 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")

Fattu, resta solu à curriri (da a radica di u rolu, lasciami ricurdà):

> molecule test

Scarico longu sottu u 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

U nostru rolu simplice hè statu pruvatu senza prublemi.
Hè vale a ricurdà chì s'ellu ci sò prublemi durante u travagliu molecule test, tandu ùn avete micca cambiatu a sequenza predeterminata, a Molecule sguassà l'istanza.

I seguenti cumandamenti sò utili per a debugging:

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

Role esistente

Aghjunghjendu un novu script à un rolu esistente hè da u cartulare di u rolu cù i seguenti cumandamenti:

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

In casu chì questu hè u primu scenariu in u rolu, allora u paràmetru -s pò esse omessi perchè creà un script default.

cunchiusioni

Comu pudete vede, a Molecule ùn hè micca assai cumplessa, è utilizendu i vostri mudelli, l'implementazione di un novu script pò esse ridutta à edità variabili in i playbooks di creazione è eliminazione di istanza. A molécula s'integra perfettamente cù i sistemi CI, chì vi permette di aumentà a velocità di sviluppu riducendu u tempu per a prova manuale di playbooks.

Grazie per a vostra attenzione. Sì avete sperienza in a prova di roli ansible, è ùn hè micca ligata à a Molecule, diteci in i cumenti!

Source: www.habr.com

Add a comment