Infrastructure as Code? – to proste!

Wstęp

Czasy w których infrastrukturę IT tworzyło się ręcznie odchodzą do lamusa. Wraz z rozpowszechnieniem się wirtualizacji i praktyki DevOps specjaliści IT dostali szereg narzędzi pozwalających na optymalizację ich pracy. Jednym z nich jest Infrastructure as Code (IaC).

IaC to podejście w którym infrastrukturę IT oraz jej konfigurację opisujemy za pomocą kodu. Daje nam to wiele zalet:

  • automatyzacja wdrożeń – koniec z monotonnym i czasochłonnym klikaniem w GUI czy przepychaniem komend w CLI, żeby stworzyć pożądane środowisko,
  • powtarzalność wdrożeń – możemy tworzyć wiele środowisk i mieć pewność, że zawsze będą takie same,
  • wersjonowanie – tak jak w przypadku kodu aplikacji, kod infrastruktury przechowujemy w repozytorium dzięki czemu mamy możliwość:
    • powrotu do dowolnego momentu w historii
    • znamy historię zmian
    • kod odzwierciedla stan faktyczny infrastruktury
  • oszczędność czasu i pieniędzy*

*Oszczędność wynikająca z wdrożenia podejścia IaC nie jest widoczna od razu. IaC to nie tylko filozofia pracy, ale przede wszystkim zestaw narzędzi i bibliotek, które wymagają czasu potrzebnego na ich opanowanie.

Pomimo niewątpliwych zalet wynikających z użycia IaC spotykam się z oporem niektórych programistów i architektów oprogramowania do wykorzystania tego podejścia w swoich projektach? Dlaczego? Nie do końca wiem. Wydawać by się mogło, że takie podejście będzie naturalne dla programistów, ponieważ mają do czynienia z kodem na co dzień, więc ten sposób pracy z infrastrukturą powinien być dla nich chlebem powszednim, ale nie zawsze jest i z jakiegoś powodu tworząc kolejne środowisko wolą klikać next, next, next…

Jeden z powodów upatruję w przeciążeniu mentalnym. Programiści i tak mają już tyle technologii do opanowania, że na samą myśl o nauce kolejnego narzędzia (lub narzędzi!) do automatyzacji infrastruktury (Terraform, Vargant, Puppet, Chef, Ansible, CloudFormation, ARM Templates), żeby wymienić pierwsze z brzegu, zwyczajnie brakuje im chęci. A w kolejce do nauki stoi kolejny framework JS. W końcu większość z nas ma rodziny, hobby i zainteresowania. Żeby nie było, rozwój w branży IT jest ważny i jeżeli chce się być dobrym to nie da się go całkowicie wyeliminować z życia, niemniej trzeba zachować umiar i nie podążać ślepo za nowinkami, rozsądnie dobierając narzędzia i biblioteki do nauki, by znaleźć równowagę pomiędzy rozwojem zawodowym, a życiem osobistym.

Tym wpisem chcę rozpocząć serię artykułów pokazujących podejście IaC do tworzenia środowisk w Azure, bez obaw o przeciążenie mentalne naszych umysłów w najgorszym wypadku skutkujące wypaleniem zawodowym.

Na początek na warsztat weźmiemy szablony ARM (ang. ARM Templates).

Azure Resource Manager Templates

ARM (Azure Resource Manager) Template to plik zawierający opis infrastruktury Azure w postaci JSON. Przykład takiego pliku możemy znaleźć np. tutaj: https://github.com/Azure/azure-quickstart-templates/blob/master/101-webapp-linux-managed-postgresql/azuredeploy.json. Ten szablon utworzy aplikację NodeJS hostowaną za pomocą usługi AppService oraz bazę danych PostgreSQL. Opisywanie infrastruktury za pomocą składni JSON może wydawać się nieco skomplikowane, w końcu trzeba pamiętać te wszystkie atrybuty i ich składnię, a jest co bo to co widzimy w podlinkowanym szablonie to tylko wycinek atrybutów jakimi możemy opisać AppService. Pełna składnia i specyfikacja zasobu aplikacji dostępna jest tutaj: https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites a gdzie jeszcze specyfikacja bazy danych?

Na szczęście Visual Studio dostarcza nam zestaw szablonów projektów, które możemy wykorzystać do pracy z Azure. VS Code ma podobne udogodnienia, niemniej VS Code jest nastawiony na pracę z edytorem tekstowym i terminalem, dlatego temat VS Code i ARM Templates poruszę w jednym z kolejnych wpisów. Ponieważ chcemy zbudować infrastrukturę wybieramy szablon projektu Azure Resource Group.

Po podaniu informacji o projekcie takich jak nazwa i lokalizacja zostaniemy poproszeni o wybór szablonu ARM. Możemy zacząć od gotowca lub zacząć od zera i wybrać pusty.

W szablonie ARM wyróżniamy następujące sekcje:

  • parameters
  • variables
  • resources
  • outputs

Parameters

W sekcji parameters możemy zdefiniować parametry, z których będziemy korzystać w dalszej części szablonu, takie jak nazwa aplikacji, lokalizacja, konto administratora, rozmiar bazy danych, pricing plan (darmowy, płatny), itp.

Jak widzimy do utworzenia wartości parametru, możemy wykorzystać wbudowane funkcje takie jak concat() czy uniqueString(). Pełną listę funkcji możemy znaleźć w dokumentacji https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions. Do parametrów możemy następnie odwoływać z pozostałych miejsc szablonu.

Variables

Sekcja variables służy do definiowana zmiennych, czyli wartości do których możemy odwołać się w takich sekcjach jak resources czy outputs. W sekcji variables, podobnie jak w parameters możemy korzystać z wbudowanych funkcji. Co bardziej doświadczeni czytelnicy zauważą, że obydwie sekcje mogą realizować te same funkcjonalności i zadać pytanie jaka jest różnica i kiedy używać jednego lub drugiego? Odpowiedź nie jest prosta. W skrócie moglibyśmy powiedzieć, że sekcja parameters może przyjmować wartości spoza szablonu. To znaczy, że jeżeli szablon używa wartości przyjmowanych z zewnątrz, takie których nie chcemy umieszczać w szablonie bo zależą od konfiguracji czy środowiska: url-e, nazwy użytkowników, hasła, klucze dostępowe, itp, to powinniśmy je zdefiniować w sekcji parameters, gdyż wartości te są dostarczanie dynamicznie w trakcie wdrażania szablonu.

Z kolei sekcji variables powinniśmy używać do przechowywania wartości generowanych na podstawie parametrów i gdy chcemy skorzystać z funkcji, aby wykonać jakąś logikę. Spójrzmy na przykładowy szablon, żeby rozwiać wszelkie wątpliwości:

{
  "parameters": {
    "application": { ... },
    "businessUnit": { ... },
    "environment": { ... }
  },
  "variables": {
    "webApp": {
      "name": "[concat('app-', parameters('application'), '-', parameters(businessUnit), '-', parameters('environment'))]"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Web/sites",
      "name": "[variables('webApp').name]",
      ...
    }
  ]
}

W powyższym szablonie wywołanie funkcji [variables('webApp').name spowoduje utworzenie nazwy aplikacji o następującym formacie:

app-application-businessUnit-environment

Przykładowa nazwa aplikacji mogłaby wyglądać wtedy tak:

app-wordpress-marketing-dev

Resources

Ostatnią sekcją szablonów ARM którą chciałbym pokrótce omówić to resources, czyli serce naszego szablonu. Jak sama nazwa wskazuje to w tym miejscu definiujemy zasoby Azure do stworzenia oraz ich pożądaną konfigurację (ang. Desired State Configuration).

Jak zauważyłem wcześniej ilość atrybutów, którymi możemy opisać zasoby Azure może przyprawiać o ból głowy i powodować trudności w odpowiedzi na pytanie, czy w swoim szablonie powinienem użyć wszystkich atrybutów, czy może wystarczy tylko kilka z nich? Czy muszę mieć pod ręką link do dokumentacji każdego zasobu, żeby wiedzieć jakie atrybuty posiada? Otóż nie do końca. Visual Studio dostarcza okno o nazwie JSON Outline. Jak możemy zobaczyć poniżej wyświetla ono strukturę szablonu w nieco bardziej przystępny sposób.

Dzięki temu oknu nie tylko możemy w łatwy sposób nawigować po szablonie czy widzieć z jakich elementów się składa, ale również dodawać nowe zasoby. W tym celu klikamy prawym klawiszem myszki na węzeł resources i wybieramy Add New Resource.

Wybieramy zasób z listy, np Redis Cache i klikamy Add.

Po kliknięciu Add zobaczymy, że w szablonie pojawił się nowy zasób:

Co bardziej dociekliwi czytelnicy zauważą, że wraz z pojawieniem się nowego zasobu, pojawiły się również odniesienia do parametrów reprezentujących wartości dla niektórych atrybutów. Jak możemy się domyśleć Visual Studio dodał odpowiednie wpisy w sekcji parameters za nas:

Nam jedynie pozostaje przekazać odpowiednie wartości do parametrów i voila – infrastruktura potrzebna do zbudowania cache aplikacji opartego o Redis gotowa.

ARM Template Deployment

Po przygotowaniu szablonu nie pozostaje nam nic innego jak wdrożyć go na środowisko w chmurze. W tym celu w Solution Explorer klikamy prawym klawiszem myszki i wybieramy Deploy > New. W kolejnym oknie wybieramy subskrypcję, resource group oraz szablon i klikamy Deploy.

W kolejnym oknie mamy możliwość przekazania parametrów do szablonu:

Po kliknięciu Save rozpocznie się proces deploymentu, czyli tworzenia zdefiniowanej infrastruktury w Azure wraz z pożądaną konfiguracją.

Podsumowanie

Mam nadzieję, że tym wpisem udało mi się pokazać, że mając pod ręką odpowiednie narzędzia, tworzenie szablonów ARM nie jest takie trudne jak może się z początku wydawać. Oczywiście zaprezentowane przykłady stanowią niewielki wycinek możliwości jakie dają szablony ARM (pełna specyfikacja znajduje się pod adresem https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/) niemniej chciałem Cię zachęcić Drogi Czytelniku do spróbowania tego podejścia i poeksperymentowania we własnych zakresie.

Dla Firm

Jeżeli prowadzisz firmę i chciałbyś wykorzystać podejście Infrastructure as Code w swoich projektach, a Tobie i Twojemu zespołowi brakuje wiedzy z tego obszaru to mam w swojej ofercie szkoleniowej 2-dniowe warsztaty Infrastruktura jako kod w których uczestnicy poznają teorię, narzędzia wspierające IaC oraz samodzielnie piszą kod wdrażający przykładowe rozwiązania w Azure – od małych środowisk obejmujących aplikację i bazę danych do średniej wielkości systemów składających się z takich usług jak: AzureSQL, kontenery, Azure Search, App Service, CDN, Computer Vision, Storage Account, Azure Front Door, Azure Functions).

Ze względu na obecną sytuację z COVID-19 szkolenia prowadzone są online.