Mga Tagubilin: kung paano subukan ang mga angkop na tungkulin at alamin ang tungkol sa mga problema bago ang produksyon

Kumusta sa lahat!

Nagtatrabaho ako bilang isang DevOps engineer para sa isang serbisyo sa pag-book ng hotel. Ostrovok.ru. Sa artikulong ito gusto kong pag-usapan ang aming karanasan sa pagsubok sa mga tungkulin ng Ansible.

Sa Ostrovok.ru ginagamit namin ang ansible bilang isang configuration manager. Kamakailan ay dumating kami sa pangangailangan na subukan ang mga tungkulin, ngunit, tulad ng nangyari, walang maraming mga tool para dito - ang pinakasikat, marahil, ay ang balangkas ng Molecule, kaya nagpasya kaming gamitin ito. Ngunit lumabas na ang kanyang dokumentasyon ay tahimik tungkol sa maraming mga pitfalls. Hindi kami makahanap ng sapat na detalyadong gabay sa Russian, kaya nagpasya kaming isulat ang artikulong ito.

Mga Tagubilin: kung paano subukan ang mga angkop na tungkulin at alamin ang tungkol sa mga problema bago ang produksyon

Molecule

Molecule — isang balangkas upang makatulong sa pagsubok sa mga tungkuling Ansible.

Pinasimpleng paglalarawan: Ang Molecule ay gumagawa ng isang instance sa platform na iyong tinukoy (cloud, virtual machine, container; para sa higit pang mga detalye, tingnan ang seksyon Drayber), pinapatakbo ang iyong tungkulin dito, pagkatapos ay nagpapatakbo ng mga pagsubok at tinatanggal ang instance. Kung may pagkabigo sa isa sa mga hakbang, aabisuhan ka ng Molecule tungkol dito.

Ngayon higit pa.

Isang kaunting teorya

Isaalang-alang natin ang dalawang pangunahing entity ng Molecule: Scenario at Driver.

Sitwasyon

Ang script ay naglalaman ng isang paglalarawan ng kung ano, saan, paano at sa anong pagkakasunod-sunod ang isasagawa. Ang isang tungkulin ay maaaring magkaroon ng ilang mga script, at bawat isa ay isang direktoryo sa landas <role>/molecule/<scenario>, na naglalaman ng mga paglalarawan ng mga pagkilos na kinakailangan para sa pagsubok. Dapat may script default, na awtomatikong malilikha kung sisimulan mo ang tungkulin gamit ang Molecule. Ang mga pangalan ng mga sumusunod na script ay nasa iyong paghuhusga.

Ang pagkakasunud-sunod ng mga aksyon sa pagsubok sa isang script ay tinatawag matris, at bilang default ay ganito:

(Namarkahan ang mga hakbang ?, ay nilaktawan bilang default kung hindi tinukoy ng user)

  • lint - tumatakbo linters. Bilang default yamllint и flake8,
  • destroy — pagtanggal ng mga instance mula sa huling paglulunsad ng Molecule (kung mayroon man),
  • dependency? — pag-install ng maaasahang dependency ng nasubok na tungkulin,
  • syntax - checking role syntax gamit ansible-playbook --syntax-check,
  • create - paglikha ng isang halimbawa,
  • prepare? - paghahanda ng halimbawa; halimbawa pagsuri/pag-install ng python2
  • converge — paglulunsad ng sinubok na playbook,
  • idempotence — muling patakbuhin ang playbook para sa idempotency test,
  • side_effect? — mga aksyon na hindi direktang nauugnay sa tungkulin, ngunit kinakailangan para sa mga pagsubok,
  • verify — pagpapatakbo ng mga pagsubok ng resultang pagsasaayos gamit testinfra(default) /goss/inspec,
  • cleanup? - (sa mga bagong bersyon) - halos nagsasalita, "paglilinis" sa panlabas na imprastraktura na apektado ng Molecule,
  • destroy — pagtanggal ng isang instance.

Sinasaklaw ng sequence na ito ang karamihan ng mga kaso, ngunit maaaring baguhin kung kinakailangan.

