
Podejście IaC (Infrastructure as Code) składa się nie tylko z kodu, który jest przechowywany w repozytorium, ale także z ludzi i procesów, które go otaczają. Czy można wykorzystać podejścia z rozwoju oprogramowania w zarządzaniu i opisywaniu infrastruktury? Nie zaszkodzi mieć tę ideę na uwadze podczas czytania artykułu.
To jest transkrypcja mojego na .
Prezentacje i filmy
- Wizja 2019-04-24
Infrastruktura jako historia bash

Załóżmy, że przychodzisz do nowego projektu, a mówią ci: „mamy Infrastruktura jako kod„. W rzeczywistości okazuje się, Infrastruktura jako historia bash lub na przykład Dokumentacja jako historia bash. To całkiem realistyczna sytuacja, na przykład, podobny przypadek opisał Denis Łysenko w swoim wystąpieniu , opowiedział, jak z historii bash otrzymali zorganizowaną infrastrukturę w projekcie.
Przy pewnej dozie chęci, można powiedzieć, że Infrastruktura jako historia bash to jak kod:
- odtwarzalność: możesz wziąć historię bash, wykonać polecenia stamtąd, możliwe, że w ten sposób otrzymasz działającą konfigurację na wyjściu.
- wersjonowanie: wiesz, kto się logował i co robił, ponownie nie ma pewności, że to doprowadzi cię do działającej konfiguracji na wyjściu.
- historię: historia kto i co zrobił. tylko nie będziesz mógł z niej korzystać, jeśli zgubisz serwer.
Co robić?
Infrastruktura jako kod

Nawet taki dziwny przypadek jak Infrastruktura jako historia bash można jakoś połączyć z Infrastruktura jako kod, ale gdy zechcemy zrobić coś bardziej skomplikowanego niż stary, dobry serwer LAMP, dojdziemy do wniosku, że ten kod trzeba w jakiś sposób modyfikować, zmieniać, rozwijać. Następnie chcielibyśmy rozważyć paralele między Infrastruktura jako kod a rozwojem oprogramowania.
D.R.Y.

W projekcie rozwoju systemów magazynowych, istniał podprojekt : wydajemy nową wersję - trzeba ją wdrożyć do dalszych testów. Zadanie jest proste:
- wejdź tutaj przez ssh i wykonaj polecenie.
- skopiuj tam plik.
- tu popraw konfigurację.
- tam uruchom usługę
- …
- ZYSK!
Dla opisanej logiki więcej niż wystarczy bash, szczególnie na wczesnych etapach projektu, gdy dopiero się rozpoczyna. To , ale z czasem pojawia się potrzeba rozwinięcia czegoś podobnego, ale nieco różniącego się. Pierwsze, co przychodzi na myśl, to copy-paste. I już mamy dwa bardzo podobne skrypty, które robią niemal to samo. Z czasem liczba skryptów wzrosła, i napotkaliśmy na pewną logikę biznesową wdrożenia instalacji, którą trzeba zsynchronizować pomiędzy różnymi skryptami, co jest dość skomplikowane.

Okazuje się, że istnieje praktyka D.R.Y. (Nie Powtarzaj Się). Idea polega na ponownym wykorzystaniu istniejącego kodu. Brzmi prosto, ale nie doszliśmy do tego od razu. W naszym przypadku była to prosta idea: oddzielenie konfiguracji od skryptów. Tzn. logika biznesowa dotycząca wdrożenia instalacji osobno, konfiguracje osobno.
S.O.L.I.D. dla CFM

Z czasem projekt rósł i stało się pojawienie Ansible. Głównym powodem jego pojawienia się była obecność ekspertyzy w zespole oraz fakt, że bash nie jest przeznaczony do złożonej logiki. Ansible także zaczęło zawierać złożoną logikę. Aby złożona logika nie przerodziła się w chaos, w rozwoju oprogramowania istnieją zasady organizacji kodu. S.O.L.I.D. Także, na przykład, Grigorij Pietrow w swoim referacie "Dlaczego IT-owiec potrzebuje osobistej marki" poruszył kwestię, że człowiek, tak jest skonstruowany, że łatwiej mu operować pewnymi bytami społecznymi, w rozwoju oprogramowania są to obiekty. Jeśli połączyć te dwie idee i rozwijać je dalej, można zauważyć, że w opisie infrastruktury również można używać S.O.L.I.D. aby w przyszłości było łatwiej utrzymywać i modyfikować tę logikę.
Zasada pojedynczej odpowiedzialności

