Infrastructure as a code, czyli konfiguracja i uruchomienie mierzone w sekundach

dodał 11 czerwca 2019 o 06:43 w kategorii HowTo  z tagami:
Infrastructure as a code, czyli konfiguracja i uruchomienie mierzone w sekundach

Błogosławieństwem technologii miała być oszczędność czasu. Trudno jednak o niej pamiętać, gdy poświęca się długie godziny na stawianie i konfigurowanie serwerów. A gdyby zrobić to wszystko automatycznie?

W dotychczasowej serii artykułów Aruba Cloud prezentowaliśmy różne scenariusze wykorzystania zasobów w chmurze, odnosząc się przede wszystkim do aspektów ich praktycznego wykorzystania. Każda z publikacji zawierała instrukcję, której celem było przeprowadzenie czytelnika przez szereg czynności konfiguracyjnych zmierzających do uzyskania efektu końcowego w postaci działającego rozwiązania. Dziś natomiast nie będzie żadnego ,,kompletnego tutoriala”, ponieważ zamierzamy dostarczyć wam gotową infrastrukturę w postaci kodu.

Cyfrowy Ninja”

Ile razy w swojej codziennej pracy robiliście to samo: dwuklik, dalej, dalej, zainstaluj… a następnie niecierpliwe oczekiwanie, aż przysłowiowy ,,pasek postępu” dotrze do końca? Ile jest komend i poleceń z basha, które nie tyle znacie, co pamiętają je już wasze palce? Ręczne powtarzanie tych samych zadań setki razy dziennie to jedna z najnudniejszych, uciążliwych i – na szczęście – odchodzących do lamusa praktyk.

W tym roku mija już 10 lat od wydarzenia, podczas którego po raz pierwszy publicznie została zaprezentowana metodyka DevOps. Samo sformułowanie jest powszechnie znane w branży IT, a wpisanie tej frazy w rodzimych wyszukiwarkach ofert pracy generuje kilkaset wyników. Metodyka DevOps służy przede wszystkim szybszemu dostarczeniu oprogramowania przy znaczącym ograniczeniu liczby błędów powstałych podczas jego tworzenia.

Automatyzacja – czy może jednak instrumentacja?

Terraform to rozwiązanie open source służące do orkiestracji zasobów uruchamianych zarówno w ramach infrastruktur lokalnych, jaki i chmurowych. Projekt jest bardzo dynamicznie rozwijany, a dzięki bardzo aktywnej społeczności zapewnia na tę chwilę wsparcie dla ponad setki dostawców API (providers). Ponadto współdziała on z wieloma różnymi narzędziami służącymi do tzw. ,,wyposażania” (provisioners). Terraform pozwala na realizację bardzo złożonych zadań, same platformy chmurowe to przecież nie tylko instancje systemów operacyjnych, ale też niezliczona ilość dodatkowych elementów – zasoby storage, komponenty sieciowe czy systemy zarządzania tożsamością (IAM). Stąd właśnie coraz częściej spotykamy się z pojęciem orkiestracji (instrumentacji). Sama automatyzacja to nie wszystko – jako proces musi być odpowiednio zaplanowana, realizowana w kontekście wymagań biznesowych oraz monitorowana przez cały cykl życia dostarczanej aplikacji.

Korzystanie z Terraforma polega na opisaniu naszej infrastruktury w plikach o rozszerzeniu .tf przy wykorzystaniu języka HCL (HashiCorp Configuration Language). Składnia bazuje na tej znanej z JSON, przy czym autorzy narzędzia (firma HashiCorp) wprowadzili do HCL parę usprawnień (m.in. możliwość umieszczania komentarzy). W samym kodzie wykorzystywanych jest kilka elementów służących do budowania całego środowiska. Najistotniejsze z nich i wykorzystywane w naszym przykładzie to:

data – pozwala na odczytywanie dostępnych parametrów pobieranych przez API, takich jak np. nazwy istniejących instancji,

variablezmienna wykorzystywana do przechowywania wartości, np. nazwa lub adresacja nowo tworzonej sieci, nazwa hosta, login itd. Aby odwołać się do wartości zmiennej, nazwę parametru należy poprzedzić przedrostkiem var,

resourceczyli zasoby, jakie zostaną stworzone przez Terraforma.

