Norādījumi: kā pārbaudīt iespējamās lomas un uzzināt par problēmām pirms ražošanas

Sveiki visiem!

Es strādāju par DevOps inženieri viesnīcu rezervēšanas pakalpojumā. Ostrovok.ru. Šajā rakstā es vēlos runāt par mūsu pieredzi iespējamo lomu pārbaudē.

Vietnē Ostrovok.ru mēs izmantojam ansible kā konfigurācijas pārvaldnieku. Nesen mēs nonācām pie nepieciešamības pārbaudīt lomas, taču, kā izrādījās, tam nav tik daudz rīku - vispopulārākais, iespējams, ir Molecule ietvars, tāpēc nolēmām to izmantot. Bet izrādījās, ka viņa dokumentācija klusē par daudzām kļūmēm. Mēs nevarējām atrast pietiekami detalizētu rokasgrāmatu krievu valodā, tāpēc nolēmām uzrakstīt šo rakstu.

Norādījumi: kā pārbaudīt iespējamās lomas un uzzināt par problēmām pirms ražošanas

molekula

Molekula - sistēma, kas palīdz pārbaudīt iespējamās lomas.

Vienkāršots apraksts: molekula izveido instanci jūsu norādītajā platformā (mākonis, virtuālā mašīna, konteiners; sīkāku informāciju skatiet sadaļā Vadītājs), izpilda tajā jūsu lomu, pēc tam veic testus un izdzēš gadījumu. Neveiksmes gadījumā kādā no soļiem Molekula jūs par to informēs.

Tagad vairāk

Mazliet teorija

Apsveriet divas galvenās molekulas vienības: scenārijs un draiveris.

Scenārijs

Skripts satur aprakstu, kas, kur, kā un kādā secībā tiks izpildīts. Vienai lomai var būt vairāki skripti, un katrs no tiem ir direktorijs ceļā <role>/molecule/<scenario>, kas satur testam nepieciešamo darbību aprakstus. Jāiekļauj skripts default, kas tiks automātiski izveidota, ja inicializēsit lomu ar molekulu. Tālāk norādīto skriptu nosaukumi ir jūsu ziņā.

Tiek izsaukta skripta testēšanas darbību secība matrica, un pēc noklusējuma tas ir:

(Soļi ir marķēti ?, pēc noklusējuma tiek izlaists, ja lietotājs to nav norādījis)

  • lint - skriešanas līkumi. Pēc noklusējuma tiek izmantoti yamllint и flake8,
  • destroy - gadījumu dzēšana no pēdējās molekulas palaišanas (ja tāda ir),
  • dependency? — pārbaudītās lomas iespējamās atkarības uzstādīšana,
  • syntax - lomas sintakses pārbaude, izmantojot ansible-playbook --syntax-check,
  • create - izveidot piemēru,
  • prepare? — lietas sagatavošana; piemēram, pārbaudiet/instalējiet python2
  • converge — testējamās rokasgrāmatas palaišana,
  • idempotence - idempotences testa rokasgrāmatas restartēšana,
  • side_effect? - darbības, kas nav tieši saistītas ar lomu, bet nepieciešamas testiem,
  • verify - iegūtās konfigurācijas testu veikšana, izmantojot testinfra(noklusējums) /goss/inspec,
  • cleanup? - (jaunās versijās) - rupji sakot, Molekulas ietekmētās ārējās infrastruktūras "tīrīšana",
  • destroy - instances dzēšana.

Šī secība aptver lielāko daļu gadījumu, taču vajadzības gadījumā to var mainīt.

Katru no iepriekšminētajām darbībām var veikt atsevišķi ar molecule <command>. Bet jāsaprot, ka katrai šādai klimandam var būt sava darbību secība, kuru varat uzzināt, izpildot molecule matrix <command>. Piemēram, palaižot komandu converge (palaižot pārbaudāmo rokasgrāmatu), tiks veiktas šādas darbības:

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

Šo darbību secību var rediģēt. Ja kaut kas no saraksta jau ir izdarīts, tas tiks izlaists. Pašreizējo stāvokli, kā arī gadījumu konfigurāciju Molecule saglabā direktorijā $TMPDIR/molecule/<role>/<scenario>.

Pievienojiet soļus ar ? jūs varat aprakstīt vēlamās darbības ansible-playbook formātā un izveidot faila nosaukumu atbilstoši darbībai: prepare.yml/side_effect.yml. Gaidiet šos failus Molekula atradīsies skripta mapē.

Vadītājs

Draiveris ir entītija, kurā tiek izveidoti testa gadījumi.
Standarta draiveru saraksts, kuriem Molecule ir gatavas veidnes, ir šāds: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

Vairumā gadījumu veidnes ir faili create.yml и destroy.yml skripta mapē, kas attiecīgi apraksta instances izveidi un dzēšanu.
Izņēmumi ir Docker un Vagrant, jo mijiedarbība ar to moduļiem var notikt bez iepriekšminētajiem failiem.

Ir vērts izcelt deleģēto draiveri, jo, ja tas tiek izmantots failos instances izveidei un dzēšanai, ir aprakstīts tikai darbs ar gadījumu konfigurāciju, pārējais jāapraksta inženierim.

Noklusējuma draiveris ir Docker.

