Petunjuk: cara menguji peran yang memungkinkan dan mencari tahu tentang masalah sebelum produksi

Hello!

Saya bekerja sebagai insinyur DevOps di layanan pemesanan hotel. Ostrovok.ru. Pada artikel ini, saya ingin berbicara tentang pengalaman kami dalam menguji peran yang memungkinkan.

Di Ostrovok.ru, kami menggunakan ansible sebagai pengelola konfigurasi. Baru-baru ini, kami sampai pada kebutuhan untuk menguji peran, tetapi ternyata, tidak banyak alat untuk ini - yang paling populer, mungkin, adalah kerangka Molekul, jadi kami memutuskan untuk menggunakannya. Tapi ternyata dokumentasinya bungkam tentang banyak jebakan. Kami tidak dapat menemukan manual yang cukup rinci dalam bahasa Rusia, jadi kami memutuskan untuk menulis artikel ini.

Petunjuk: cara menguji peran yang memungkinkan dan mencari tahu tentang masalah sebelum produksi

Molekul

Molekul - kerangka kerja untuk membantu menguji peran yang memungkinkan.

Deskripsi sederhana: Molekul membuat instans pada platform yang Anda tentukan (awan, mesin virtual, wadah; untuk detail lebih lanjut, lihat bagian sopir), jalankan peran Anda di atasnya, lalu jalankan pengujian dan hapus instance. Jika salah satu langkah gagal, Molekul akan memberi tahu Anda tentang hal itu.

Sekarang lebih.

Sedikit teori

Pertimbangkan dua entitas utama Molekul: Skenario dan Penggerak.

Contoh

Naskah berisi uraian tentang apa, di mana, bagaimana, dan dalam urutan apa yang akan dilakukan. Satu peran dapat memiliki beberapa skrip, dan masing-masing merupakan direktori di sepanjang jalur <role>/molecule/<scenario>, yang berisi deskripsi tindakan yang diperlukan untuk pengujian. Skrip harus disertakan default, yang akan dibuat secara otomatis jika Anda menginisialisasi peran dengan Molekul. Nama-nama skrip berikut terserah Anda.

Urutan tindakan pengujian dalam skrip disebut matriks, dan secara default adalah:

(Langkah berlabel ?, dilewati secara default jika tidak ditentukan oleh pengguna)

  • lint - menjalankan linter. Secara default digunakan yamllint и flake8,
  • destroy - menghapus instance dari peluncuran terakhir Molekul (jika ada),
  • dependency? — pemasangan ketergantungan yang mungkin dari peran yang diuji,
  • syntax - memeriksa sintaks peran menggunakan ansible-playbook --syntax-check,
  • create - membuat sebuah contoh,
  • prepare? — persiapan contoh; misalnya periksa/pasang python2
  • converge — peluncuran buku pedoman yang sedang diuji,
  • idempotence - memulai kembali buku pedoman untuk tes idempotensi,
  • side_effect? - tindakan yang tidak terkait langsung dengan peran, tetapi diperlukan untuk tes,
  • verify - menjalankan tes dari konfigurasi yang dihasilkan menggunakan testinfra(bawaan) /goss/inspec,
  • cleanup? - (dalam versi baru) - secara kasar, "membersihkan" infrastruktur eksternal yang dipengaruhi oleh Molekul,
  • destroy - Menghapus sebuah contoh.

Urutan ini mencakup sebagian besar kasus, tetapi dapat diubah jika perlu.

Setiap langkah di atas dapat dijalankan secara terpisah dengan molecule <command>. Tetapi harus dipahami bahwa untuk setiap perintah cli tersebut mungkin ada urutan tindakannya sendiri, yang dapat Anda ketahui dengan mengeksekusi molecule matrix <command>. Misalnya saat menjalankan perintah converge (menjalankan playbook yang sedang diuji), tindakan berikut akan dilakukan:

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

Urutan tindakan ini dapat diedit. Jika sesuatu dari daftar sudah selesai, itu akan dilewati. Status saat ini, serta konfigurasi instance, yang disimpan Molekul di direktori $TMPDIR/molecule/<role>/<scenario>.

Tambahkan langkah dengan ? Anda dapat mendeskripsikan tindakan yang diinginkan dalam format ansible-playbook, dan membuat nama file sesuai dengan langkah tersebut: prepare.yml/side_effect.yml. Harapkan file-file ini Molekul akan berada di folder skrip.

sopir

Driver adalah entitas tempat instance pengujian dibuat.
Daftar driver standar yang Molecule siapkan templatenya adalah sebagai berikut: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

Dalam kebanyakan kasus, templat adalah file create.yml и destroy.yml di folder skrip yang masing-masing menjelaskan pembuatan dan penghapusan instance.
Pengecualiannya adalah Docker dan Vagrant, karena interaksi dengan modulnya dapat terjadi tanpa file yang disebutkan di atas.

Penting untuk menyoroti driver yang Didelegasikan, karena jika digunakan dalam file untuk membuat dan menghapus instance, hanya bekerja dengan konfigurasi instance yang dijelaskan, sisanya harus dijelaskan oleh insinyur.

