Terraform vs. CloudFormation: ostateczny przewodnik

Opublikowany: 2022-03-11

Jeśli, tak jak ja, przeszukiwałeś Internet, aby pomóc Ci wybrać między CloudFormation a Terraform jako kolejnym narzędziem infrastruktury jako kodu (IaC) bez znalezienia ostatecznej odpowiedzi, przez długi czas dzieliłem się Twoim bólem. Teraz mam spore doświadczenie z obydwoma narzędziami i potrafię podjąć świadomą decyzję, którego użyć.

TL; DR

Dla swojego projektu IaC na AWS wybierz CloudFormation, ponieważ:

  1. CloudFormation rozróżnia kod (tj. szablony) i instancje kodu (tj. stosy). W Terraform nie ma takiego rozróżnienia. Więcej na ten temat w następnej sekcji.
  2. Terraform nie radzi sobie zbyt dobrze z podstawowym zarządzaniem zależnościami. Więcej na ten temat w dalszej części.

Rozróżnianie między kodem a instancjami

Jedną z różnic między CloudFormation i Terraform jest to, jak kod i wystąpienia są ze sobą powiązane w ramach każdej usługi.

CloudFormation ma koncepcję stosu , która jest instancją szablonu. Ten sam szablon może być tworzony w nieskończoność przez danego klienta na danym koncie, na wielu kontach lub przez różnych klientów.

Terraform nie ma takiej koncepcji i wymaga relacji jeden do jednego między kodem a jego instancją. Byłoby to podobne do duplikowania kodu źródłowego serwera WWW dla każdego serwera, który chcesz uruchomić, lub duplikowania kodu za każdym razem, gdy musisz uruchomić aplikację zamiast uruchamiać skompilowaną wersję.

Ten punkt jest dość trywialny w przypadku prostej konfiguracji, ale szybko staje się głównym problemem przy operacjach na średnią i dużą skalę. W Terraform za każdym razem, gdy musisz rozkręcić nowy stos z istniejącego kodu, musisz go zduplikować. A kopiowanie/wklejanie plików skryptów to bardzo łatwy sposób na sabotowanie siebie i uszkodzenie zasobów, których nie zamierzałeś dotykać.

Terraform w rzeczywistości nie ma koncepcji stosów , takich jak CloudFormation, co wyraźnie pokazuje, że Terraform został zbudowany od podstaw, aby dopasować jeden do jednego między kodem a zasobami, którymi zarządza. Zostało to później częściowo skorygowane przez koncepcję środowisk (które zostały przemianowane na „obszary robocze”), ale sposób ich użycia sprawia, że ​​wdrożenie w niechcianym środowisku jest niezwykle łatwe. Dzieje się tak, ponieważ przed wdrożeniem musisz uruchomić terraform workspace select , a pominięcie tego kroku spowoduje wdrożenie do poprzednio wybranego obszaru roboczego, który może, ale nie musi, być tym, który chcesz.

W praktyce co prawda problem ten łagodzi zastosowanie modułów Terraform, ale nawet w najlepszym przypadku wymagałoby to znacznej ilości kodu wzorcowego. W rzeczywistości ten problem był tak poważny, że ludzie musieli stworzyć narzędzie do owijania wokół Terraform, aby rozwiązać ten problem: Terragrunt.

Zarządzanie państwowe i uprawnienia

Inną ważną różnicą między CloudFormation i Terraform jest sposób, w jaki zarządzają stanem i uprawnieniami.

CloudFormation zarządza stanami stosu za Ciebie i nie daje żadnych opcji. Ale z mojego doświadczenia wynika, że ​​stany stosu CloudFormation są solidne. Ponadto CloudFormation umożliwia mniej uprzywilejowanym użytkownikom zarządzanie stosami bez posiadania wszystkich niezbędnych uprawnień wymaganych przez sam stos. Dzieje się tak, ponieważ CloudFormation może uzyskać uprawnienia z roli usługi dołączonej do stosu, a nie uprawnienia od użytkownika uruchamiającego operację stosu.

Terraform wymaga udostępnienia mu pewnych zapleczy do zarządzania stanami. Domyślnie jest to plik lokalny, co jest całkowicie niezadowalające, biorąc pod uwagę:

  1. Solidność pliku stanu jest całkowicie powiązana z solidnością maszyny, na której jest przechowywany.
  2. To praktycznie uniemożliwia pracę zespołową.

