Instruksi: cara menguji peran yang dimungkinkan dan mencari tahu tentang masalah sebelum produksi

Halo semuanya!


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


Di Ostrovok.ru, kami menggunakan ansible sebagai manajer konfigurasi. Kami baru-baru ini datang dengan kebutuhan untuk menguji peran, tetapi ternyata, tidak ada banyak alat untuk ini - kerangka kerja Molekul mungkin yang paling populer, jadi kami memutuskan untuk menggunakannya. Tetapi ternyata dokumentasinya diam tentang banyak jebakan. Kami tidak dapat menemukan panduan yang cukup rinci dalam bahasa Rusia, jadi kami memutuskan untuk menulis artikel ini.



Molekul


Molekul - kerangka kerja untuk membantu menguji peran yang mungkin.


Deskripsi yang disederhanakan: Molekul membuat sebuah instance pada platform yang Anda tentukan (cloud, mesin virtual, wadah; untuk lebih jelasnya, lihat bagian Driver ), jalankan peran Anda di atasnya, kemudian jalankan tes dan hapus instance. Dalam hal kegagalan pada salah satu langkah, Molekul akan memberi tahu Anda tentang hal ini.


Sekarang lebih detail.


Sedikit teori


Pertimbangkan dua entitas kunci Molekul: Skenario dan Pengemudi.


Skenario


Script berisi deskripsi tentang apa, di mana, bagaimana, dan dalam urutan apa yang akan dilakukan. Satu peran dapat memiliki beberapa skrip, dan masing-masing adalah direktori di sepanjang jalur <role>/molecule/<scenario> , yang berisi deskripsi tindakan yang diperlukan untuk pengujian. Skrip default harus ada, yang akan dibuat secara otomatis jika Anda menginisialisasi peran menggunakan Molekul. Nama-nama skenario berikut ini dipilih atas kebijakan Anda.


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


(Langkah ditandai dengan ? Dilewati secara default jika tidak dijelaskan oleh pengguna)


  • lint - run linter. Secara default, yamllint dan flake8 ,
  • destroy - menghapus instance dari peluncuran Molekul terakhir (jika dibiarkan),
  • dependency ? - pemasangan dependensi yang dimungkinkan dari peran yang diuji,
  • syntax - periksa sintaks peran menggunakan ansible-playbook --syntax-check ,
  • create - buat sebuah instance,
  • prepare ? - persiapan instance; mis. memeriksa / menginstal python2
  • converge - peluncuran playbook yang diuji,
  • idempotence - restart playbook untuk tes idempotency,
  • side_effect ? - tindakan yang tidak terkait langsung dengan peran, tetapi diperlukan untuk pengujian,
  • verify - jalankan tes dari konfigurasi yang dihasilkan menggunakan testinfra (default) / goss / inspec ,
  • cleanup ? - (dalam versi baru) - secara kasar, "pembersihan" infrastruktur eksternal yang dipengaruhi oleh Molekul,
  • destroy - menghapus sebuah instance.

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


Setiap langkah di atas dapat dijalankan secara terpisah menggunakan molecule <command> . Tetapi bermanfaat untuk memahami bahwa untuk setiap cli-command tersebut mungkin ada urutan tindakannya sendiri, yang dapat dikenali dengan mengeksekusi molecule matrix <command> . Misalnya, ketika Anda menjalankan perintah converge (menjalankan buku pedoman yang diuji), tindakan berikut akan dilakukan:


 $ molecule matrix converge ... └── default #   ├── dependency #   ├── create #   ├── prepare #   └── converge #   

Urutan tindakan ini dapat diedit. Jika sesuatu dari daftar telah selesai, maka akan dilewati. Keadaan saat ini, serta konfigurasi instance, disimpan dalam direktori $TMPDIR/molecule/<role>/<scenario> .


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


Supir


Driver adalah suatu entitas tempat instance uji dibuat.
Daftar driver standar yang siap digunakan Molecule adalah sebagai berikut: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.


Dalam kebanyakan kasus, templat adalah file create.yml dan create.yml di folder skrip yang masing-masing menggambarkan pembuatan dan penghapusan instance.
Pengecualian adalah Docker dan Vagrant, karena interaksi dengan modul mereka dapat terjadi tanpa file di atas.


