Talimatlar: üretim öncesinde yanıtlayıcı rollerin nasıl test edileceği ve sorunların nasıl öğrenileceği

Herkese Merhaba!

Bir otel rezervasyon hizmetinde DevOps mühendisi olarak çalışıyorum. Ostrovok.ru. Bu yazımda yanıtlayıcı rolleri test etme deneyimimizden bahsetmek istiyorum.

Ostrovok.ru'da ansible'ı konfigürasyon yöneticisi olarak kullanıyoruz. Son zamanlarda rolleri test etme ihtiyacı duyduk, ancak bunun için çok fazla araç olmadığı ortaya çıktı - belki de en popüler olanı Molecule çerçevesidir, bu yüzden onu kullanmaya karar verdik. Ancak belgelerinin birçok tuzak konusunda sessiz kaldığı ortaya çıktı. Rusça'da yeterince ayrıntılı bir kılavuz bulamadık, bu yüzden bu makaleyi yazmaya karar verdik.

Talimatlar: üretim öncesinde yanıtlayıcı rollerin nasıl test edileceği ve sorunların nasıl öğrenileceği

molekül

molekül - yanıtlanabilir rolleri test etmeye yardımcı olacak bir çerçeve.

Basitleştirilmiş açıklama: Molekül, belirttiğiniz platformda (bulut, sanal makine, konteyner) bir örnek oluşturur; daha fazla ayrıntı için bölüme bakın Sürücü), rolünüzü üzerinde çalıştırır, ardından testleri çalıştırır ve örneği siler. Adımlardan birinde başarısızlık olması durumunda Molecule sizi bu konuda bilgilendirecektir.

Şimdi ayrıntıları.

Biraz teori

Molekülün iki temel varlığını düşünün: Senaryo ve Sürücü.

senaryo

Komut dosyası neyin, nerede, nasıl ve hangi sırayla gerçekleştirileceğine ilişkin bir açıklama içerir. Bir rolün birden fazla komut dosyası olabilir ve her biri yol boyunca bir dizindir <role>/molecule/<scenario>Test için gerekli eylemlerin açıklamalarını içeren. Senaryo dahil edilmelidir defaultRolü bir Molecule ile başlatırsanız otomatik olarak oluşturulur. Aşağıdaki scriptlerin isimleri size kalmış.

Bir komut dosyasındaki test eylemleri dizisine denir matrisve varsayılan olarak şöyledir:

(Etiketli adımlar ?, kullanıcı tarafından belirtilmemişse varsayılan olarak atlanır)

  • lint - linter'ları çalıştırıyorum. Varsayılan olarak kullanılır yamllint и flake8,
  • destroy - Molekülün son başlatılmasından (varsa) örneklerin silinmesi,
  • dependency? — test edilen rolün yanıtlanabilir bağımlılığının kurulumu,
  • syntax - kullanarak rolün sözdizimini kontrol etmek ansible-playbook --syntax-check,
  • create - bir örnek oluşturmak,
  • prepare? - örneğin hazırlanması; örneğin python2'yi kontrol edin/kurun
  • converge — test edilen başucu kitabının başlatılması,
  • idempotence - yetersizlik testi için oyun kitabının yeniden başlatılması,
  • side_effect? - rolle doğrudan ilgili olmayan ancak testler için gerekli olan eylemler,
  • verify - kullanarak ortaya çıkan konfigürasyonun testlerini çalıştırmak testinfra(varsayılan) /goss/inspec,
  • cleanup? - (yeni versiyonlarda) - kabaca söylemek gerekirse, Molecule'den etkilenen dış altyapının "temizlenmesi",
  • destroy - Bir örneğin silinmesi.

Bu sıra çoğu durumu kapsar ancak gerekirse değiştirilebilir.

Yukarıdaki adımların her biri ayrı ayrı çalıştırılabilir. molecule <command>. Ancak, bu tür her bir komut için kendi eylem dizisinin olabileceği ve bunu çalıştırarak öğrenebileceğiniz anlaşılmalıdır. molecule matrix <command>. Örneğin, komutu çalıştırırken converge (başucu kitabını test altında çalıştırarak), aşağıdaki eylemler gerçekleştirilecektir:

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

Bu eylemlerin sırası düzenlenebilir. Listedeki bir şey zaten yapılmışsa atlanacaktır. Molecule, örneklerin yapılandırmasının yanı sıra mevcut durumu da dizinde saklar $TMPDIR/molecule/<role>/<scenario>.

Şununla adım ekle: ? istediğiniz eylemleri ansible-playbook formatında tanımlayabilir ve dosya adını aşağıdaki adıma göre yapabilirsiniz: prepare.yml/side_effect.yml. Bu dosyaları bekleyin. Molekül, komut dosyası klasöründe olacaktır.

Sürücü

Sürücü, test örneklerinin oluşturulduğu bir varlıktır.
Molecule'ün hazır şablonlara sahip olduğu standart sürücülerin listesi şu şekildedir: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

Çoğu durumda şablonlar dosyalardır create.yml и destroy.yml sırasıyla bir örneğin oluşturulmasını ve silinmesini açıklayan komut dosyası klasöründe.
Docker ve Vagrant istisnadır, çünkü modülleriyle etkileşim yukarıda belirtilen dosyalar olmadan da gerçekleşebilir.

Yetkilendirilmiş sürücüyü vurgulamakta fayda var, çünkü dosyalarda bir örneği oluşturmak ve silmek için kullanılıyorsa, yalnızca örneklerin yapılandırmasıyla çalışma açıklanır, geri kalanı mühendis tarafından açıklanmalıdır.

Varsayılan sürücü Docker'dır.