Potrzebujesz więc solidnego i współdzielonego stanu, który w AWS jest zwykle osiągany za pomocą zasobnika S3 do przechowywania pliku stanu, wraz z tabelą DynamoDB do obsługi współbieżności.

Oznacza to, że musisz ręcznie utworzyć zasobnik S3 i tabelę DynamoDB dla każdego stosu, który chcesz utworzyć, a także ręcznie zarządzać uprawnieniami dla tych dwóch obiektów, aby ograniczyć mniej uprzywilejowanym użytkownikom dostęp do danych, do których nie powinni mieć dostępu. Jeśli masz tylko kilka żetonów, nie będzie to zbyt duży problem, ale jeśli masz 20 żetonów do zarządzania, staje się to bardzo kłopotliwe.

Nawiasem mówiąc, podczas korzystania z obszarów roboczych Terraform nie można mieć jednej tabeli DynamoDB na obszar roboczy. Oznacza to, że jeśli chcesz, aby użytkownik IAM miał minimalne uprawnienia do wykonywania wdrożeń, będzie mógł manipulować blokadami wszystkich obszarów roboczych, ponieważ uprawnienia DynamoDB nie są szczegółowo określone na poziomie elementu.

Zarządzanie zależnościami

W tym momencie zarówno CloudFormation, jak i Terraform mogą być nieco trudne. Jeśli zmienisz identyfikator logiczny (tj. nazwę) zasobu, obaj uznają, że stary zasób musi zostać zniszczony, a nowy utworzony. Dlatego generalnie złym pomysłem jest zmiana logicznego identyfikatora zasobów w obu narzędziach, szczególnie w przypadku stosów zagnieżdżonych w CloudFormation.

Jak wspomniano w pierwszej sekcji, Terraform nie obsługuje podstawowych zależności. Niestety, twórcy Terraform nie poświęcają wiele uwagi temu zadawnionemu problemowi, pomimo widocznego braku obejścia.

Biorąc pod uwagę, że właściwe zarządzanie zależnościami ma absolutnie kluczowe znaczenie dla narzędzia IaC, takie problemy w Terraform podważają jego przydatność, gdy tylko w grę wchodzą operacje o znaczeniu krytycznym dla firmy, takie jak wdrożenie w środowisku produkcyjnym. CloudFormation zapewnia znacznie bardziej profesjonalny charakter, a AWS zawsze bardzo dba o to, aby oferować swoim klientom narzędzia klasy produkcyjnej. Przez wszystkie lata korzystania z CloudFormation nigdy nie spotkałem się z problemem z zarządzaniem zależnościami.

CloudFormation umożliwia stosowi wyeksportowanie niektórych zmiennych wyjściowych, które mogą być następnie ponownie wykorzystane przez inne stosy. Szczerze mówiąc, ta funkcjonalność jest ograniczona, ponieważ nie będziesz w stanie utworzyć więcej niż jednego stosu na region. Dzieje się tak, ponieważ nie można wyeksportować dwóch zmiennych o tej samej nazwie, a wyeksportowane zmienne nie mają przestrzeni nazw.

Terraform nie oferuje takich udogodnień, więc masz mniej pożądane opcje. Terraform umożliwia importowanie stanu innego stosu, ale daje to dostęp do wszystkich informacji w tym stosie, w tym wielu wpisów tajnych przechowywanych w stanie. Alternatywnie stos może wyeksportować niektóre zmienne w postaci pliku JSON przechowywanego w wiadrze S3, ale znowu ta opcja jest bardziej kłopotliwa: musisz zdecydować, którego wiaderka S3 użyć i nadać mu odpowiednie uprawnienia, a następnie zapisać wszystkie kod instalacyjny samodzielnie po stronie piszącej i czytającej.

Jedną z zalet Terraform jest to, że posiada źródła danych. Terraform może zatem wysyłać zapytania do zasobów, które nie są zarządzane przez Terraform. Jednak w praktyce ma to niewielkie znaczenie, gdy chcesz napisać ogólny szablon, ponieważ nie będziesz wtedy zakładać niczego na temat konta docelowego. Odpowiednikiem w CloudFormation jest dodanie większej liczby parametrów szablonu, co wiąże się z powtarzalnością i potencjalnymi błędami; jednak z mojego doświadczenia wynika, że ​​nigdy nie stanowiło to problemu.