Po opisaniu całej infrastruktury i stworzeniu wszystkich plików, zanim przystąpimy do uruchomienia wdrożenia, warto zweryfikować, czy wszystkie pliki są poprawne i nie zawierają błędów. W tym celu możemy uruchomić polecenie terraform validate. Polecenie wywołujemy zawsze z głównego katalogu zawierającego pliki naszego środowiska. O ile nie popełniliśmy żadnego błędu, powinniśmy zobaczyć komunikat o treści: ,,Success! The configuration is valid”. Poza walidacją w Terraformie jest jeszcze kilka istotnych poleceń:

terraform init – służy do inicjalizacji, czyli dokonuje wstępnej analizy naszego środowiska i w razie potrzeby przeprowadza automatyczne pobranie wymaganych modułów, jakie zostaną zapisane w subkatalogu o nazwie .terraform,

terrafform plan – wyświetla opis tworzonej infrastruktury dla jej aktualnego stanu. Dzięki automatycznie utworzonemu plikowi terraform.tfstate stan infrastruktury jest cały czas monitorowany. Dlatego kolejne wywołania wdrożeń zamiast budować wszystko od nowa po prostu zaktualizują tylko te zmiany, jakie dodaliśmy w kolejnej rewizji kodu. Na koniec każdego wywołania tej komendy Terraform poinformuje nas o liczbie wprowadzanych zmian:

terraform apply – realizuje wdrożenie / aktualizację środowiska zgodnie z wcześniej utworzonym planem,

terraform destroy – usuwa wszystkie zasoby zgodnie z sobie znanym stanem środowiska. Dlatego pod żadnym pozorem nie należy ręcznie edytować czy kasować pliku terraform.tfstate, w przeciwnym razie Terraform może wygenerować błędy lub nie być w stanie przeprowadzić żadnej modyfikacji na środowisku.

Sam Terraform pozwala na wykonanie dowolnych poleceń czy skryptów powłoki, niemniej jednak dzieje się to każdorazowo podczas wykonywania operacji związanych z wdrożeniem czy aktualizacją infrastruktury. Dzięki tzw. ,,provisionerom” mamy możliwość wykonywania zestawu dodatkowych operacji już po utworzeniu naszych zasobów. Jednym z najpopularniejszych narzędzi do zarządzana infrastrukturą jest Ansible. Rozwiązanie to jest całkowicie bezagentowe – w przypadku platformy CentOS działa w oparciu o protokół SSH i biblioteki Pythona. Do realizacji wdrożeń konfiguracji będziemy korzystać z tzw. playbooków. To specjalne pliki utworzone w formacie YAML– zawieramy w nich dyrektywy służące do przeprowadzania procesów konfiguracyjnych na wskazanych hostach.

Demonstrację na żywym systemie znajdziecie na poniższym filmie, a pod nim zamieściliśmy instrukcje krok po kroku.

Aruba Private Cloud

Firma Aruba dla najbardziej wymagających klientów przygotowała rozwiązanie w postaci usługi dedykowanej chmury prywatnej. To rozwiązanie bez kompromisów, zapewniające rezerwację zasobów obliczeniowych czy przestrzeni dyskowej na ściśle określonym poziomie. Usługa Private Cloud działa w oparciu o stabilne i sprawdzone rozwiązania firmy VMware, jakimi są vCloudDirector czy NSX. Zamówienie takiej usługi to tak naprawdę utworzenie tzw. wirtualnego data center wydzielonego z fizycznych zasobów Aruba Cloud. Sama aktywacja usługi, gdy już posiadamy konto Aruba Cloud, sprowadza się do przeprowadzenia kilku prostych czynności:

1. Po zalogowaniu do Panelu Administracyjnego przechodzimy do zakładki Cloud PRIVATE i rozpoczynamy proces konfiguracji usługi poprzez kliknięcie na przycisk

2. W formularzu podajemy parametry nowej chmury prywatnej, które są zgodnie z naszymi wymaganiami. Dla naszego środowiska wybieramy poniższą konfigurację:

3. Po kliknięciu na ,,Kontynuuj” przechodzimy do kolejnego okna kreatora, w którym definiujemy parametry zasobów sieciowych:

4. W ramach usługi Cloud Private mamy możliwość skorzystać z zewnętrznych technologii do backupu i obsługi mechanizmów disaster recovery. Wybór obu rozwiązań jest opcjonalny, stąd też ten krok konfiguracji możemy pominąć. Ostatnim oknem kreatora jest to, w którym definiujemy parametry takie jak: nazwa usługi, dane logowania do panelu VMware vCloud Director czy też dane kontaktowe do administratora zasobu Cloud Private:

