Instruktioner: hvordan man tester mulige roller og finder ud af problemer før produktion

Hej alle!

Jeg arbejder som DevOps-ingeniør i en hotelbookingstjeneste. Ostrovok.ru. I denne artikel vil jeg fortælle om vores erfaring med at teste mulige roller.

Hos Ostrovok.ru bruger vi ansible som konfigurationsmanager. For nylig kom vi til behovet for at teste roller, men som det viste sig, er der ikke så mange værktøjer til dette - det mest populære er måske Molecule-rammen, så vi besluttede at bruge det. Men det viste sig, at hans dokumentation er tavs om mange faldgruber. Vi kunne ikke finde en tilstrækkelig detaljeret manual på russisk, så vi besluttede at skrive denne artikel.

Instruktioner: hvordan man tester mulige roller og finder ud af problemer før produktion

Molecule

Molekyle - en ramme for at hjælpe med at teste mulige roller.

Forenklet beskrivelse: Molekylet opretter en instans på den platform, du angiver (sky, virtuel maskine, container; for flere detaljer, se afsnittet Chauffør), kører din rolle på den, kører derefter test og sletter forekomsten. I tilfælde af fejl på et af trinene, vil Molekylet informere dig om det.

Nu mere.

Lidt teori

Overvej to nøgleenheder af molekylet: Scenario og Driver.

Scenario

Scriptet indeholder en beskrivelse af hvad, hvor, hvordan og i hvilken rækkefølge, der skal udføres. En rolle kan have flere scripts, og hver rolle er en mappe langs stien <role>/molecule/<scenario>, som indeholder beskrivelser af de handlinger, der kræves til testen. Script skal medfølge default, som oprettes automatisk, hvis du initialiserer rollen med et molekyle. Navnene på følgende scripts er op til dig.

Sekvensen af ​​testhandlinger i et script kaldes matrix, og som standard er det:

(Trin mærket ?, sprunget over som standard, hvis det ikke er angivet af brugeren)

  • lint - løbende linters. Som standard bruges yamllint и flake8,
  • destroy - sletning af forekomster fra den sidste lancering af molekylet (hvis nogen),
  • dependency? — installation af den mulige afhængighed af den testede rolle
  • syntax - kontrol af rollens syntaks ved hjælp af ansible-playbook --syntax-check,
  • create - oprettelse af en instans,
  • prepare? — forberedelse af sagen; tjek/installer python2
  • converge — lancering af den spillebog, der testes,
  • idempotence - genstart af spillebogen til idempotenstesten,
  • side_effect? - handlinger, der ikke er direkte relateret til rollen, men nødvendige for tests
  • verify - køre test af den resulterende konfiguration vha testinfra(Standard) /goss/inspec,
  • cleanup? - (i nye versioner) - groft sagt "rengøring" af den eksterne infrastruktur påvirket af molekylet,
  • destroy - Sletning af en instans.

Denne rækkefølge dækker de fleste tilfælde, men kan ændres om nødvendigt.

Hvert af ovenstående trin kan køres separat med molecule <command>. Men det skal forstås, at for hver sådan cli-kommando kan der være sin egen rækkefølge af handlinger, som du kan finde ud af ved at udføre molecule matrix <command>. For eksempel, når du kører kommandoen converge (kører playbook under test), vil følgende handlinger blive udført:

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

Rækkefølgen af ​​disse handlinger kan redigeres. Hvis noget fra listen allerede er udført, vil det blive sprunget over. Den aktuelle tilstand, såvel som konfigurationen af ​​forekomsterne, gemmer Molecule i mappen $TMPDIR/molecule/<role>/<scenario>.

Tilføj trin med ? du kan beskrive de ønskede handlinger i ansible-playbook-formatet og lave filnavnet i henhold til trinnet: prepare.yml/side_effect.yml. Forvent disse filer Molekylet vil være i script-mappen.

Chauffør

En driver er en enhed, hvor testinstanser oprettes.
Listen over standarddrivere, som Molecule har skabeloner klar til, er som følger: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegeret.

I de fleste tilfælde er skabeloner filer create.yml и destroy.yml i script-mappen, der beskriver henholdsvis oprettelse og sletning af en instans.
Undtagelserne er Docker og Vagrant, da interaktioner med deres moduler kan forekomme uden de førnævnte filer.

Det er værd at fremhæve den delegerede driver, da hvis den bruges i filerne til oprettelse og sletning af en instans, beskrives kun arbejdet med konfigurationen af ​​instanser, resten skal beskrives af ingeniøren.

Standarddriveren er Docker.

Lad os nu gå videre til praksis og overveje yderligere funktioner der.