Wracając do kwestii zarządzania zależnościami Terraform, innym przykładem jest błąd podczas próby zaktualizowania ustawień modułu równoważenia obciążenia i uzyskanie następujących informacji:

 Error: Error deleting Target Group: ResourceInUse: Target group 'arn:aws:elasticloadbalancing:us-east-1:723207552760:targetgroup/strategy-api-default-us-east-1/14a4277881e84797' is currently in use by a listener or a rule status code: 400, request id: 833d8475-f702-4e01-aa3a-d6fa0a141905

Oczekiwane zachowanie byłoby takie, że Terraform wykryje, że grupa docelowa jest zależnością jakiegoś innego zasobu, który nie jest usuwany, i w związku z tym nie powinien próbować go usunąć — ale nie powinien też zgłaszać błędu.

Operacje

Chociaż Terraform jest narzędziem wiersza poleceń, jest bardzo jasne, że oczekuje, że uruchomi go człowiek, ponieważ jest bardzo interaktywne. Możliwe jest uruchomienie go w trybie wsadowym (tj. ze skryptu), ale wymaga to kilku dodatkowych argumentów wiersza poleceń. Fakt, że Terraform został domyślnie opracowany do obsługi przez ludzi, jest dość zagadkowy, biorąc pod uwagę, że celem narzędzia IaC jest automatyzacja.

Terraform jest trudny do debugowania. Komunikaty o błędach są często bardzo proste i nie pozwalają zrozumieć, co się dzieje, w takim przypadku będziesz musiał uruchomić Terraform z TF_LOG=debug , co generuje ogromną ilość danych wyjściowych do przeszukania. Komplikując to, Terraform czasami wykonuje wywołania API do AWS, które kończą się niepowodzeniem, ale awaria nie jest problemem z Terraform. W przeciwieństwie do tego CloudFormation zapewnia dość jasne komunikaty o błędach z wystarczającą ilością szczegółów, aby umożliwić zrozumienie, gdzie jest problem.

Przykładowy komunikat o błędzie Terraform:

 Error: error reading S3 bucket Public Access Block: NoSuchBucket: The specified bucket does not exist status code: 404, request id: 19AAE641F0B4AC7F, host id: rZkgloKqxP2/a2F6BYrrkcJthba/FQM/DaZnj8EQq/5FactUctdREq8L3Xb6DgJmyKcpImipv4s=

Powyższy komunikat o błędzie pokazuje wyraźny komunikat o błędzie, który w rzeczywistości nie odzwierciedla podstawowego problemu (który w tym przypadku był problemem z uprawnieniami).

Ten komunikat o błędzie pokazuje również, jak Terraform może czasami malować się w rogu. Na przykład, jeśli utworzysz zasobnik S3 i zasób aws_s3_bucket_public_access_block w tym zasobniku i jeśli z jakiegoś powodu dokonasz zmian w kodzie Terraform, który zniszczy to zasobnik — np. w opisie „zmiana oznacza usunięcie i utworzenie” opisanej powyżej — Terraform utknie podczas próby załadowania aws_s3_bucket_public_access_block ale ciągle nie powiedzie się z powodu powyższego błędu. Prawidłowe zachowanie Terraform polegałoby na zastąpieniu lub usunięciu aws_s3_bucket_public_access_block w razie potrzeby.

Wreszcie, nie można używać skryptów pomocniczych CloudFormation z Terraform. Może to być irytujące, zwłaszcza jeśli masz nadzieję na użycie cfn-signal, który informuje CloudFormation, że instancja EC2 zakończyła się samoczynnie i jest gotowa do obsługi żądań.

Składnia, społeczność i wycofywanie

Pod względem składni Terraform ma dobrą przewagę w porównaniu z CloudFormation — obsługuje pętle. Ale z własnego doświadczenia ta funkcja może okazać się nieco niebezpieczna. Zazwyczaj pętla służy do tworzenia wielu identycznych zasobów; jednak, gdy chcesz zaktualizować stos o inną liczbę, może być konieczne połączenie starych i nowych zasobów (na przykład użycie zipmap() do połączenia wartości z dwóch tablic, które teraz są różnych rozmiarów, ponieważ jedna tablica ma rozmiar starego rozmiaru pętli, a druga ma rozmiar nowej pętli). Co prawda taki problem może się zdarzyć bez pętli, ale bez pętli problem byłby znacznie bardziej widoczny dla osoby piszącej skrypt. Użycie pętli w takim przypadku zaciemnia problem.