Layak menyoroti driver Delegated, 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 kita beralih ke latihan dan mempertimbangkan fitur lebih lanjut di sana.


Memulai


Sebagai "hello world", kami menguji peran sederhana menginstal nginx. Kami akan memilih buruh pelabuhan sebagai driver - saya pikir itu diinstal pada sebagian besar dari Anda (dan ingat bahwa buruh pelabuhan adalah driver default).


Siapkan virtualenv dan pasang molecule di dalamnya:


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

Hasilnya adalah peran yang memungkinkan. Lebih lanjut, 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 (kami hanya akan mengganti 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 , gilt , shell.


Shell hanyalah shell perintah yang digunakan jika galaksi dan emas tidak memenuhi kebutuhan Anda.


Saya tidak akan berhenti di sini untuk waktu yang lama, itu sudah dijelaskan dalam dokumentasi .


pengemudi


Nama pengemudi. Kami memiliki buruh pelabuhan ini.


serat


Sebagai linter, yamllint digunakan.


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 diulangi di atas bagian ini, dan setiap item daftar tersedia di Dockerfile.j2 sebagai variabel item .


Dalam kasus driver, di mana create.yml dan create.yml destroy.yml , bagian tersedia di dalamnya sebagai molecule_yml.platforms , dan iterasi di atasnya sudah dijelaskan dalam file-file ini.


Karena Molekul menyediakan kontrol instan untuk modul yang mungkin, daftar pengaturan yang mungkin harus dicari di sana. Untuk buruh pelabuhan, misalnya, modul docker_container_module digunakan . Modul mana yang digunakan pada driver lain dapat ditemukan dalam dokumentasi .


Dan juga contoh penggunaan berbagai driver dapat ditemukan dalam tes Molekul itu sendiri .


Ganti centos: 7 di ubuntu di sini .


pembuat ketentuan


"Penyedia" adalah entitas yang mengendalikan mesin virtual. Dalam kasus Molekul, ini dimungkinkan, dukungan untuk orang lain tidak direncanakan, sehingga bagian ini dapat dipanggil dengan reservasi konfigurasi lanjutan dari ansible.
Di sini Anda dapat menentukan banyak hal, saya akan menyoroti utama, menurut pendapat saya, momen:


  • playbooks : 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 

  • connection_options : parameter koneksi

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

  • opsi : Opsi opsi 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 suatu <command>_sequence menambahkan <command>_sequence dan menentukan daftar langkah-langkah yang kita butuhkan sebagai nilai untuknya.
Misalkan kita ingin mengubah urutan tindakan saat menjalankan perintah jalankan playbook: molecule converge


 # : # - dependency # - create # - prepare # - converge scenario: name: default converge_sequence: - create - converge 

pemverifikasi


Menyiapkan kerangka kerja untuk tes dan linter untuk itu. Secara default, testinfra dan flake8 digunakan testinfra flake8 . Opsi yang mungkin mirip dengan yang 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. Edit file tasks/main.yml agar terlihat seperti 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 berjalan saja (dari akar peran, saya ingatkan 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 pengoperasian molecule test , maka jika Anda tidak mengubah urutan standar, Molekul akan menghapus instance.


Perintah-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 terjadi dari direktori peran dengan perintah berikut:


 #     > molecule init scenarion --help #    > molecule init scenario -r <role_name> -s <scenario_name> 

Dalam hal ini adalah skrip pertama dalam peran, -s dapat dihilangkan karena skrip default akan dibuat.


Kesimpulan


Seperti yang Anda lihat, Molekul tidak terlalu rumit, dan saat menggunakan templat Anda sendiri, Anda dapat mengurangi penyebaran skrip baru ke mengedit variabel dalam buku pedoman untuk membuat dan menghapus instance. Molekul terintegrasi dengan sistem CI, yang memungkinkan Anda untuk meningkatkan kecepatan pengembangan dengan mengurangi waktu yang dibutuhkan untuk secara manual menguji buku pedoman.


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

Source: https://habr.com/ru/post/id448136/


All Articles