Każda klasa wykonuje tylko jedno zadanie.
Nie należy mieszać kodu i tworzyć monolitycznych boskich makaronowych potworów. Infrastruktura powinna składać się z prostych klocków. Okazuje się, że jeśli podzielić Ansible playbook na małe kawałki, czytaj Ansible role, to łatwiej je utrzymywać.
Zasada otwarte/zamknięte

Zasada otwartości/zamkniętości.
- Otwarte na rozszerzenia: oznacza, że zachowanie bytu może być rozszerzone poprzez tworzenie nowych typów bytów.
- Zamknięte na zmiany: w wyniku rozszerzenia zachowania bytu nie powinny być wprowadzane zmiany w kodzie, który korzysta z tych bytów.
Początkowo rozwijaliśmy testową infrastrukturę na maszynach wirtualnych, ale dzięki temu, że logika biznesowa implementacji była oddzielona od realizacji, bez problemu dodaliśmy rozkładanie na baremetal.
Zasada podstawienia Liskov

Zasada podstawienia Barbary Liskov. Obiekty w programie powinny być wymienialne na instancje ich podtypów bez zmiany poprawności działania programu.
Jeśli spojrzeć szerzej, to nie jest to szczególna cecha konkretnego projektu, można to zastosować wszędzie. S.O.L.I.D., w ogólnym ujęciu chodzi o CFM, na innym projekcie konieczne jest wdrażanie aplikacji Java na różnych serwerach aplikacyjnych, bazach danych, systemach operacyjnych itd. Na tym przykładzie rozważę dalsze zasady. S.O.L.I.D.
W naszym przypadku w ramach zespołu infrastruktury istnieje ustalenie, że jeśli zainstalujemy rolę imbjava lub oraclejava, to mamy binarny plik wykonywalny java. Jest to konieczne, ponieważ wyższe role zależą od tego zachowania, oczekują obecności java. Jednocześnie pozwala nam to na wymianę jednej implementacji/wersji java na inną, nie zmieniając logiki wdrażania aplikacji.
Problem polega na tym, że w Ansible nie można zaimplementować takiej funkcji, w ramach zespołu pojawiają się jakieś ustalenia.
Zasada segregacji interfejsów

Zasada segregacji interfejsów: "Wiele interfejsów, specjalnie zaprojektowanych dla klientów, jest lepsze niż jeden interfejs ogólnego przeznaczenia."
Początkowo próbowaliśmy zbierać całą wariantowość wdrażania aplikacji w jednym playbooku Ansible, ale było to trudne do utrzymania, a podejście, w którym mamy sprecyzowany interfejs na zewnątrz (klient oczekuje portu 443), pozwala na komponowanie infrastruktury dla konkretnej realizacji z oddzielnych bloków.
Zasada inwersji zależności

Zasada inwersji zależności. Moduły wyższych poziomów nie powinny zależeć od modułów niższych poziomów. Oba typy modułów powinny zależeć od abstrahacji. Abstrahacje nie powinny zależeć od szczegółów. Szczegóły powinny zależeć od abstrahacji.
Ten przykład będzie oparty na antywzorcach.
- Jeden z naszych klientów miał prywatne chmurę.
- Wewnątrz chmury zamawialiśmy maszyny wirtualne.
- Jednak z powodu szczególnych cech chmury wdrażanie aplikacji było powiązane z tym, na jaki hypervisor trafiła VM.
To. wysoko poziomowa logika wdrażania aplikacji, zależności przeszły na niższe poziomy hypervisora, co oznaczało problemy z ponownym wykorzystaniem tej logiki. Nie rób tak.
Interakcja

Infrastruktura jako kod to nie tylko kod, ale także relacje między kodem a człowiekiem, interakcje między twórcami infrastruktury.
Bus factor

Załóżmy, że na twoim projekcie jest Wania. Wania wie wszystko o twojej infrastrukturze. Co się stanie, jeśli Wania nagle zniknie? To całkiem realna sytuacja, ponieważ może go przejechać autobus. Czasami tak się zdarza. Jeśli wiedza na temat kodu, jego struktury, tego jak działa, loginów i haseł nie jest rozproszona w zespole, możesz napotkać wiele nieprzyjemnych sytuacji. Aby zminimalizować te ryzyka i rozłożyć wiedzę w zespole, można zastosować różne podejścia.
Pair Devopsing

To nie jest jak , że administratorzy pili piwo, zmieniali hasła, a to odpowiednik programowania w parach. To znaczy dwóch inżynierów siada za jednym komputerem, na jednej klawiaturze i zaczyna wspólnie konfigurować twoją infrastrukturę: konfigurować serwer, pisać rolę Ansible itd. Brzmi pięknie, ale u nas się nie sprawdziło. Jednak niektóre przypadki tej praktyki działały. Nowy pracownik, jego mentor razem z nim bierze rzeczywiste zadanie, pracują — przekazują wiedzę.
Inny przypadek to incident call. Podczas problemu zbiera się grupa dyżurnych i zainteresowanych, wyznaczany jest jeden prowadzący, który udostępnia swój ekran i na głos przedstawia tok myślenia. Inni uczestnicy śledzą myśli prowadzącego, podglądają triki z konsoli, sprawdzają, czy nie pominęli jakiejś linii w logach, poznają nowe informacje o systemie. Takie podejście działało raczej lepiej niż gorzej.
Code Review

Subiektywnie, bardziej efektywne przekazywanie wiedzy o infrastrukturze i tym, jak jest zbudowana, odbywało się za pomocą code review:
- Infrastruktura opisana jest kodem w repozytorium.
- Zmiany zachodzą w oddzielnej gałęzi.
- Podczas żądania mergowania można zobaczyć różnicę w zmianach infrastruktury.
Unikalnym elementem było to, że recenzenci byli wybierani na zmianę, według harmonogramu, to znaczy z pewnym prawdopodobieństwem trafiłeś w nowy obszar infrastruktury.
Styl kodu

Z biegiem czasu zaczęły się pojawiać napięcia podczas przeglądów, ponieważ recenzenci mieli swoje style, a rotacja recenzentów sprawiała, że spotykali się z różnymi stylami: 2 spacje lub 4, camelCase czy snake_case. Wdrożenie tego nie było łatwe.
- Pierwszą myślą było zarekomendowanie użycia lintera, wszak inżynierowie to inteligentni ludzie. Ale różne edytory oraz systemy operacyjne były problematyczne.
- To ewoluowało w bota, który przy każdym problematycznym commicie pisał na slacku i dołączał wynik lintera. Jednak w większości przypadków znajdowały się ważniejsze zadania i kod pozostawał nieskorygowany.
Green Build Master

Czas mija, a doszliśmy do wniosku, że nie można wpuszczać do mastera commitów, które nie przechodzą pewnych testów. Voilà! wynaleźliśmy Green Build Master, który już od dawna jest praktykowany w tworzeniu oprogramowania:
- Rozwój odbywa się w osobnej gałęzi.
- W tej gałęzi uruchamiane są testy.
- Jeśli testy nie przechodzą, kod nie trafi do mastera.
Podjęcie tej decyzji było dość bolesne, ponieważ wywołało wiele sporów, ale było warto, ponieważ na przeglądach zaczęły się pojawiać prośby o scalanie bez różnic w stylu, a z biegiem czasu liczba problematycznych miejsc zaczęła się zmniejszać.
IaC Testing