5. Po zapisaniu wszystkich danych kreatora zostajemy przeniesieni do strony podsumowania. Warto jeszcze raz dokładnie sprawdzić wszystkie parametry, ponieważ Cloud Private działa w modelu rozliczenia miesięcznego – po zakończeniu procesu wdrożenia nasze konto zostanie obciążone kwotą za całą usługę:

Wydzielenie naszej infrastruktury i uruchomienie prywatnej chmury może potrwać do 24 godzin. Stan tworzenia zasobów możemy monitorować bezpośrednio z panelu administracyjnego:

Oczywiście jak tylko zasoby będą już dostępne, otrzymamy stosowne powiadomienie na naszą skrzynkę pocztową.

Terraform – formujemy pierwsze zasoby

Samego Terraforma możemy bardzo łatwo zainstalować poprzez pobranie gotowego pliku binarnego ze strony producenta: https://www.terraform.io/downloads.html

Terraform działa na praktycznie dowolnej platformie – również w architekturze ARM. Aktualnie wspierane systemy to między innymi Linux, Windows, macOS, Free/OpenBSD oraz Solaris. Na potrzeby naszego artykułu wykorzystujemy system Debian 9.9. Samo pierwsze uruchomienie Terraforma może wyglądać w poniższy sposób:

Gdy samo narzędzie jest gotowe do pracy, kolejnym etapem jest stworzenie opisu naszego środowiska w postaci kodu. Na początek zdefiniujmy jego podstawowe parametry:

  • serwer CentOS utworzony z gotowego obrazu w konfiguracji: 4xvCPU i 4GB RAM,
  • serwer ma działać w ramach sieci wewnętrznej i adresacji prywatnej,
  • na zewnątrz pod jednym publicznym adresem IP osiągalne będą usługi takie jak http/https,
  • zarządzanie serwerem ma być możliwe przez SSH dostępne na publicznym adresie IP,
  • na maszynach wirtualnych zaraz po ich wdrożeniu mają być automatycznie przeprowadzone następujące czynności: instalacja i konfiguracja LAMP stack (apache + php + mariadb) oraz wdrożenie gotowej witryny opartej o WordPressa.

Powyższy opis możemy potraktować jako prosty przykład wymagań klienta oczekującego od nas przygotowania odpowiedniego środowiska pod konkretną aplikację.

Aruba Cloud Private daje nam możliwość załadowania własnego obrazu maszyny wirtualnej w formacie OVF. W związku z tym, że takie własne obrazy będą zmniejszały zakupioną przestrzeń dyskową, skorzystamy z gotowych szablonów OVF dostarczanych przez Aruba. Nazwy wszystkich obrazów możemy zweryfikować z poziomu vCloudDirectora:

Każdy plik .tf zawierający kod może opisywać konkretny fragment infrastruktury, taki jak konfiguracja aplikacji (vApp), definicje sieci (Network) czy reguły firewalla (Firewall). Na początku zaczynamy od zdefiniowania wartości naszych zmiennych – będą to parametry podłączenia Terraforma do API vCloud Directora. W tym celu, korzystając z dowolnego edytora, tworzymy plik o nazwie terraform.tfvars. Plik ten będzie zawierał następujące definicje:

Poszczególne wartości dla zmiennych związane z danymi logowania zostały wcześniej zdefiniowane na etapie konfiguracji usługi. URL API jest tożsamy z adresem do logowani do panelu, jaki możemy podejrzeć w panelu zarządzaniu usługą:

Samo API jest dostępne przez inną ścieżkę, dlatego kasujemy wszystko za rozszerzeniem .pl i po ukośniku dopisujemy frazę ,,api”, co w przypadku naszego środowiska utworzy nam następujący URL: https://admin01.dc8.private.arubacloud.pl/api

Plik zmiennych mamy już gotowy – możemy przejść do utworzenia pliku konfiguracyjnego Config.tf . Służy on do skonfigurowania połączenia w oparciu o zmienne i ich wartości, jakie zostały zdefiniowane wcześniej w pliku terraform.tfvars. Zawartość naszej konfiguracji wygląda w następujący sposób:

Mając oba pliki możemy od razu sprawdzić, czy wszystkie definicje zostały przez nas wprowadzone poprawnie. W tym celu będąc w ścieżce, w której znajdują się oba pliki, wystarczy wydać polecenie:

Wynik jego działania powinien przedstawiać się w następujący sposób:

Jak widać powyżej Terraform sam w sposób automatyczny pobrał plugin wymagany do połączenia z providerem (vcd).

Gdy już sam Terraform został wstępnie przygotowany do pracy, możemy zacząć opisywać naszą infrastrukturę. W pierwszej kolejności utworzymy plik Network.tf, który będzie definiował parametry sieci wewnętrznej, w ramach której pracować będzie nasz serwer:

Korzystamy tutaj z sieci typu ‚routed’, dzięki czemu z wykorzystaniem reguł obsługiwanych przez bramę domyślną będziemy mogli na adres prywatny serwera realizować przekierowania wybranych portów z adresu publicznego. Sama definicja sieci jest dość przejrzysta i jak widać powyżej, zwiera w sobie: jej nazwę, maskę oraz adres bramy, definicje serwerów dns i konfigurację usługi dhcp.

Kolejno – mając już opis sieci – możemy utworzyć stosowne reguły, definiując je w pliku o nazwie Firewall.tf. Za samą obsługę polityk firewalla będzie odpowiedzialny nasz ,,Edge Gateway”:

To, na co należy zwrócić uwagę zarówno w pliku Network.tf, jak i Firewall.tf, to odwołania do zmiennej ,,vcd_edge”, pod którą kryje się nazwa naszego ,,Edge Gateway”. Wartość zmiennej została zdefiniowana w pliku terraform.tfvars:

Nazwę ,,Edge Gateway” możemy odnaleźć po zalogowaniu się do vCloudDirectora i przejściu do zakładki ,,Administration”. Klikamy w niej na nazwę naszego wirtualnego data center:

I następnie przechodząc do sekcji ,,Edge Gateways”:

Do ukończenia opisu środowiska w Terraform został nam już tylko jeden plik – ten najważniejszy, opisujący samą ,,wirtualną aplikację” – vApp.tf. Odpowiada on założeniom poczynionym na samym początku i wygląda w następujący sposób:

W początkowych wierszach vAPP.tf zdefiniowana została ścieżka do skryptu, jaki zostanie automatycznie uruchomiony wewnątrz maszyny podczas jej wdrożenia:

Zasadniczo taki skrypt może dokonywać jakiejś wstępnej prekonfiguracji systemu. Nie jest to oczywiście konieczne, ponieważ wszystko możemy zrealizować na późniejszym etapie przy pomocy narzędzia, jakim jest Ansible.

Konfigurowanie i utrzymywanie środowiska przy pomocy Ansible

