Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

To jest transkrypcja występy na DevOps-40 2020:

Począwszy od drugiego zatwierdzenia, każdy kod staje się starszy, ponieważ Początkowe pomysły zaczynają odbiegać od twardej rzeczywistości. Nie jest to ani dobre, ani złe, jest to fakt, z którym trudno polemizować i z którym należy żyć. Częścią tego procesu jest refaktoryzacja. Refaktoryzacja infrastruktury jako kodu. Zacznijmy od historii o tym, jak dokonać refaktoryzacji Ansible w ciągu roku i nie zwariować.

Narodziny dziedzictwa

Dzień nr 1: Pacjent Zero

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Dawno, dawno temu istniał projekt warunkowy. Miał zespół programistów Dev i inżynierów operacyjnych. Rozwiązywali ten sam problem: jak wdrożyć serwery i uruchomić aplikację. Problem w tym, że każdy zespół rozwiązał ten problem na swój sposób. W projekcie zdecydowano się wykorzystać Ansible do synchronizacji wiedzy pomiędzy zespołami Dev i Ops.

Dzień #89: Narodziny dziedzictwa

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Sami tego nie zauważając, chcieli to zrobić jak najlepiej, ale okazało się, że to już dziedzictwo. Jak to się stało?

  • Mamy tutaj pilne zadanie, zróbmy brudny hack, a potem go naprawmy.
  • Nie musisz pisać dokumentacji i wszystko jest jasne, co się tutaj dzieje.
  • Znam Ansible/Python/Bash/Terraform! Zobacz, jak potrafię robić uniki!
  • Jestem programistą Full Stack Overflow i skopiowałem to z stackoverflow, nie wiem, jak to działa, ale wygląda fajnie i rozwiązuje problem.

W rezultacie można otrzymać niezrozumiały typ kodu, dla którego nie ma dokumentacji, nie jest jasne, co on robi, czy jest potrzebny, ale problem jest taki, że trzeba go rozwinąć, zmodyfikować, dodać kule i podpory , co jeszcze bardziej pogarsza sytuację.

- hosts: localhost
  tasks:
    - shell: echo -n Z >> a.txt && cat a.txt
      register: output
      delay: 1
      retries: 5
      until: not output.stdout.find("ZZZ")

Dzień #109: Świadomość problemu

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Pierwotnie wymyślony i wdrożony model IaC nie spełnia już wymagań użytkowników/biznesu/innych zespołów, a czas na wprowadzanie zmian w infrastrukturze przestaje być akceptowalny. W tym momencie przychodzi zrozumienie, że nadszedł czas, aby podjąć działania.

Refaktoryzacja IaC

Dzień #139: Czy naprawdę potrzebujesz refaktoryzacji?

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Zanim przystąpisz do refaktoryzacji, musisz odpowiedzieć na kilka ważnych pytań:

  1. Dlaczego potrzebujesz tego wszystkiego?
  2. Czy masz czas?
  3. Czy wiedza wystarczy?

Jeśli nie wiesz, jak odpowiedzieć na pytania, refaktoryzacja zakończy się, zanim w ogóle się rozpocznie, lub może się tylko pogorszyć. Ponieważ miał doświadczenie ( Czego nauczyłem się testując 200 000 linii kodu infrastruktury), wówczas projekt otrzymał prośbę o pomoc w naprawieniu ról i objęciu ich testami.

Dzień #149: Przygotowanie refaktoryzacji

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Pierwszą rzeczą jest przygotowanie. Zdecyduj, co zrobimy. W tym celu komunikujemy się, znajdujemy obszary problematyczne i znajdujemy sposoby ich rozwiązania. Powstałe koncepcje w jakiś sposób rejestrujemy, np. artykuł w konfluencji, aby w przypadku pojawienia się pytania „co jest najlepsze?” lub „co jest poprawne?” Nie zgubiliśmy drogi. W naszym przypadku trzymaliśmy się pomysłu dziel i rządź: dzielimy infrastrukturę na małe kawałki/cegiełki. Takie podejście pozwala wziąć wyizolowany fragment infrastruktury, zrozumieć, co robi, objąć go testami i zmienić bez obawy, że cokolwiek zepsuje.

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Okazuje się, że podstawą jest testowanie infrastruktury i w tym miejscu warto wspomnieć o piramidzie testowania infrastruktury. Dokładnie ten sam pomysł, który jest w fazie rozwoju, ale w przypadku infrastruktury: odchodzimy od tanich szybkich testów, które sprawdzają proste rzeczy, takie jak wcięcia, na rzecz drogich, pełnoprawnych testów, które wdrażają całą infrastrukturę.

