Wstęp

Jedna aplikacja pozwalająca na automatyzację czynności administracyjnych w IT zazwyczaj nie będzie wystarczająca. Nie będzie obsługiwała wszystkich produktów lub platform, z którymi mamy do czynienia, będzie brakować jej funkcji albo po prostu do pewnych zadań będzie ona niepraktyczna. Dlatego zazwyczaj do stworzenia łańcucha czynności, które chcemy zautomatyzować wykorzystujemy więcej, niż jedną aplikację. Trzeba je jakoś ze sobą połączyć i jest na to kilka sposobów.

Pamiętaj, że wybór odpowiedniego sposobu zależy od narzędzi, jakie wykorzystujesz, informacji, które musisz pomiędzy nimi przekazać oraz tego, czy kolejne etapy scenariusza mają się uruchamiać automatycznie, lub czy będą one uruchamiane manualnie przez specjalistów zarządzających infrastrukturą. W tym artykule przyjrzymy się kilku sposobom łączenia ze sobą dwóch bardzo popularnych narzędzi jakimi są Terraform i Ansible. W poprzednim wpisie „Przechowywanie aktualnego stanu infrastruktury” wspomniałem, że moim zdaniem Terraform lepiej nadaje się do budowania i zarządzania elementami infrastruktury, zaś Ansible do ich konfiguracji i zarządzania. Zastanówmy się nad prostym przykładem uruchomienia maszyny wirtualnej w chmurze publicznej AWS.

Wykorzystanie Ansible do konfiguracji maszyny wirtualnej jest jak najbardziej wskazane, jednakże, jeżeli konfiguracja ta jest powtarzalna rekomendowanym i bezpieczniejszym podejściem jest utworzenie własnego obrazu AMI i jedynie zarządzanie konfigurację aplikacji, a nie konfigurowanie od podstaw za każdym razem systemu operacyjnego i aplikacji.

Bezpośrednie wywołanie playbooka Ansible

Na czym tak naprawdę polega główny problem związany z łączeniem wielu narzędzi ze sobą wspomniałem już wcześniej. To kwestia przekazywania pewnych parametrów pomiędzy używanymi narzędziami. W naszym scenariuszu będzie to lista nowo powołanych serwerów za pomocą Terraforma, które mają zostać następnie skonfigurowane przygotowanym playbookiem Ansible.

Terraform zawiera specjalny blok służący do wywoływania zdalnych narzędzi. Blok ten nosi nazwę provisioner. Może on być używany do modelowania określonych działań na systemie lokalnym lub zdalnym w celu przygotowania serwerów lub innych obiektów infrastruktury do obsługi. Odwoływać może się on generycznych zasobów takich jak plik (file), wywołanie lokalnego skryptu (local-exec) oraz wywołanie skryptu na zdalnym systemie (remote-exec). Istniały także moduły dla połączenia z systemami Chef, Puppet, Habitat czy Salt, lecz zostały one oznaczone jako przestarzałe z wydaniem 0.13.4 Terraforma, i całkowicie usunięte od wersji 0.15, która jest najnowszą wersją w momencie pisania tego artykułu.

W jaki sposób zatem możemy wywołać playbook Ansible, aby skonfigurować nowoutworzoną maszynę wirtualną? Oto przykład:

provisioner „local-exec” {

    command = „ansible-playbook -i '${self.public_ip},' konfiguracja.yml”

}

Parametr command jest wymagany a jego wartość musi wskazywać na polecenie systemowe, którego chcemy użyć na lokalnym systemie. Przy czym lokalny system odnosi się tutaj do urządzenia, na którym wykonywana jest receptura Terraforma. Pamiętajmy, że nie musi być to to samo urządzenie, z którego uruchamiamy cały proces automatyzacji. Wywoływana aplikacja musi jednak być dostępna w ścieżce $PATH. Alternatywnie możemy podać ścieżką bezwzględną do jej pliku wykonywalnego. Nie zapomnijmy także umieścić w wywołaniu wszystkich niezbędnych parametrów. Robimy to dokładnie w taki sam sposób, jakbyśmy uruchamiali dany playbook lokalnie. Jeżeli potrzebujemy przekazać dodatkowe parametry związane z interpreterem, na przykład powłoki bash czy interpretera języka python, to przekazujemy je za pomocą parametru interpreter. Ten sposób pozwala na uruchomienie lokalnego skryptu w powłoce zsh nawet jeżeli domyślnie w systemie używany jest bash. Dodatkowo za pomocą parametru environment ustawimy dodatkowe zmienne środowiskowe.

Tworzenie inventory z pliku stanu Terraform

W poprzednim artykule „Przechowywanie aktualnego stanu infrastruktury” opisałem w jaki sposób Terraform utrzymuje informację o zarządzanej za jego pomocą infrastrukturze. Przechowywany jest on w pliku terraform.tfstate. Plik ten zawiera strukturę JSON, co oznacza, że w prosty sposób możemy go odczytać, a zawarte w nim dane przetworzyć. Ansible nie ma jednak wbudowanych narzędzi pozwalających na wykorzystywanie tego pliku stanu. Na szczęście istnieją niezależne projekty takie jak choćby terraform-inventory (https://github.com/nbering/terraform-inventory/), które pozwalają przekształcić plik stanu na inventory zgodne ze standardem Ansible. Pamiętajmy także, że plik stanu w Terraform nie musi być przechowywany na lokalnym systemie plików. Może on wykorzystywać zdalne systemy czy usługi chmurowe takie jak Amazon S3. w połączeniu z automatyzacją wbudowano chmurę możemy dodatkowo skonfigurować automatyczne wyzwalanie odpowiednich playbooków Ansible przy każdej zmianie pliku stanu.

Rozwiązanie takie ma jednak trochę wad. Przede wszystkim zazwyczaj nie chcemy, aby wskazany playbook był za każdym razem wykonywany dla wszystkich powołanych do życia maszyn wirtualnych. Oznacza to, że musimy jeszcze napisać dodatkowy parser, za pomocą którego będziemy śledzili zmiany plików stanu. Musi on wyłapywać jedynie nowe urządzenia powołane w ramach zarządzania infrastruktury przeciek i tylko dla nich powinien być wykonywany playbook wprowadzający konfigurację.

Wspomniany powyżej projekt terraform-inventory nie jest jedynym tego typu. Przeszukując projektów na GitHub znajdziemy wiele podobnych narzędzi, które różnią się między sobą detalami związanymi ze sposobem użytkowania, czy parametrami, które są analizowane. Jeżeli chcesz używać tego sposobu dynamicznego tworzenia inventory musisz samodzielnie poszukać projektu, który najbardziej będzie spełniał twoje oczekiwania i potrzeby.

Dynamiczne tworzenie inventory po wykonaniu skryptu Terraform

W poprzednich przykładach pokazałem, w jaki sposób możemy powiązać etap budowania infrastruktury za pomocą Terraform z jej konfiguracją w Ansible bez narzędzi zewnętrznych. Nic nie stoi na przeszkodzie, żeby takie narzędzia wprowadzić. Za pomocą aplikacji CI/CD takich jak Jenkins czy TravisCI zaprogramujemy cały ciąg zdarzeń, który będzie się łączył w jeden kompletny scenariusz. Taki scenariusz może składać się z trzech kroków:

  1. Zbudowania lub aktualizacji infrastruktury za pomocą Terraform
  2. Stworzenia inventory dla playbooka Ansible zawierającego listę nowych serwerów
  3. Wykonania playbooka

W drugim kroku możemy użyć zarówno narzędzi odczytujących plik stanu Terraforma, jak zrobiliśmy to w poprzednim przykładzie. Możemy także w dowolny inny sposób śledzić zmiany w infrastrukturze, rejestrujący choćby w zewnętrznych bazach danych, sprawdzając aktualny stan usługi w chmurze publicznej czy korzystając z każdego innego sposobu, który wykorzystujemy codziennie do zarządzania infrastrukturą i jej monitorowania. Mamy całą gamę narzędzi i najlepiej wybrać tutaj takie, które już znamy, czyli te które na co dzień używamy.

Pamiętajmy także że krok 2 i 3 możemy ze sobą złączyć. Ansible pozwala na wykorzystywanie skryptów do budowania inventory w sposób dynamiczny. W takim przypadku zamiast statycznego pliku z listą serwerów podajemy po prostu ścieżkę do wykonywanego skryptu, który zwróci dane w odpowiednim formacie akceptowalnym przez Ansible.