Oprócz sprawdzania stylu można zastosować inne elementy, na przykład sprawdzić, czy Twoja infrastruktura rzeczywiście może się wdrożyć. Lub sprawdzić, czy zmiany w infrastrukturze nie doprowadzą do strat finansowych. Dlaczego może to być potrzebne? To skomplikowane i filozoficzne pytanie, najlepiej odpowiedzieć anegdotą, że kiedyś istniał auto-scaler na Powershell, który nie sprawdzał warunków brzegowych => utworzono więcej VM-ów niż potrzeba => klient wydał więcej pieniędzy, niż planował. To nieprzyjemne, ale ten błąd można było wykryć na wcześniejszych etapach.
Można zapytać, dlaczego skomplikowaną infrastrukturę uczynić jeszcze bardziej skomplikowaną? Testy dla infrastruktury, tak jak dla kodu, nie mają na celu uproszczenia, a raczej uzyskania wiedzy na temat tego, jak Twoja infrastruktura powinna działać.
IaC Testing Pyramid

IaC Testing: Analiza statyczna
Jeśli od razu wdrożysz całą infrastrukturę i sprawdzisz, czy działa, może się okazać, że zajmuje to mnóstwo czasu i wymaga dużych zasobów. Dlatego w podstawie powinno być coś, co działa szybko, jest tego dużo i pokrywa wiele podstawowych miejsc.
Bash jest skomplikowany
Rozważmy banalny przykład. Wybierz wszystkie pliki w bieżącym katalogu i skopiuj je w inne miejsce. Pierwsza myśl, która przychodzi do głowy:
for i in * ; do
cp $i /some/path/$i.bak
doneA co jeśli w nazwie pliku jest spacja? No dobrze, jesteśmy inteligentni, umiemy używać cudzysłowów:
for i in * ; do cp "$i" "/some/path/$i.bak" ; doneBrawo? Nie! A co jeśli w katalogu nie ma nic, tzn. globbing nie zadziała.
find . -type f -exec mv -v {} dst/{}.bak ;Teraz brawo? Nie… Zapomnieliśmy, że w nazwie pliku może być n.
touch x
mv x "$(printf "foonbar")"
find . -type f -print0 | xargs -0 mv -t /path/to/target-dirNarzędzia do analizy statycznej
Problem z poprzedniego kroku można było wychwycić, gdy zapomnieliśmy o cudzysłowach, i w tym celu istnieje wiele narzędzi , w rzeczywistości jest ich wiele i prawdopodobnie znajdziesz linter dla swojego IDE, odpowiedni do twojego stosu technologicznego.
Język
Narzędzie
bash
Ruby
python
ansible
Testowanie IaC: Testy jednostkowe

Jak się przekonaliśmy z poprzedniego przykładu, lintery nie są wszechmocne i nie mogą wskazać wszystkich problematycznych miejsc. W tym kontekście warto przypomnieć o testach jednostkowych, które pojawiają się od razu: , , , . Ale co zrobić z ansible, chef, saltstack i im podobnymi?
Na początku mówiliśmy o S.O.L.I.D. i tym, że nasza infrastruktura powinna się składać z małych elementów. Nadszedł ich czas.
- Infrastruktura jest podzielona na małe elementy, na przykład role Ansible.
- Wdraża się jakieś środowisko, czy to docker, czy VM.
- Na to testowe środowisko stosujemy naszą rolę Ansible.
- Sprawdzamy, czy wszystko działa tak, jak oczekiwaliśmy (uruchamiamy testy).
- Decydujemy, czy jest OK, czy nie.
Testowanie IaC: Narzędzia do testowania jednostkowego
Pytanie, co to są testy dla CFM? Można po prostu uruchomić skrypt, ale można też użyć gotowych rozwiązań:
CFM
Narzędzie
Ansible
Chef
Chef
saltstack
Przykład dla testinfra, sprawdzamy, czy użytkownicy test1, test2 istnieją i są w grupie sshusers:
def test_default_users(host):
users = ['test1', 'test2' ]
for login in users:
assert host.user(login).exists
assert 'sshusers' in host.user(login).groupsCo wybrać? To skomplikowane pytanie, oto przykład zmian w projektach na githubie w latach 2018-2019:

Frameworki do testowania IaC
Jak to wszystko zebrać razem i uruchomić? Można przy odpowiedniej liczbie inżynierów. Można też wziąć gotowe rozwiązania, choć nie ma ich zbyt wiele:
CFM
Narzędzie
Ansible
Chef
Terraform
Przykład zmian w projektach na githubie w latach 2018-2019:

Molecule vs. Testkitchen

Początkowo :
- Stworzyć VM równolegle.
- Zastosować role Ansible.
- Uruchomić inspec.
Dla 25-35 ról zajmowało to 40-70 minut, co było zbyt długo.

Kolejnym krokiem było przejście na jenkins / docker / ansible / molecule. Ideologicznie to to samo.
- Przeprowadzić lintowanie playbooków.
- Przeprowadzić lintowanie ról.
- Uruchomić kontener.
- Zastosować role Ansible.
- Uruchomić testinfra.
- Sprawdzić idempotencję.

Lintowanie dla 40 ról oraz testy dla kilku zajmowały około 15 minut.

Co wybrać, zależy od wielu czynników, takich jak używany stack, ekspertyza w zespole itd. Każdy sam decyduje, jak załatwić kwestie testów jednostkowych.
Testowanie IaC: testy integracyjne.

Na następnej warstwie piramidy testowania infrastruktury pojawiają się testy integracyjne. Są podobne do testów jednostkowych:
- Infrastruktura dzieli się na małe elementy, na przykład role Ansible.
- Wdraża się jakieś środowisko, czy to docker, czy VM.
- Na to środowisko testowe stosuje się wiele role Ansible.
- Sprawdzamy, czy wszystko działa zgodnie z oczekiwaniami (przeprowadzamy testy).
- Decydujemy, czy jest OK, czy nie.
Mówiąc ogólnie, nie sprawdzamy funkcjonalności pojedynczego elementu systemu jak w testach jednostkowych, sprawdzamy, jak serwer jest skonfigurowany w całości.
Testowanie IaC: testy end-to-end.

Na szczycie piramidy czekają testy end-to-end. Tzn. nie sprawdzamy funkcjonalności pojedynczego serwera, pojedynczego skryptu, pojedynczego elementu naszej infrastruktury. Sprawdzamy, czy wiele serwerów, połączonych w całość, działa zgodnie z naszymi oczekiwaniami. Niestety, nie miałem okazji zobaczyć gotowych rozwiązań, pewnie dlatego, że infrastruktura jest często unikalna i trudno ją ztemplate'ować oraz stworzyć framework do jej testowania. W efekcie każdy tworzy swoje własne rozwiązania. Istnieje popyt, ale brak odpowiedzi. Dlatego opowiem, co istnieje, aby zainspirować innych do zdrowych myśli lub przekonać mnie, że wszystko zostało wynalezione przed nami.

Projekt z bogatą historią. Używany w dużych organizacjach i prawdopodobnie każdy z Was miał z nim do czynienia. Aplikacja obsługuje wiele baz danych, integracji itd. Wiedza o tym, jak może wyglądać infrastruktura, to wiele plików docker-compose, a wiedza o tym, jakie testy uruchomić w jakim środowisku — to jenkins.

Ten schemat działał dość długo, dopóki w ramach nie spróbowaliśmy przenieść tego do Openshift. Kontenery pozostały te same, a środowisko uruchomieniowe zmieniło się (cześć D.R.Y. znowu).

Myśl badawcza poszła dalej i w openshift znalazła się taka rzecz jak APB (Ansible Playbook Bundle), która pozwala zapakować wiedzę na temat rozwoju infrastruktury w kontener. Tzn. istnieje powtarzalny, testowalny punkt wiedzy, jak rozwinąć infrastrukturę.

To wszystko brzmiało dobrze, dopóki nie napotkaliśmy na heterogeniczną infrastrukturę: potrzebujemy Windows do testów. W efekcie wiedza o tym, gdzie i jak rozwinąć oraz przetestować, znajduje się w jenkins.
Podsumowanie

Infrastructure as Code to
- Kod w repozytorium.
- Interakcja międzyludzkie.
- Testowanie infrastruktury.
linki
- Wizja 2019-04-24
- &
Źródło: habr.com