To, czy składnia Terraform, czy składnia CloudFormation jest lepsza, jest głównie kwestią preferencji. CloudFormation początkowo obsługiwał tylko JSON, ale szablony JSON są bardzo trudne do odczytania. Na szczęście CloudFormation obsługuje również YAML, który jest znacznie łatwiejszy do odczytania i umożliwia komentarze. Składnia CloudFormation jest jednak dość szczegółowa.

Składnia Terraform wykorzystuje HCL, który jest rodzajem pochodnej JSON i jest dość specyficzny. Terraform oferuje więcej funkcji niż CloudFormation i zazwyczaj łatwiej je zrozumieć. Można więc argumentować, że Terraform ma niewielką przewagę w tej kwestii.

Kolejną zaletą Terraform jest łatwo dostępny zestaw modułów obsługiwanych przez społeczność, co upraszcza pisanie szablonów. Jednym z problemów może być to, że takie moduły mogą nie być wystarczająco bezpieczne, aby spełnić wymagania organizacji. Dlatego w przypadku organizacji wymagających wysokiego poziomu bezpieczeństwa przegląd tych modułów (a także kolejnych wersji w miarę ich pojawiania się) może być koniecznością.

Ogólnie rzecz biorąc, moduły Terraform są znacznie bardziej elastyczne niż stosy zagnieżdżone CloudFormation. Zagnieżdżony stos CloudFormation ma tendencję do ukrywania wszystkiego poniżej. Ze stosu zagnieżdżenia operacja aktualizacji pokazałaby, że zagnieżdżony stos zostanie zaktualizowany, ale nie pokazuje szczegółowo, co stanie się wewnątrz zagnieżdżonego stosu.

Ostatnią kwestią, która w rzeczywistości może być kontrowersyjna, jest to, że CloudFormation próbuje wycofać nieudane wdrożenia. Jest to dość interesująca funkcja, ale niestety może trwać bardzo długo (na przykład CloudFormation może potrwać do trzech godzin, aby zdecydować, że wdrożenie usługi Elastic Container Service nie powiodło się). Natomiast w przypadku awarii Terraform po prostu zatrzymuje się tam, gdzie był. To, czy funkcja wycofywania jest dobra, czy nie, jest dyskusyjna, ale doceniłem fakt, że stos jest utrzymywany w stanie roboczym tak często, jak to możliwe, gdy dłuższe oczekiwanie jest akceptowalnym kompromisem.

W obronie Terraform kontra CloudFormation

Terraform ma przewagę nad CloudFormation. Moim zdaniem najważniejszą z nich jest to, że podczas stosowania aktualizacji Terraform pokazuje wszystkie zmiany, które zamierzasz wprowadzić, w tym drążenie do wszystkich używanych modułów. Natomiast CloudFormation podczas korzystania ze stosów zagnieżdżonych pokazuje tylko, że stos zagnieżdżony wymaga aktualizacji, ale nie zapewnia sposobu na drążenie szczegółów. Może to być frustrujące, ponieważ tego typu informacje są dość ważne, aby wiedzieć przed naciśnięciem przycisku „start”.

Rozszerzenia obsługują zarówno CloudFormation, jak i Terraform. W CloudFormation istnieje możliwość zarządzania tak zwanymi „custom resources” za pomocą własnej funkcji AWS Lambda jako zaplecza. W przypadku Terraform rozszerzenia są znacznie łatwiejsze do napisania i stanowią część kodu. Tak więc w tym przypadku Terraform ma przewagę.

Terraform może obsługiwać wielu dostawców chmury. Dzięki temu Terraform jest w stanie ujednolicić dane wdrożenie na wielu platformach chmurowych. Załóżmy na przykład, że masz pojedyncze obciążenie rozłożone między AWS i Google Cloud Platform (GCP). Normalnie część obciążenia AWS byłaby wdrażana przy użyciu CloudFormation, a część GCP przy użyciu Cloud Deployment Managera GCP. Dzięki Terraform możesz zamiast tego użyć jednego skryptu do wdrożenia obu stosów i zarządzania nimi na odpowiednich platformach w chmurze. W ten sposób musisz rozłożyć tylko jeden stos zamiast dwóch.

Bez argumentów za Terraform vs. CloudFormation