Şimdi uygulamaya geçelim ve oradaki diğer özellikleri ele alalım.

Başlarken

"Merhaba dünya" olarak basit bir nginx kurulum rolünü test edelim. Sürücü olarak docker'ı seçelim - çoğunuzun bunu yüklediğini düşünüyorum (ve docker'ın varsayılan sürücü olduğunu unutmayın).

Hazırlamak virtualenv ve içine yükleyin molecule:

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

Bir sonraki adım yeni rolü başlatmaktır.
Yeni bir rolün ve yeni bir betiğin başlatılması şu komut kullanılarak gerçekleştirilir: 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

Tipik bir yanıtlayıcı rolü ortaya çıktı. Ayrıca CLI Molekülleriyle olan tüm etkileşimler rolün kökünden yapılır.

Rol dizininde neler olduğunu görelim:

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

1 directory, 6 files

Yapılandırmayı analiz edelim molecule/default/molecule.yml (yalnızca liman işçisi görüntüsünü değiştirin):

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

bağımlılık

Bu bölümde bağımlılıkların kaynağı açıklanmaktadır.

Seçenekler şunlardır: galaksi, geçerlidir, kabuk.

Kabuk, galaksinin ve yaldızın ihtiyaçlarınızı karşılamaması durumunda kullanılan bir komut kabuğudur.

Burada uzun süre kalmayacağım, burada yeterince anlatıldı. belgeleme.

sürücü

Sürücünün adı. Bizimki liman işçisi.

keten tiftiği

Linter yamllint'tir.

Yapılandırmanın bu bölümündeki yararlı seçenekler, yamllint için bir yapılandırma dosyası belirtme, ortam değişkenlerini iletme veya linter'ı devre dışı bırakma yeteneğidir:

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

platformları

Örneklerin yapılandırmasını açıklar.
Docker'ın sürücü olması durumunda, Molekül bu bölüm üzerinde yinelenir ve listedeki her öğe şu adreste bulunur: Dockerfile.j2 değişken olarak item.

gerektiren bir sürücü durumunda create.yml и destroy.yml, bölüm içlerinde şu şekilde mevcuttur: molecule_yml.platformsve bunun üzerindeki yinelemeler bu dosyalarda zaten açıklanmıştır.

Molecule, ansible modüllerine örneklerin kontrolünü sağladığından, olası ayarların listesine de burada bakılmalıdır. Örneğin liman işçisi için modül kullanılır docker_container_module. Diğer sürücülerde hangi modüllerin kullanıldığı şurada bulunabilir: belgeleme.

Ayrıca çeşitli sürücülerin kullanımına ilişkin örnekler de bulunabilir. Molekülün kendi testlerinde.

Burayı değiştirin centos:7 üzerinde ubuntu.

sağlayıcı

"Tedarikçi" - örnekleri yöneten bir varlık. Molecule söz konusu olduğunda bu yanıtlanabilirdir, başkalarına destek planlanmamıştır, bu nedenle bu bölüme bir uyarı ile yanıtlanabilir genişletilmiş yapılandırma denilebilir.
Burada birçok şeyi belirtebilirsiniz, bence ana noktaları vurgulayacağım:

  • oyun kitapları: Belirli aşamalarda hangi oyun kitaplarının kullanılması gerektiğini belirleyebilirsiniz.

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

  • seçenekleri: Ansible seçenekleri ve ortam değişkenleri

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

senaryo

Komut dizilerinin adı ve açıklaması.
Anahtarı ekleyerek herhangi bir komutun varsayılan eylem matrisini değiştirebilirsiniz. <command>_sequence ve ihtiyacımız olan adımların listesini tanımlayarak bunun için bir değer olarak.
Diyelim ki playbook run komutunu çalıştırırken eylemlerin sırasını değiştirmek istiyoruz: molecule converge

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

doğrulayıcı

Testler için bir çerçeve ve buna bir linter oluşturmak. Varsayılan linter testinfra и flake8. Olası seçenekler yukarıdakilerle aynıdır:

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

Rolümüze dönelim. Dosyayı düzenleyelim tasks/main.yml bu türe:

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

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

Ve testleri ekleyin 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")

Bitti, geriye sadece koşmak kalıyor (rolün kökünden size hatırlatmama izin verin):

> molecule test

Spoylerin altındaki uzun egzoz:

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

Basit rolümüz sorunsuz bir şekilde test edildi.
Çalışma sırasında sorunlar yaşanırsa şunu hatırlamakta fayda var molecule test, eğer varsayılan sırayı değiştirmediyseniz Molecule örneği silecektir.

Aşağıdaki komutlar hata ayıklama için kullanışlıdır:

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

Mevcut Rol

Mevcut bir role yeni bir komut dosyası eklemek rol dizininden aşağıdaki komutlarla:

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

Bunun roldeki ilk senaryo olması durumunda parametre -s bir komut dosyası oluşturacağından ihmal edilebilir default.

Sonuç

Gördüğünüz gibi Molekül çok karmaşık değildir ve kendi şablonlarınızı kullanarak yeni bir komut dosyası dağıtmak, örnek oluşturma ve çalışma kitaplarındaki değişkenleri düzenlemeye indirgenebilir. Molekül, CI sistemleriyle sorunsuz bir şekilde bütünleşir; bu, taktik kitapların manuel olarak test edilmesi süresini azaltarak geliştirme hızını artırmanıza olanak tanır.

İlginiz için teşekkür ederiz. Yanıtlayıcı rolleri test etme konusunda deneyiminiz varsa ve bu Molekül ile ilgili değilse, yorumlarda bize bundan bahsedin!

Kaynak: habr.com

Yorum ekle