Kom godt i gang

Som en "hej verden", lad os teste en simpel nginx-installationsrolle. Vi vil vælge docker som driver - jeg tror de fleste af jer har det installeret (og husk at docker er standarddriveren).

Lad os forberede os virtualenv og installere i den molecule:

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

Det næste trin er at initialisere den nye rolle.
Initialisering af en ny rolle samt et nyt script udføres ved hjælp af kommandoen 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

Det blev en typisk ansible-rolle. Yderligere er alle interaktioner med CLI Molecules lavet fra roden af ​​rollen.

Lad os se, hvad der er i rollekataloget:

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

1 directory, 6 files

Lad os analysere konfigurationen molecule/default/molecule.yml (erstat kun docker-billede):

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

afhængighed

Dette afsnit beskriver kilden til afhængigheder.

Mulige indstillinger: galakse, gælder, skal.

Shell er blot en kommandoskal, der bruges i tilfælde af, at galaxy og gilt ikke dækker dine behov.

Jeg vil ikke dvæle her længe, ​​det er nok beskrevet i dokumentation.

driver

Navnet på føreren. Vores er havnearbejder.

fnug

Linteret er yamllint.

Nyttige muligheder i denne del af konfigurationen er muligheden for at angive en konfigurationsfil for yamllint, fremsende miljøvariabler eller deaktivere linter:

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

platforme

Beskriver konfigurationen af ​​forekomsterne.
I tilfælde af docker som chauffør, gentages molekylet over dette afsnit, og hvert element på listen er tilgængeligt i Dockerfile.j2 som en variabel item.

I tilfælde af en chauffør, der kræver create.yml и destroy.yml, afsnittet er tilgængeligt i dem som molecule_yml.platforms, og iterationer over det er allerede beskrevet i disse filer.

Da Molecule giver kontrol over forekomster til mulige moduler, bør listen over mulige indstillinger også kigges efter der. Til docker bruges modulet for eksempel docker_container_modul. Hvilke moduler der bruges i andre drivere kan findes i dokumentation.

Samt eksempler på brug af forskellige drivere kan findes i testene af selve Molekylet.

Udskift her centos: 7ubuntu.

proviant

"Leverandør" - en enhed, der administrerer instanser. I tilfælde af Molecule er dette muligt, støtte til andre er ikke planlagt, så dette afsnit kan kaldes en mulig udvidet konfiguration med en advarsel.
Her kan du specificere en masse ting, jeg vil fremhæve hovedpunkterne, efter min mening:

  • playbooks: du kan angive, hvilke spillebøger der skal bruges på bestemte stadier.

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

  • optioner: Ansible muligheder og miljøvariabler

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

scenarie

Navn og beskrivelse af scriptsekvenser.
Du kan ændre standardhandlingsmatrixen for enhver kommando ved at tilføje nøglen <command>_sequence og som en værdi for det ved at definere listen over trin, vi har brug for.
Lad os sige, at vi vil ændre rækkefølgen af ​​handlinger, når du kører kommandoen playbook run: molecule converge

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

verifikator

Opsætning af rammer for test og en linter til det. Standard linter er testinfra и flake8. De mulige muligheder er de samme som ovenfor:

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

Lad os vende tilbage til vores rolle. Lad os redigere filen tasks/main.yml til denne slags:

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

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

Og tilføj test til 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")

Færdig, det er kun tilbage at køre (fra roden af ​​rollen, lad mig minde dig om):

> molecule test

Lang udstødning under spoileren:

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

Vores simple rolle blev testet uden problemer.
Det er værd at huske, at hvis der er problemer under arbejdet molecule test, så hvis du ikke ændrede standardsekvensen, vil Molekylet slette forekomsten.

Følgende kommandoer er nyttige til fejlretning:

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

Eksisterende rolle

Tilføjelse af et nyt script til en eksisterende rolle er fra rollekartoteket med følgende kommandoer:

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

Hvis dette er det første scenarie i rollen, så parameteren -s kan udelades, da det vil skabe et script default.

Konklusion

Som du kan se, er Molekylet ikke særlig komplekst, og ved at bruge dine egne skabeloner kan implementering af et nyt script reduceres til at redigere variabler i instansoprettelse og sletning af playbooks. Molekylet integreres problemfrit med CI-systemer, hvilket giver dig mulighed for at øge udviklingshastigheden ved at reducere tiden til manuel test af playbooks.

Tak for din opmærksomhed. Hvis du har erfaring med at teste mulige roller, og det ikke er relateret til Molekylet, så fortæl os om det i kommentarerne!

Kilde: www.habr.com

Tilføj en kommentar