Tagad pāriesim pie prakses un apsvērsim turpmākās funkcijas.

Darba sākšana

Kā "sveika pasaule", pārbaudīsim vienkāršu nginx instalēšanas lomu. Mēs izvēlēsimies docker kā draiveri — es domāju, ka lielākajai daļai no jums tas ir instalēts (un atcerieties, ka docker ir noklusējuma draiveris).

Sagatavot virtualenv un instalējiet tajā molecule:

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

Nākamais solis ir inicializēt jauno lomu.
Jaunas lomas, kā arī jauna skripta inicializācija tiek veikta, izmantojot komandu 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

Izrādījās tipiska iespējamā loma. Turklāt visas mijiedarbības ar CLI molekulām tiek veidotas no lomas saknes.

Apskatīsim, kas atrodas lomu direktorijā:

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

1 directory, 6 files

Analizēsim konfigurāciju molecule/default/molecule.yml (aizstāt tikai docker attēlu):

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

atkarība

Šajā sadaļā ir aprakstīts atkarību avots.

Iespējamie varianti: galaktika, giltar, apvalks.

Shell ir tikai komandu apvalks, kas tiek izmantots gadījumam, ja galaktika un gilt neatbilst jūsu vajadzībām.

Es šeit ilgi nekavēšos, tas ir pietiekami aprakstīts dokumentācija.

vadītājs

Vadītāja vārds. Mūsējais ir dokeris.

savārstījums

Linters ir yamllint.

Noderīgas opcijas šajā konfigurācijas daļā ir iespēja norādīt yamllint konfigurācijas failu, pārsūtīt vides mainīgos vai atspējot linteri:

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

platformas

Apraksta gadījumu konfigurāciju.
Docker kā draivera gadījumā molekula tiek atkārtota šajā sadaļā, un katrs saraksta elements ir pieejams Dockerfile.j2 kā mainīgo item.

Gadījumā, ja vadītājs, kas prasa create.yml и destroy.yml, sadaļa tajos ir pieejama kā molecule_yml.platforms, un iterācijas pār to jau ir aprakstītas šajos failos.

Tā kā Molecule nodrošina iespējamo moduļu gadījumu kontroli, tur ir jāmeklē arī iespējamo iestatījumu saraksts. Piemēram, dokerim tiek izmantots modulis docker_container_module. Kuri moduļi tiek izmantoti citos draiveros, varat uzzināt dokumentācija.

Kā arī var atrast dažādu draiveru izmantošanas piemērus pašas molekulas testos.

Nomainiet šeit centos:7 par Ubuntu.

nodrošinātājs

"Piegādātājs" - entītija, kas pārvalda gadījumus. Molecule gadījumā tas ir iespējams, atbalsts citiem nav plānots, tāpēc šo sadaļu ar piebildi var saukt par ansible paplašināto konfigurāciju.
Šeit jūs varat norādīt daudzas lietas, es izcelšu galvenos punktus, manuprāt:

  • rotaļu grāmatas: varat norādīt, kuras rokasgrāmatas ir jāizmanto noteiktos posmos.

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

  • savienojuma_iespējas: opcijas savieno

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

  • iespējas: iespējamās opcijas un vides mainīgie

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

scenārijs

Skriptu secību nosaukums un apraksts.
Varat mainīt jebkuras komandas noklusējuma darbību matricu, pievienojot atslēgu <command>_sequence un kā vērtību, definējot nepieciešamo darbību sarakstu.
Pieņemsim, ka, palaižot rokasgrāmatas palaišanas komandu, vēlamies mainīt darbību secību: molecule converge

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

pārbaudītājs

Pārbaužu ietvara iestatīšana un tā savienojuma izveide. Noklusējuma līnīte ir testinfra и flake8. Iespējamās iespējas ir tādas pašas kā iepriekš:

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

Atgriezīsimies pie savas lomas. Rediģēsim failu tasks/main.yml šāda veida:

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

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

Un pievienojiet testus 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")

Gatavs, atliek tikai skriet (no lomas saknes atgādināšu):

> molecule test

Gara izplūde zem spoileri:

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

Mūsu vienkāršā loma tika pārbaudīta bez problēmām.
Ir vērts atcerēties, ka, ja darba laikā rodas problēmas molecule test, tad, ja nemainījāt noklusējuma secību, molekula izdzēsīs gadījumu.

Šādas komandas ir noderīgas atkļūdošanai:

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

Esošā loma

Jauna skripta pievienošana esošai lomai ir no lomu direktorijas ar šādām komandām:

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

Ja šis ir pirmais scenārijs lomai, tad parametrs -s var izlaist, jo tiks izveidots skripts default.

Secinājums

Kā redzat, molekula nav īpaši sarežģīta, un, izmantojot savas veidnes, jauna skripta izvietošanu var samazināt līdz mainīgo rediģēšanai gadījumu izveides un dzēšanas rokasgrāmatās. Molekula nemanāmi integrējas ar CI sistēmām, kas ļauj palielināt izstrādes ātrumu, samazinot laiku rokasgrāmatu testēšanai.

Paldies par jūsu uzmanību. Ja tev ir pieredze spējīgu lomu testēšanā, un tas nav saistīts ar Molekulu, pastāsti par to komentāros!

Avots: www.habr.com

Pievieno komentāru