Od strony zasobów systemów operacyjnych i konfiguracji sieci nasza infrastruktura jest już w pełni opisana. Jedną z ciekawszych funkcji Terraforma jest możliwość budowania grafów, co pozwala na zwizualizowanie zależności pomiędzy poszczególnymi elementami umieszczonymi w kodzie infrastruktury. Poniższy graf przedstawiający naszą infrastrukturę został wykonany przy wykorzystaniu zewnętrznego narzędzia blast-radius (https://github.com/28mm/blast-radius):

Wszystkie nasze zasoby zostały utworzone i uruchomione – teraz należy przejść do kolejnego etapu, w którym dalsze działania zostaną przeprowadzone ,,od wewnątrz” naszej wirtualnej instancji. Do tego właśnie potrzebujemy wspomnianego wcześniej ,,provisionera”.                

Ansible, podobnie jak Terraforma, również instalujemy na zewnętrznym systemie – w naszym przypadku będzie to ten sam lokalny serwer z systemem Debian. Instalacja sprowadza się do zainstalowania Pythona oraz narzędzia ,,pip”, a następnie instalacji samego Ansible:

Gdy już narzędzie jest gotowe do pracy, możemy zacząć przygotowywać pierwszego playbooka.

Przyjrzyjmy się jeszcze zawartości naszego katalogu roboczego, który zawiera zarówno kod opisujący infrastrukturę, jak i konfiguracje Ansible wraz z playbookiem:

ansible.cfg to plik zawierający wszystkie domyślne ustawienia środowiska, w tym definicję pliku zasobów (inventory):

Sam plik zasobów o nazwie hosts przedstawia się w następujący sposób:

webserver.yml to playbook Ansible, w którym zostały kolejno opisane wszystkie czynności konfiguracyjne:

Stosowanie haseł w jawnej postaci nigdy nie jest dobrym pomysłem – nawet w przypadku środowiska testowego. W przypadku Ansible dzięki tzw. Vaults możemy w bezpieczny sposób przechowywać wszystkie sensytywne dane w zaszyfrowanych wartościach lub odrębnych plikach: https://docs.ansible.com/ansible/latest/user_guide/vault.html

W naszym przykładzie mamy dwie zmienne, dla których wartości zostały zaszyfrowane z wykorzystaniem algorytmu AES256:

Sam klucz szyfrujący to znane tylko nam hasło – może być ono przekazywane jako parametry przy uruchamianiu playbooka (interaktywnie) lub ładowane z pliku, który je zawiera (za co odpowiada parametr ,,–vault-password-file”). Samo utworzenie pliku haseł oraz zaszyfrowania wartości zmiennych wygląda w następujący sposób:

Wynik powyżej wykonanych poleceń powinien być zbliżony do poniższego:

Oczywiście w takim wypadku najistotniejszą kwestią jest właściwe zabezpieczenie pliku zawierającego hasła (vault_pass).

Na podstawie zawartości powyższego playbooka Ansible przeprowadzi następujące akcje:

  1. Oczekuje maksymalnie 300 sekund na uruchomienie usługi OpenSSH na naszym serwerze.
  2. Instaluje usługę httpd oraz biblioteki php.
  3. Pobiera i rozpakowuje archiwum z najnowszą wersją WordPressa (polskojęzyczną).
  4. Instaluje bazę danych MariaDB.
  5. Instaluje biblioteki Python MySQL.
  6. Uruchamia i włącza usługę MariaDB.
  7. Ustawia hasło użytkownika root dla usługi MariaDB.
  8. Tworzy plik konfiguracyjny /root/.my.cnf.
  9. Usuwa z konfiguracji MariaDB użytkowników anonimowych.
  10. Tworzy użytkownika o nazwie wordpress i nadaje mu uprawnienia do bazy o nazwie wordpress.
  11. Tworzy bazę danych o nazwie wordpress.
  12. Kopiuje gotowy plik konfiguracyjny wp-config.php.j2 do ścieżki /var/www/html/wordpress/wp-config.php.
  13. Kopiuje plik zrzutu bazy danych do katalogu /tmp.
  14. Odtwarza bazę danych z pliku zrzutu.
  15. Uruchamia i włącza usługę httpd.
  16. Restartuje usługę MariaDB.

Aby powyższe działania mogły być zrealizowane, Ansible musi mieć możliwość połączenia z serwerem docelowym przez protokół SSH. Całą operację provisioningu wykonujemy jednym poleceniem:

W naszym przykładzie nie musimy tego robić- powyższe polecenie zostanie wywołane w ramach wdrożenia realizowanego przez Terraforma – w vApp.tf odpowiedzialna jest za to następująca część kodu:

Polecenie [terraform apply] musi być w takim wypadku wykonane z głównego katalogu – z tej samej ścieżki zadziała też Ansible i będzie oczekiwał widoczności wszystkich wymaganych plików w tej samej lokalizacji. To tyle, jeżeli chodzi o naszą testową infrastrukturę. Na koniec wydajemy zestaw poniższych poleceń i oczekujemy na efekt końcowy ich działania:

Jak widać na poniższym zrzucie, cały proces zajął około dwóch i pół minuty:

Wszystkie pliki wykorzystane w naszym przykładzie możecie pobrać z wykorzystaniem poniższego linku (hasło: z3s):

https://zaufanatrzeciastrona.pl/wp-content/uploads/2019/06/z3s-archiwum.zip

W zaprezentowanym przykładowym środowisku zależało nam przede wszystkim na jego prostocie – w końcu dla niektórych z Was będzie to pierwsza styczność z tym narzędziem. Uproszczenia jednak nie są dobre tam, gdzie środowisko nie będzie tym w pełni testowym. Minimalnie zalecamy zmodyfikowanie zaprezentowanych plików przez dodanie do konfiguracji własnej pary kluczy SSH.

Możecie również rozważyć wdrożenie konfiguracji tunelu IPSec, w ramach to którego Ansible będzie komunikował się z instancjami maszyn wdrożonymi przez Terraforma: https://www.terraform.io/docs/providers/vcd/r/edgegateway_vpn.html

Na zakończenie podajemy Wam bezpośrednie linki do dokumentacji produktów –  poza samymi opisami poszczególnych modułów zawiera ona też instrukcje dla początkujących typu ,,getting started”: