Arahan: bagaimana untuk menguji peranan yang boleh dipercayai dan mengetahui masalah sebelum pengeluaran

Hello!

Saya bekerja sebagai jurutera DevOps dalam perkhidmatan tempahan hotel. Ostrovok.ru. Dalam artikel ini, saya ingin bercakap tentang pengalaman kami dalam menguji peranan yang boleh dipercayai.

Di Ostrovok.ru, kami menggunakan ansible sebagai pengurus konfigurasi. Baru-baru ini, kami datang kepada keperluan untuk menguji peranan, tetapi ternyata, tidak begitu banyak alat untuk ini - yang paling popular, mungkin, adalah rangka kerja Molekul, jadi kami memutuskan untuk menggunakannya. Tetapi ternyata dokumentasinya senyap tentang banyak perangkap. Kami tidak dapat mencari manual yang cukup terperinci dalam bahasa Rusia, jadi kami memutuskan untuk menulis artikel ini.

Arahan: bagaimana untuk menguji peranan yang boleh dipercayai dan mengetahui masalah sebelum pengeluaran

Molekul

Molekul - rangka kerja untuk membantu menguji peranan yang boleh dipercayai.

Penerangan ringkas: Molekul mencipta contoh pada platform yang anda tentukan (awan, mesin maya, bekas; untuk butiran lanjut, lihat bahagian Pemandu), menjalankan peranan anda padanya, kemudian menjalankan ujian dan memadamkan contoh. Sekiranya berlaku kegagalan pada salah satu langkah, Molekul akan memberitahu anda mengenainya.

Sekarang lebih lagi.

Sedikit teori

Pertimbangkan dua entiti utama Molekul: Senario dan Pemacu.

senario

Skrip mengandungi penerangan tentang apa, di mana, bagaimana dan dalam urutan apa yang akan dilakukan. Satu peranan boleh mempunyai beberapa skrip, dan setiap satu ialah direktori di sepanjang laluan <role>/molecule/<scenario>, yang mengandungi penerangan tentang tindakan yang diperlukan untuk ujian. Skrip mesti disertakan default, yang akan dibuat secara automatik jika anda memulakan peranan dengan Molekul. Nama skrip berikut terpulang kepada anda.

Urutan tindakan ujian dalam skrip dipanggil matriks, dan secara lalai ialah:

(Langkah dilabel ?, dilangkau secara lalai jika tidak ditentukan oleh pengguna)

  • lint - lari bersepah. Secara lalai digunakan yamllint и flake8,
  • destroy - memadamkan kejadian daripada pelancaran terakhir Molekul (jika ada),
  • dependency? — pemasangan kebergantungan yang boleh diterima oleh peranan yang diuji,
  • syntax - menyemak sintaks peranan menggunakan ansible-playbook --syntax-check,
  • create - mencipta contoh,
  • prepare? — penyediaan contoh; cth. semak/pasang python2
  • converge — pelancaran buku main yang sedang diuji,
  • idempotence - memulakan semula buku permainan untuk ujian mati pucuk,
  • side_effect? - tindakan yang tidak berkaitan secara langsung dengan peranan, tetapi perlu untuk ujian,
  • verify - menjalankan ujian konfigurasi yang terhasil menggunakan testinfra(lalai) /goss/inspec,
  • cleanup? - (dalam versi baharu) - secara kasarnya, "membersihkan" infrastruktur luaran yang terjejas oleh Molekul,
  • destroy - Memadam contoh.

Urutan ini merangkumi kebanyakan kes, tetapi boleh diubah jika perlu.

Setiap langkah di atas boleh dijalankan secara berasingan dengan molecule <command>. Tetapi anda harus faham bahawa untuk setiap perintah cli sedemikian mungkin terdapat urutan tindakannya sendiri, yang boleh anda ketahui dengan melaksanakan molecule matrix <command>. Sebagai contoh, semasa menjalankan arahan converge (menjalankan buku main dalam ujian), tindakan berikut akan dilakukan:

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

Urutan tindakan ini boleh diedit. Jika sesuatu daripada senarai sudah selesai, ia akan dilangkau. Keadaan semasa, serta konfigurasi keadaan, Molekul disimpan dalam direktori $TMPDIR/molecule/<role>/<scenario>.

Tambah langkah dengan ? anda boleh menerangkan tindakan yang diingini dalam format ansible-playbook dan membuat nama fail mengikut langkah: prepare.yml/side_effect.yml. Jangkakan fail ini Molekul akan berada dalam folder skrip.

Pemandu

Pemacu ialah entiti tempat kejadian ujian dibuat.
Senarai pemacu standard yang Molecule mempunyai templat sedia adalah seperti berikut: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

Dalam kebanyakan kes, templat ialah fail create.yml и destroy.yml dalam folder skrip yang masing-masing menerangkan penciptaan dan pemadaman contoh.
Pengecualian adalah Docker dan Vagrant, kerana interaksi dengan modul mereka boleh berlaku tanpa fail yang disebutkan di atas.

Perlu diserlahkan pemacu Diwakilkan, kerana jika ia digunakan dalam fail untuk mencipta dan memadam contoh, hanya berfungsi dengan konfigurasi contoh yang diterangkan, selebihnya harus diterangkan oleh jurutera.

Pemacu lalai ialah Docker.

Sekarang mari kita teruskan untuk berlatih dan pertimbangkan ciri-ciri selanjutnya di sana.

Bermula

Sebagai "hello world", mari kita uji peranan pemasangan nginx yang mudah. Mari pilih docker sebagai pemandu - saya rasa kebanyakan anda telah memasangnya (dan ingat bahawa docker ialah pemandu lalai).

Sediakan virtualenv dan pasang di dalamnya molecule:

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

Langkah seterusnya ialah memulakan peranan baharu.
Permulaan peranan baharu, serta skrip baharu, dilakukan menggunakan arahan 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

Ia ternyata peranan ansible biasa. Selanjutnya, semua interaksi dengan Molekul CLI dibuat daripada akar peranan.

Mari lihat apa yang ada dalam direktori peranan:

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

1 directory, 6 files

Mari analisa konfigurasi molecule/default/molecule.yml (gantikan imej docker sahaja):

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

pergantungan

Bahagian ini menerangkan sumber kebergantungan.

Pilihan yang mungkin: galaksi, boleh digunakan, cangkerang.

Shell hanyalah shell arahan yang digunakan sekiranya galaksi dan gilt tidak memenuhi keperluan anda.

Saya tidak akan tinggal di sini untuk masa yang lama, ia cukup diterangkan dalam dokumentasi.

pemandu

Nama pemandu. Milik kita adalah buruh pelabuhan.

reben

Linter adalah yamllint.

Pilihan berguna dalam bahagian konfigurasi ini ialah keupayaan untuk menentukan fail konfigurasi untuk yamllint, pembolehubah persekitaran ke hadapan, atau melumpuhkan linter:

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

platform

Menerangkan konfigurasi keadaan.
Dalam kes docker sebagai pemacu, Molekul diulang pada bahagian ini, dan setiap elemen senarai tersedia dalam Dockerfile.j2 sebagai pembolehubah item.

Dalam kes pemandu yang memerlukan create.yml и destroy.yml, bahagian itu tersedia di dalamnya sebagai molecule_yml.platforms, dan lelaran di atasnya sudah diterangkan dalam fail ini.

Memandangkan Molekul menyediakan kawalan kejadian kepada modul yang boleh, senarai tetapan yang mungkin juga harus dicari di sana. Untuk buruh pelabuhan, sebagai contoh, modul digunakan docker_container_module. Modul yang digunakan dalam pemacu lain boleh didapati di dokumentasi.

Serta contoh penggunaan pelbagai pemandu boleh didapati dalam ujian Molekul itu sendiri.

Gantikan di sini centos:7 pada ubuntu.

pemberi rezeki

"Pembekal" - entiti yang mengurus kejadian. Dalam kes Molekul, ini boleh dilakukan, sokongan untuk orang lain tidak dirancang, jadi bahagian ini boleh dipanggil konfigurasi lanjutan ansible dengan kaveat.
Di sini anda boleh menentukan banyak perkara, saya akan menyerlahkan perkara utama, pada pendapat saya:

  • playbook: anda boleh menentukan buku permainan yang harus digunakan pada peringkat tertentu.

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

  • pilihan: Pilihan yang boleh dipercayai dan pembolehubah persekitaran

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

senario

Nama dan huraian urutan skrip.
Anda boleh menukar matriks tindakan lalai bagi mana-mana arahan dengan menambah kunci <command>_sequence dan sebagai nilai untuknya dengan menentukan senarai langkah yang kita perlukan.
Katakan kita mahu menukar urutan tindakan semasa menjalankan arahan run playbook: molecule converge

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

pengesah

Sediakan rangka kerja untuk ujian dan linter kepadanya. Linter lalai ialah testinfra и flake8. Pilihan yang mungkin adalah sama seperti di atas:

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

Mari kita kembali kepada peranan kita. Mari edit fail tasks/main.yml kepada jenis ini:

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

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

Dan tambahkan ujian kepada 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")

Selesai, ia kekal hanya untuk dijalankan (dari akar peranan, izinkan saya mengingatkan anda):

> molecule test

Ekzos panjang di bawah 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

Peranan mudah kami diuji tanpa masalah.
Perlu diingat bahawa jika terdapat masalah semasa kerja molecule test, maka, jika anda tidak menukar jujukan lalai, Molekul akan memadamkan kejadian itu.

Perintah berikut berguna untuk penyahpepijatan:

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

Peranan Sedia Ada

Menambah skrip baharu pada peranan sedia ada ialah daripada direktori peranan dengan arahan berikut:

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

Sekiranya ini adalah senario pertama dalam peranan, maka parameter -s boleh ditinggalkan kerana ia akan mencipta skrip default.

Kesimpulan

Seperti yang anda lihat, Molekul tidak begitu rumit, dan dengan menggunakan templat anda sendiri, menggunakan skrip baharu boleh dikurangkan kepada menyunting pembolehubah dalam penciptaan contoh dan buku permainan pemadaman. Molekul ini terintegrasi dengan lancar dengan sistem CI, yang membolehkan anda meningkatkan kelajuan pembangunan dengan mengurangkan masa untuk ujian manual buku permainan.

Terima kasih kerana memberi perhatian. Jika anda mempunyai pengalaman dalam menguji peranan yang boleh dipercayai, dan ia tidak berkaitan dengan Molekul, beritahu kami mengenainya dalam ulasan!

Sumber: www.habr.com

Tambah komen