Ang bawat isa sa mga hakbang sa itaas ay maaaring patakbuhin nang hiwalay gamit ang molecule <command>. Ngunit dapat mong maunawaan na para sa bawat naturang cli command ay maaaring mayroong sariling pagkakasunud-sunod ng mga aksyon, na maaari mong malaman sa pamamagitan ng pagpapatakbo molecule matrix <command>. Halimbawa, kapag pinapatakbo ang command converge (pagpapatakbo ng nasubok na playbook) ang mga sumusunod na aksyon ay isasagawa:

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

Maaaring i-edit ang pagkakasunud-sunod ng mga pagkilos na ito. Kung ang isang bagay mula sa listahan ay nakumpleto na, ito ay lalaktawan. Ang kasalukuyang estado, pati na rin ang instance config, ay naka-imbak sa Molecule directory $TMPDIR/molecule/<role>/<scenario>.

Magdagdag ng mga hakbang gamit ang ? Maaari mong ilarawan ang mga gustong aksyon sa Ansible na playbook na format, at gawin ang pangalan ng file ayon sa hakbang: prepare.yml/side_effect.yml. Asahan na ang mga Molecule file na ito ay nasa folder ng script.

Drayber

Ang driver ay isang entity kung saan ang mga pagkakataon para sa mga pagsubok ay nilikha.
Ang listahan ng mga karaniwang driver kung saan ang Molecule ay may mga nakahandang template ay: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

Sa karamihan ng mga kaso, ang mga template ay mga file create.yml и destroy.yml sa folder ng script, na naglalarawan sa paggawa at pagtanggal ng instance, ayon sa pagkakabanggit.
Ang mga pagbubukod ay Docker at Vagrant, dahil ang mga pakikipag-ugnayan sa kanilang mga module ay maaaring mangyari nang wala ang mga file sa itaas.

Ito ay nagkakahalaga ng pag-highlight sa Delegated driver, dahil kung ito ay ginagamit, tanging ang trabaho na may pagsasaayos ng halimbawa ay inilarawan sa paglikha ng mga halimbawa at pagtanggal ng mga file; ang iba ay dapat na inilarawan ng engineer.

Ang default na driver ay Docker.

Ngayon ay magpatuloy tayo sa pagsasanay at isaalang-alang ang karagdagang mga tampok doon.

Pagsisimula

Bilang isang "hello world" susubukan namin ang isang simpleng papel sa pag-install ng nginx. Piliin natin ang docker bilang driver - sa tingin ko karamihan sa inyo ay na-install na ito (at tandaan na ang docker ay ang default na driver).

Paghandaan natin virtualenv at i-install ito sa loob nito molecule:

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

Ang susunod na hakbang ay ang pagsisimula ng isang bagong tungkulin.
Ang pagsisimula ng isang bagong tungkulin, pati na rin ang isang bagong script, ay isinasagawa gamit ang utos 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

Ang resulta ay isang tipikal na ansible na tungkulin. Dagdag pa, ang lahat ng mga pakikipag-ugnayan sa Molecules CLI ay ginawa mula sa ugat ng papel.

Tingnan natin kung ano ang nasa direktoryo ng tungkulin:

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

1 directory, 6 files

Tingnan natin ang config molecule/default/molecule.yml (papalitan lang namin ang docker image):

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

pagpapasustento

Inilalarawan ng seksyong ito ang pinagmulan ng mga dependency.

Posibleng mga pagpipilian: kalawakan, nalalapat, kabibi.

Ang Shell ay isang command shell lang na gagamitin kung hindi saklaw ng galaxy at gilt ang iyong mga pangangailangan.

Hindi ako magtatagal dito, ito ay sapat na inilarawan sa dokumentasyon.

drayber

Pangalan ng driver. Para sa amin ito ay docker.

linen

Ang Yamllint ay ginagamit bilang isang linter.

Ang mga kapaki-pakinabang na opsyon sa bahaging ito ng config ay ang kakayahang tumukoy ng configuration file para sa yamllint, forward environment variable, o huwag paganahin ang linter:

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

platform

Inilalarawan ang pagsasaayos ng mga pagkakataon.
Sa kaso ng docker bilang driver, ang Molecule ay umuulit sa seksyong ito, at ang bawat elemento ng listahan ay magagamit sa Dockerfile.j2 bilang variable item.