W Internecie nadal krąży wiele nieargumentów. Największą z nich jest to, że ponieważ Terraform działa w wielu chmurach, możesz użyć jednego narzędzia do wdrożenia wszystkich swoich projektów, bez względu na to, na jakiej platformie w chmurze są one wykonywane. Technicznie jest to prawda, ale nie jest to duża zaleta, jaką może się wydawać, zwłaszcza w przypadku zarządzania typowymi projektami w jednej chmurze. Rzeczywistość jest taka, że ​​między zasobami zadeklarowanymi w (na przykład) CloudFormation a tymi samymi zasobami zadeklarowanymi w skrypcie Terraform zachodzi niemal jeden do jednego. Ponieważ i tak musisz znać szczegóły zasobów specyficznych dla chmury, różnica sprowadza się do składni, która nie jest największym problemem w zarządzaniu wdrożeniami.

Niektórzy twierdzą, że korzystając z Terraform, można uniknąć uzależnienia od dostawcy. Ten argument nie ma sensu w tym sensie, że używając Terraform, jesteś zablokowany przez HashiCorp (twórcę Terraform), dokładnie w ten sam sposób, w jaki używając CloudFormation, jesteś zablokowany przez AWS i tak dalej dla innej chmury platformy.

To, że moduły Terraform są łatwiejsze w użyciu, ma dla mnie mniejsze znaczenie. Przede wszystkim uważam, że AWS celowo chce uniknąć hostingu jednego repozytorium dla szablonów CloudFormation opartych na społeczności z powodu postrzeganej odpowiedzialności za luki w zabezpieczeniach tworzone przez użytkowników i naruszenia różnych programów zgodności.

Na bardziej osobistym poziomie w pełni rozumiem korzyści płynące z używania bibliotek w przypadku tworzenia oprogramowania, ponieważ te biblioteki mogą łatwo natrafić na dziesiątki tysięcy wierszy kodu. W przypadku IaC jednak rozmiar kodu jest zwykle znacznie mniejszy, a takie moduły mają zwykle kilkadziesiąt linijek długości. Korzystanie z funkcji kopiuj/wklej nie jest tak naprawdę złym pomysłem w tym sensie, że pozwala uniknąć problemów z utrzymaniem kompatybilności i delegowaniem bezpieczeństwa na nieznane osoby.

Korzystanie z funkcji kopiowania/wklejania nie podoba się wielu programistom i inżynierom DevOps, i istnieją ku temu dobre powody. Jednak z mojego punktu widzenia użycie funkcji kopiuj/wklej dla fragmentów kodu pozwala łatwo dostosować go do własnych potrzeb i nie ma potrzeby tworzenia z niego biblioteki i poświęcania dużo czasu na uczynienie go generycznym. Ból związany z utrzymaniem tych fragmentów kodu jest zwykle bardzo niski, chyba że Twój kod zostanie zduplikowany, powiedzmy, w kilkunastu szablonach. W takim przypadku zawłaszczenie kodu i używanie go jako zagnieżdżonych stosów ma sens, a korzyści z tego, że się nie powtarzasz, są prawdopodobnie większe niż irytacja niemożności zobaczenia, co zostanie zaktualizowane w zagnieżdżonym stosie podczas wykonywania aktualizacji operacja.

CloudFormation a Terraform Wniosek

Dzięki CloudFormation AWS chce zapewnić swoim klientom solidne narzędzie, które będzie zawsze działać zgodnie z przeznaczeniem. Zespół Terraform też oczywiście to robi — ale wydaje się, że kluczowy aspekt ich narzędzi, zarządzanie zależnościami, nie jest niestety priorytetem.

Terraform może mieć miejsce w twoim projekcie, zwłaszcza jeśli masz architekturę wielochmurową, w którym to przypadku skrypty Terraform są jednym ze sposobów ujednolicenia zarządzania zasobami u różnych dostawców chmury, z których korzystasz. Ale nadal możesz uniknąć wad Terraform w tym przypadku, używając tylko Terraform do zarządzania stosami już zaimplementowanymi przy użyciu odpowiednich narzędzi IaC specyficznych dla chmury.

Ogólne wrażenie Terraform vs CloudFormation polega na tym, że CloudFormation, chociaż niedoskonały, jest bardziej profesjonalny i niezawodny, i zdecydowanie poleciłbym go dla każdego projektu, który nie jest specjalnie multi-cloud.