Driver default adalah Docker.

Sekarang mari beralih ke latihan dan mempertimbangkan fitur lebih lanjut di sana.

Memulai

Sebagai "halo dunia", mari kita uji peran instalasi nginx sederhana. Mari kita pilih docker sebagai driver - saya pikir sebagian besar dari Anda sudah menginstalnya (dan ingat bahwa docker adalah driver default).

Mari bersiap virtualenv dan instal di dalamnya molecule:

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

Langkah selanjutnya adalah menginisialisasi peran baru.
Inisialisasi peran baru, serta skrip baru, dilakukan dengan menggunakan perintah 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

Ternyata peran yang memungkinkan. Selanjutnya, semua interaksi dengan Molekul CLI dibuat dari akar peran.

Mari kita lihat apa yang ada di direktori peran:

> 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 kita menganalisis konfigurasi molecule/default/molecule.yml (ganti hanya gambar buruh pelabuhan):

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

ketergantungan

Bagian ini menjelaskan sumber dependensi.

Opsi yang memungkinkan: galaksi, berlaku, kerang.

Shell hanyalah shell perintah yang digunakan jika galaxy dan gilt tidak memenuhi kebutuhan Anda.

Saya tidak akan tinggal di sini untuk waktu yang lama, cukup dijelaskan dokumentasi.

pengemudi

Nama pengemudi. Kami adalah buruh pelabuhan.

pita

Linternya yamllint.

Opsi yang berguna di bagian konfigurasi ini adalah kemampuan untuk menentukan file konfigurasi untuk yamllint, meneruskan variabel lingkungan, atau menonaktifkan linter:

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

platform

Menjelaskan konfigurasi instance.
Dalam kasus buruh pelabuhan sebagai driver, Molekul diulang pada bagian ini, dan setiap elemen daftar tersedia di Dockerfile.j2 sebagai variabel item.

Dalam kasus driver yang membutuhkan create.yml и destroy.yml, bagian ini tersedia di dalamnya sebagai molecule_yml.platforms, dan perulangannya sudah dijelaskan dalam file-file ini.

Karena Molekul menyediakan kontrol instance ke modul yang memungkinkan, daftar pengaturan yang memungkinkan juga harus dicari di sana. Untuk buruh pelabuhan, misalnya, modul digunakan docker_container_module. Modul mana yang digunakan di driver lain dapat ditemukan di dokumentasi.

Serta contoh penggunaan berbagai driver dapat ditemukan dalam pengujian Molekul itu sendiri.

Ganti di sini cento:7 pada ubuntu.

penyedia

"Pemasok" - entitas yang mengelola instans. Dalam kasus Molekul, ini dimungkinkan, dukungan untuk yang lain tidak direncanakan, jadi bagian ini dapat disebut konfigurasi yang diperluas dengan peringatan.
Di sini Anda dapat mengklarifikasi banyak hal, saya akan menyoroti poin-poin utama, menurut saya:

  • buku pedoman: Anda dapat menentukan playbook mana yang harus digunakan pada tahapan 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 memungkinkan dan variabel lingkungan

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

skenario

Nama dan deskripsi urutan skrip.
Anda dapat mengubah matriks tindakan default dari perintah apa pun dengan menambahkan kunci <command>_sequence dan sebagai nilai untuk itu dengan mendefinisikan daftar langkah-langkah yang kita butuhkan.
Katakanlah kita ingin mengubah urutan tindakan saat menjalankan perintah playbook run: molecule converge

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

verifier

Menyiapkan kerangka kerja untuk pengujian dan linter untuk itu. Linter default adalah testinfra и flake8. Opsi yang mungkin 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 ke peran kita. Mari kita mengedit file tasks/main.yml untuk jenis ini:

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

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

Dan tambahkan tes ke 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, tetap hanya menjalankan (dari akar peran, izinkan saya mengingatkan Anda):

> molecule test

Knalpot 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

Peran sederhana kami diuji tanpa masalah.
Perlu diingat bahwa jika ada masalah selama bekerja molecule test, maka jika Anda tidak mengubah urutan default, Molekul akan menghapus instance.

Perintah berikut berguna untuk debugging:

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

Peran yang Ada

Menambahkan skrip baru ke peran yang ada adalah dari direktori peran dengan perintah berikut:

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

Jika ini adalah skenario pertama dalam peran, maka parameternya -s dapat dihilangkan karena akan membuat skrip default.

Kesimpulan

Seperti yang Anda lihat, Molekul tidak terlalu rumit, dan dengan menggunakan templat Anda sendiri, penerapan skrip baru dapat dikurangi menjadi variabel pengeditan dalam playbook pembuatan dan penghapusan instance. Molekul terintegrasi secara mulus dengan sistem CI, yang memungkinkan Anda meningkatkan kecepatan pengembangan dengan mengurangi waktu untuk pengujian buku panduan secara manual.

Terima kasih atas perhatian Anda. Jika Anda memiliki pengalaman dalam menguji peran yang memungkinkan, dan itu tidak terkait dengan Molekul, beri tahu kami di komentar!

Sumber: www.habr.com

Tambah komentar