Próby testowania Ansible

Zanim przejdę do opisania jak przeszliśmy testy Ansible w projekcie, opiszę próby i podejścia, które miałem okazję wcześniej zastosować, aby zrozumieć kontekst podjętych decyzji.

Dzień nr -997: Dostarczenie karty charakterystyki

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Po raz pierwszy testowałem Ansible podczas projektu mającego na celu opracowanie SDS (Software Defined Storage). Jest na ten temat osobny artykuł
Jak rozbijać rowery o kule podczas testowania dystrybucji, ale w skrócie skończyło się na odwróconej piramidzie testowania i testowaniu spędziliśmy 60-90 minut na jednej roli, czyli dużo czasu. Podstawą były testy e2e, czyli tzw. wdrożyliśmy pełną instalację, a następnie ją przetestowaliśmy. Jeszcze bardziej irytujące było wynalezienie własnego roweru. Ale muszę przyznać, że to rozwiązanie zadziałało i pozwoliło na stabilne wydanie.

Dzień # -701: Ansible i kuchnia testowa

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Rozwinięciem idei testowania Ansible było wykorzystanie gotowych narzędzi, a mianowicie test Kitchen/ Kitchen-ci oraz inspec. O wyborze zadecydowała znajomość Ruby (więcej szczegółów w artykule o Habré: Czy programiści YML marzą o testowaniu Ansible?) pracowało szybciej, około 40 minut na 10 ról. Stworzyliśmy paczkę maszyn wirtualnych i przeprowadziliśmy w niej testy.

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Ogólnie rzecz biorąc, roztwór działał, ale ze względu na niejednorodność występowały pewne osady. Kiedy liczbę testowanych osób zwiększono do 13 ról podstawowych i 2 meta ról łączących mniejsze role, nagle testy zaczęły trwać 70 minut, czyli prawie 2 razy dłużej. Trudno było mówić o praktykach XP (programowania ekstremalnego), ponieważ… nikt nie chce czekać 70 minut. To był powód zmiany podejścia

Dzień # -601: Ansible i molekuła

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Koncepcyjnie jest to podobne do testkitchen, tyle że przenieśliśmy testowanie ról do okna dokowanego i zmieniliśmy stos. W rezultacie czas został skrócony do stabilnych 20-25 minut dla 7 ról.

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Zwiększając liczbę testowanych ról do 17 i ustawiając 45 ról, uruchomiliśmy to w 28 minut na 2 niewolnikach Jenkinsa.

Dzień #167: Dodawanie testów Ansible do projektu

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Najprawdopodobniej nie będzie możliwe wykonanie zadania refaktoryzacji w pośpiechu. Zadanie musi być mierzalne, abyś mógł je rozbić na małe kawałki i zjadać słonia kawałek po kawałku łyżeczką. Konieczne jest zrozumienie, czy zmierzasz we właściwym kierunku i ile czasu Ci to zajmie.

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Generalnie nie ma znaczenia jak to zostanie zrobione, możesz napisać na kartce papieru, możesz przykleić naklejki na szafę, możesz tworzyć zadania w Jira, albo możesz otworzyć Dokumenty Google i spisać aktualny stan Tam. Nogi rosną od tego, że proces nie jest natychmiastowy, będzie długi i żmudny. Jest mało prawdopodobne, aby ktokolwiek chciał, abyś podczas refaktoryzacji wypalił się, zmęczył i poczuł się przytłoczony.

Refaktoryzacja jest prosta:

  • Jeść.
  • Spać.
  • Kod.
  • Test IAC.
  • powtarzać

i powtarzamy to aż do osiągnięcia zamierzonego celu.

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Być może nie da się od razu rozpocząć testowania wszystkiego, więc naszym pierwszym zadaniem było zacząć od lintingu i sprawdzenia składni.

Dzień #181: Mistrz zielonego budowania

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Linting to mały pierwszy krok w kierunku Green Build Master. Nie zepsuje to prawie niczego, ale pozwoli ci debugować procesy i tworzyć zielone kompilacje w Jenkins. Ideą jest wyrobienie w zespole nawyków:

  • Czerwone testy są złe.
  • Przyszedłem coś naprawić i jednocześnie sprawić, że kod będzie trochę lepszy niż był przed tobą.

Dzień #193: Od lintingu do testów jednostkowych

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Po zbudowaniu procesu wprowadzania kodu do mastera można rozpocząć proces stopniowego doskonalenia - zastępując linting rolami uruchamiającymi, można to zrobić nawet bez idempotencji. Musisz zrozumieć, jak stosować role i jak one działają.

Dzień #211: Od testów jednostkowych do integracyjnych

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Kiedy większość ról jest objęta testami jednostkowymi i wszystko jest zaśmiecone, możesz przejść do dodawania testów integracyjnych. Te. testowanie nie pojedynczej cegły w infrastrukturze, ale ich kombinacji, np. pełnej konfiguracji instancji.

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Używając Jenkinsa, wygenerowaliśmy wiele etapów, które równolegle łączyły role/podręczniki, następnie testy jednostkowe w kontenerach, a na koniec testy integracyjne.

Jenkins + Docker + Ansible = Testy

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

  1. Sprawdź repozytorium i wygeneruj etapy kompilacji.
  2. Uruchom równolegle etapy podręcznika Lint.
  3. Uruchom równolegle etapy roli lint.
  4. Uruchom równolegle etapy roli sprawdzania składni.
  5. Uruchom równolegle etapy roli testowej.
    1. Rola kłaczków.
    2. Sprawdź zależność od innych ról.
    3. Sprawdź składnię.
    4. Utwórz instancję dokera
    5. Uruchom molekułę/default/playbook.yml.
    6. Sprawdź idempotencję.
  6. Uruchom testy integracyjne
  7. koniec

Dzień #271: Faktor autobusowy

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Początkowo refaktoryzację przeprowadzała niewielka grupa dwóch lub trzech osób. Przejrzeli kod w masterze. Z biegiem czasu zespół rozwinął wiedzę na temat pisania kodu, a jego recenzja przyczyniła się do upowszechnienia wiedzy o infrastrukturze i sposobie jej działania. Najważniejszym wydarzeniem było to, że recenzenci byli wybierani pojedynczo, według harmonogramu, tj. z pewnym prawdopodobieństwem wejdziesz na nowy element infrastruktury.

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

I tutaj powinno być wygodnie. Wygodnie jest zrobić przegląd, zobaczyć w ramach jakiego zadania zostało wykonane i historię dyskusji. Zintegrowaliśmy jenkins + bitbucket + jira.

Ale jako taka recenzja nie jest panaceum; w jakiś sposób dotarliśmy do kodu głównego, co spowodowało, że testy wypadły na flopie:

- get_url:
    url: "{{ actk_certs }}/{{ item.1 }}"
    dest: "{{ actk_src_tmp }}/"
    username: "{{ actk_mvn_user }}"
    password: "{{ actk_mvn_pass }}"
  with_subelements:
    - "{{ actk_cert_list }}"
    - "{{ actk_certs }}"
  delegate_to: localhost

- copy:
    src: "{{ actk_src_tmp }}/{{ item.1 }}"
    dest: "{{ actk_dst_tmp }}"
  with_subelements:
    - "{{ actk_cert_list }}"
    - "{{ actk_certs }}"

Potem to naprawili, ale osad pozostał.

get_url:
    url: "{{ actk_certs }}/{{ actk_item }}"
    dest: "{{ actk_src_tmp }}/{{ actk_item }}"
    username: "{{ actk_mvn_user }}"
    password: "{{ actk_mvn_pass }}"
  loop_control:
    loop_var: actk_item
  with_items: "{{ actk_cert_list }}"
  delegate_to: localhost

- copy:
    src: "{{ actk_src_tmp }}/{{ actk_item }}"
    dest: "{{ actk_dst_tmp }}"
  loop_control:
    loop_var: actk_item
  with_items: "{{ actk_cert_list }}"

Dzień #311: Przyspieszanie testów

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Z biegiem czasu testów było coraz więcej, kompilacje działały wolniej, w najgorszym przypadku do godziny. Na jednym z retro było zdanie w stylu „dobrze, że są testy, ale są powolne”. W rezultacie porzuciliśmy testy integracyjne na maszynach wirtualnych i dostosowaliśmy je do Dockera, aby było to szybsze. Zastąpiliśmy także testinfra weryfikatorem ansible, aby zmniejszyć liczbę używanych narzędzi.

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Ściśle mówiąc, istniał zestaw środków:

  1. Przejdź do okna dokowanego.
  2. Usuń testowanie ról, które jest zduplikowane ze względu na zależności.
  3. Zwiększ liczbę niewolników.
  4. Kolejność uruchomienia testowego.
  5. Możliwość linczowania WSZYSTKO lokalnie za pomocą jednego polecenia.

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

W rezultacie ujednolicono także Pipeline na Jenkinsie

  1. Generuj etapy kompilacji.
  2. Lint wszystko równolegle.
  3. Uruchom równolegle etapy roli testowej.
  4. Zakończ.

Wyciągnięte wnioski

Unikaj zmiennych globalnych

Ansible używa zmiennych globalnych, w formularzu istnieje częściowe obejście private_role_vars, ale to nie jest panaceum.

Dam ci przykład. Pozwól nam role_a и role_b

# cat role_a/defaults/main.yml
---
msg: a

# cat role_a/tasks/main.yml
---
- debug:
    msg: role_a={{ msg }}

# cat role_b/defaults/main.yml
---
msg: b

# cat role_b/tasks/main.yml
---
- set_fact:
    msg: b
- debug:
    msg: role_b={{ msg }}

- hosts: localhost
  vars:
    msg: hello
  roles:
    - role: role_a
    - role: role_b
  tasks:
    - debug:
        msg: play={{msg}}

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Zabawne jest to, że wynik podręczników będzie zależał od rzeczy, które nie zawsze są oczywiste, takich jak kolejność wymieniania ról. Taka jest niestety natura Ansible i najlepsze co można zrobić to zastosować jakąś umowę, np. w ramach roli używać tylko zmiennej opisanej w tej roli.

BAD: użyj zmiennej globalnej.

# cat roles/some_role/tasks/main.yml
---
debug:
  var: java_home

DOBRY: V defaults zdefiniuj niezbędne zmienne i później używaj tylko nich.

# cat roles/some_role/defaults/main.yml
---
r__java_home:
 "{{ java_home | default('/path') }}"

# cat roles/some_role/tasks/main.yml
---
debug:
  var: r__java_home

Przedrostek zmiennych roli

BAD: użyj zmiennej globalnej.

# cat roles/some_role/defaults/main.yml
---
db_port: 5432

DOBRY: W rolach dla zmiennych używaj zmiennych poprzedzonych nazwą roli; to, patrząc na inwentarz, ułatwi zrozumienie, co się dzieje.

# cat roles/some_role/defaults/main.yml
---
some_role__db_port: 5432

Użyj zmiennej sterującej pętli

BAD: Użyj standardowej zmiennej w pętlach item, jeśli to zadanie/podręcznik jest gdzieś uwzględnione, może to prowadzić do nieoczekiwanego zachowania

---
- hosts: localhost
  tasks:
    - debug:
        msg: "{{ item }}"
      loop:
        - item1
        - item2

DOBRY: Przedefiniuj zmienną w pętli via loop_var.

---
- hosts: localhost
  tasks:
    - debug:
        msg: "{{ item_name }}"
      loop:
        - item1
        - item2
      loop_control:
        loop_var: item_name

Sprawdź zmienne wejściowe

Zgodziliśmy się na stosowanie przedrostków zmiennych, nie będzie zbyteczne sprawdzenie, czy są one zdefiniowane zgodnie z naszymi oczekiwaniami i czy nie zostały np. nadpisane pustą wartością

DOBRY: Sprawdź zmienne.

- name: "Verify that required string variables are defined"
  assert:
    that: ahs_var is defined and ahs_var | length > 0 and ahs_var != None
    fail_msg: "{{ ahs_var }} needs to be set for the role to work "
    success_msg: "Required variables {{ ahs_var }} is defined"
  loop_control:
    loop_var: ahs_var
  with_items:
    - ahs_item1
    - ahs_item2
    - ahs_item3

Unikaj słowników zawierających skróty, używaj płaskiej struktury

Jeśli rola oczekuje skrótu/słownika w jednym ze swoich parametrów, to jeśli chcemy zmienić jeden z parametrów podrzędnych, będziemy musieli zastąpić cały skrót/słownik, co zwiększy złożoność konfiguracji.

BAD: Użyj skrótu/słownika.

---
user:
  name: admin
  group: admin

DOBRY: Użyj płaskiej, zmiennej struktury.

---
user_name: admin
user_group: "{{ user_name }}"

Twórz idempotentne podręczniki i role

Role i scenariusze muszą być idempotentne, ponieważ zmniejsza dryf konfiguracji i strach przed uszkodzeniem czegoś. Ale jeśli używasz cząsteczki, jest to zachowanie domyślne.

Unikaj używania modułów powłoki poleceń

Użycie modułu powłoki skutkuje paradygmatem opisu imperatywnego zamiast deklaratywnego, który jest rdzeniem Ansible.

Przetestuj swoje role za pomocą cząsteczki

Cząsteczka to bardzo elastyczna rzecz, spójrzmy na kilka scenariuszy.

Cząsteczka Wiele instancji

В molecule.yml w sekcji platforms możesz opisać wiele hostów, które możesz wdrożyć.

---
    driver:
      name: docker
    platforms:
      - name: postgresql-instance
        hostname: postgresql-instance
        image: registry.example.com/postgres10:latest
        pre_build_image: true
        override_command: false
        network_mode: host
      - name: app-instance
        hostname: app-instance
        pre_build_image: true
        image: registry.example.com/docker_centos_ansible_tests
        network_mode: host

W związku z tym te hosty mogą być converge.yml używać:

---
- name: Converge all
  hosts: all
  vars:
    ansible_user: root
  roles:
    - role: some_role

- name: Converge db
  hosts: db-instance
  roles:
    - role: some_db_role

- name: Converge app
  hosts: app-instance
  roles:
    - role: some_app_role

Weryfikator Ansible

W molekule można użyć ansible, aby sprawdzić, czy instancja została poprawnie skonfigurowana, co więcej, jest to ustawienie domyślne od wersji 3. Nie jest tak elastyczny jak testinfra/inspec, ale możemy sprawdzić, czy zawartość pliku odpowiada naszym oczekiwaniom:

---
- name: Verify
  hosts: all
  tasks:
    - name: copy config
      copy:
        src: expected_standalone.conf
        dest: /root/wildfly/bin/standalone.conf
        mode: "0644"
        owner: root
        group: root
      register: config_copy_result

    - name: Certify that standalone.conf changed
      assert:
        that: not config_copy_result.changed

Możesz też wdrożyć usługę, poczekać, aż stanie się dostępna i wykonać test dymny:

---
  - name: Verify
    hosts: solr
    tasks:
      - command: /blah/solr/bin/solr start -s /solr_home -p 8983 -force
      - uri:
          url: http://127.0.0.1:8983/solr
          method: GET
          status_code: 200
        register: uri_result
        until: uri_result is not failed
        retries: 12
        delay: 10
      - name: Post documents to solr
        command: /blah/solr/bin/post -c master /exampledocs/books.csv

Umieść złożoną logikę w modułach i wtyczkach

Ansible opowiada się za podejściem deklaratywnym, więc gdy wykonujesz rozgałęzienia kodu, transformację danych i moduły powłoki, kod staje się trudny do odczytania. Aby temu zaradzić i zapewnić prostotę zrozumienia, nie będzie zbędne zwalczanie tej złożoności poprzez tworzenie własnych modułów.

Podsumuj porady i wskazówki

  1. Unikaj zmiennych globalnych.
  2. Przedrostek zmiennych roli.
  3. Użyj zmiennej sterującej pętli.
  4. Sprawdź zmienne wejściowe.
  5. Unikaj słowników zawierających skróty, używaj płaskiej struktury.
  6. Twórz idempotentne podręczniki i role.
  7. Unikaj używania modułów powłoki poleceń.
  8. Przetestuj swoje role za pomocą cząsteczki.
  9. Umieść złożoną logikę w modułach i wtyczkach.

wniosek

Jak zacząć testować Ansible, zrefaktoryzować projekt w rok i nie zwariować

Nie możesz po prostu przejść do refaktoryzacji infrastruktury w projekcie, nawet jeśli masz IaC. Jest to długi proces wymagający cierpliwości, czasu i wiedzy.

UPD1 2020.05.01 20:30 — Do podstawowego profilowania podręczników, których możesz użyć callback_whitelist = profile_tasks aby zrozumieć, co dokładnie działa przez długi czas. Potem przechodzimy Klasyka akceleracji Ansible. Możesz też spróbować mitogen
UPD2 2020.05.03 16:34 - angielska wersja

Źródło: www.habr.com

Dodaj komentarz