Sa kaso ng isang driver kung saan create.yml и destroy.yml, ang seksyon ay magagamit sa kanila bilang molecule_yml.platforms, at ang mga pag-ulit dito ay inilarawan na sa mga file na ito.

Dahil ang Molecule ay nagbibigay ng instance management sa Ansible modules, dapat mong hanapin ang listahan ng mga posibleng setting doon. Para sa Docker, halimbawa, ang module ay ginagamit docker_container_module. Aling mga module ang ginagamit sa ibang mga driver ay makikita sa dokumentasyon.

Maaari ka ring makahanap ng mga halimbawa ng paggamit ng iba't ibang mga driver sa mga pagsubok ng Molecule mismo.

Palitan natin dito centos:7 sa Ubuntu.

tagapagbigay

Ang "Provider" ay ang entity na namamahala sa mga instance. Sa kaso ng Molecule, ito ay magagawa; ang suporta para sa iba ay hindi binalak, kaya ang seksyong ito ay maaaring, nang may reserbasyon, ay tinatawag na isang pinalawig na pagsasaayos.
Maraming maaari mong ituro dito, ngunit i-highlight ko ang mga pangunahing punto, sa aking opinyon:

  • playbooks: Maaari mong tukuyin kung aling mga playbook ang dapat gamitin sa ilang mga yugto.

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

  • pagpipilian: Ansible na mga parameter at mga variable ng kapaligiran

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

senaryo

Pamagat at paglalarawan ng mga pagkakasunud-sunod ng script.
Maaari mong baguhin ang default na action matrix ng isang command sa pamamagitan ng pagdaragdag ng key <command>_sequence at bilang isang halaga para dito, ang pagtukoy sa listahan ng mga hakbang na kailangan namin.
Sabihin nating gusto nating baguhin ang pagkakasunud-sunod ng mga aksyon kapag pinapatakbo ang playbook run command: molecule converge

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

verifier

Pagse-set up ng isang framework para sa mga pagsubok at isang linter para dito. Bilang default, ginagamit ang linter testinfra и flake8. Ang mga posibleng opsyon ay katulad ng nasa itaas:

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

Balik tayo sa ating tungkulin. I-edit natin ang file tasks/main.yml sa ganitong hitsura:

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

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

At magdagdag ng mga pagsubok sa 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")

Tapos na, ang natitira ay tumakbo (mula sa ugat ng tungkulin, hayaan mong ipaalala ko sa iyo):

> molecule test

Mahabang tambutso sa ilalim ng 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

Ang aming simpleng tungkulin ay sinubukan nang walang problema.
Ito ay nagkakahalaga ng pag-alala na kung ang mga problema ay lumitaw sa panahon ng operasyon molecule test, kung hindi mo binago ang karaniwang sequence, tatanggalin ng Molecule ang instance.

Ang mga sumusunod na command ay kapaki-pakinabang para sa pag-debug:

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

Kasalukuyang tungkulin

Ang pagdaragdag ng bagong script sa isang kasalukuyang tungkulin ay nagaganap mula sa direktoryo ng tungkulin gamit ang mga sumusunod na utos:

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

Kung ito ang unang script sa papel, pagkatapos ay ang parameter -s maaaring tanggalin dahil may gagawing script default.

Konklusyon

Gaya ng nakikita mo, ang Molecule ay hindi masyadong kumplikado, at kapag gumagamit ng sarili mong mga template, maaari mong bawasan ang deployment ng isang bagong script sa pag-edit ng mga variable sa mga playbook para sa paggawa at pagtanggal ng mga pagkakataon. Ang molekula ay walang putol na isinasama sa mga CI system, na nagbibigay-daan sa iyo na palakihin ang bilis ng pag-unlad sa pamamagitan ng pagbawas ng oras para sa manu-manong pagsubok ng mga playbook.

Salamat sa iyong atensyon. Kung mayroon kang karanasan sa pagsubok ng mga ansible na tungkulin, at hindi ito nauugnay sa Molecule, sabihin sa amin ang tungkol dito sa mga komento!

Pinagmulan: www.habr.com

Magdagdag ng komento